|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* floatcomp.c - Isolate floating point details.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* Copyright (C) 1986, 1988, 1989, 1991-2011, 2016
|
|
Packit Service |
f629e6 |
* the Free Software Foundation, Inc.
|
|
Packit Service |
f629e6 |
*
|
|
Packit Service |
f629e6 |
* This file is part of GAWK, the GNU implementation of the
|
|
Packit Service |
f629e6 |
* AWK Programming Language.
|
|
Packit Service |
f629e6 |
*
|
|
Packit Service |
f629e6 |
* GAWK is free software; you can redistribute it and/or modify
|
|
Packit Service |
f629e6 |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
f629e6 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit Service |
f629e6 |
* (at your option) any later version.
|
|
Packit Service |
f629e6 |
*
|
|
Packit Service |
f629e6 |
* GAWK is distributed in the hope that it will be useful,
|
|
Packit Service |
f629e6 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
f629e6 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
f629e6 |
* GNU General Public License for more details.
|
|
Packit Service |
f629e6 |
*
|
|
Packit Service |
f629e6 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
f629e6 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
f629e6 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
#include "awk.h"
|
|
Packit Service |
f629e6 |
#include <math.h>
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
#ifdef HAVE_UINTMAX_T
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* Assume IEEE-754 arithmetic on pre-C89 hosts. */
|
|
Packit Service |
f629e6 |
#ifndef FLT_RADIX
|
|
Packit Service |
f629e6 |
#define FLT_RADIX 2
|
|
Packit Service |
f629e6 |
#endif
|
|
Packit Service |
f629e6 |
#ifndef FLT_MANT_DIG
|
|
Packit Service |
f629e6 |
#define FLT_MANT_DIG 24
|
|
Packit Service |
f629e6 |
#endif
|
|
Packit Service |
f629e6 |
#ifndef DBL_MANT_DIG
|
|
Packit Service |
f629e6 |
#define DBL_MANT_DIG 53
|
|
Packit Service |
f629e6 |
#endif
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* The number of base-FLT_RADIX digits in an AWKNUM fraction, assuming
|
|
Packit Service |
f629e6 |
* that AWKNUM is not long double.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
#define AWKSMALL_MANT_DIG \
|
|
Packit Service |
f629e6 |
(sizeof (AWKNUM) == sizeof (double) ? DBL_MANT_DIG : FLT_MANT_DIG)
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* The number of base-FLT_DIGIT digits in an AWKNUM fraction, even if
|
|
Packit Service |
f629e6 |
* AWKNUM is long double. Don't mention 'long double' unless
|
|
Packit Service |
f629e6 |
* LDBL_MANT_DIG is defined, for the sake of ancient compilers that
|
|
Packit Service |
f629e6 |
* lack 'long double'.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
#ifdef LDBL_MANT_DIG
|
|
Packit Service |
f629e6 |
#define AWKNUM_MANT_DIG \
|
|
Packit Service |
f629e6 |
(sizeof (AWKNUM) == sizeof (long double) ? LDBL_MANT_DIG : AWKSMALL_MANT_DIG)
|
|
Packit Service |
f629e6 |
#else
|
|
Packit Service |
f629e6 |
#define AWKNUM_MANT_DIG AWKSMALL_MANT_DIG
|
|
Packit Service |
f629e6 |
#endif
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* The number of bits in an AWKNUM fraction, assuming FLT_RADIX is
|
|
Packit Service |
f629e6 |
* either 2 or 16. IEEE and VAX formats use radix 2, and IBM
|
|
Packit Service |
f629e6 |
* mainframe format uses radix 16; we know of no other radices in
|
|
Packit Service |
f629e6 |
* practical use.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
#if FLT_RADIX != 2 && FLT_RADIX != 16
|
|
Packit Service |
f629e6 |
Please port the following code to your weird host;
|
|
Packit Service |
f629e6 |
#endif
|
|
Packit Service |
f629e6 |
#define AWKNUM_FRACTION_BITS (AWKNUM_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4))
|
|
Packit Service |
f629e6 |
#define DBL_FRACTION_BITS (DBL_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4))
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* Return the number of trailing zeros in N. N must be nonzero. */
|
|
Packit Service |
f629e6 |
static int
|
|
Packit Service |
f629e6 |
count_trailing_zeros(uintmax_t n)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
#if 3 < (__GNUC__ + (4 <= __GNUC_MINOR__)) && UINTMAX_MAX <= ULLONG_MAX
|
|
Packit Service |
f629e6 |
return __builtin_ctzll(n);
|
|
Packit Service |
f629e6 |
#else
|
|
Packit Service |
f629e6 |
int i = 0;
|
|
Packit Service |
f629e6 |
for (; (n & 3) == 0; n >>= 2)
|
|
Packit Service |
f629e6 |
i += 2;
|
|
Packit Service |
f629e6 |
return i + (1 & ~n);
|
|
Packit Service |
f629e6 |
#endif
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* adjust_uint --- fiddle with values, ask Paul Eggert to explain */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
uintmax_t
|
|
Packit Service |
f629e6 |
adjust_uint(uintmax_t n)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* If uintmax_t is so wide that AWKNUM cannot represent all its
|
|
Packit Service |
f629e6 |
* values, strip leading nonzero bits of integers that are so large
|
|
Packit Service |
f629e6 |
* that they cannot be represented exactly as AWKNUMs, so that their
|
|
Packit Service |
f629e6 |
* low order bits are represented exactly, without rounding errors.
|
|
Packit Service |
f629e6 |
* This is more desirable in practice, since it means the user sees
|
|
Packit Service |
f629e6 |
* integers that are the same width as the AWKNUM fractions.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
int wordbits = CHAR_BIT * sizeof n;
|
|
Packit Service |
f629e6 |
if (AWKNUM_FRACTION_BITS < wordbits) {
|
|
Packit Service |
f629e6 |
uintmax_t one = 1;
|
|
Packit Service |
f629e6 |
uintmax_t sentinel = one << (wordbits - AWKNUM_FRACTION_BITS);
|
|
Packit Service |
f629e6 |
int shift = count_trailing_zeros(n | sentinel);
|
|
Packit Service |
f629e6 |
uintmax_t mask = (one << AWKNUM_FRACTION_BITS) - 1;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
n &= mask << shift;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
return n;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
#endif /* HAVE_UINTMAX_T */
|