1 /*
2 * floatcomp.c - Isolate floating point details.
3 */
4
5 /*
6 * Copyright (C) 1986, 1988, 1989, 1991-2011, 2016, 2021,
7 * the Free Software Foundation, Inc.
8 *
9 * This file is part of GAWK, the GNU implementation of the
10 * AWK Programming Language.
11 *
12 * GAWK is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * GAWK is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27 #include "awk.h"
28
29 #ifdef HAVE_UINTMAX_T
30
31 /* Assume IEEE-754 arithmetic on pre-C89 hosts. */
32 #ifndef FLT_RADIX
33 #define FLT_RADIX 2
34 #endif
35 #ifndef FLT_MANT_DIG
36 #define FLT_MANT_DIG 24
37 #endif
38 #ifndef DBL_MANT_DIG
39 #define DBL_MANT_DIG 53
40 #endif
41
42 /*
43 * The number of base-FLT_RADIX digits in an AWKNUM fraction, assuming
44 * that AWKNUM is not long double.
45 */
46 #define AWKSMALL_MANT_DIG \
47 (sizeof (AWKNUM) == sizeof (double) ? DBL_MANT_DIG : FLT_MANT_DIG)
48
49 /*
50 * The number of base-FLT_DIGIT digits in an AWKNUM fraction, even if
51 * AWKNUM is long double. Don't mention 'long double' unless
52 * LDBL_MANT_DIG is defined, for the sake of ancient compilers that
53 * lack 'long double'.
54 */
55 #ifdef LDBL_MANT_DIG
56 #define AWKNUM_MANT_DIG \
57 (sizeof (AWKNUM) == sizeof (long double) ? LDBL_MANT_DIG : AWKSMALL_MANT_DIG)
58 #else
59 #define AWKNUM_MANT_DIG AWKSMALL_MANT_DIG
60 #endif
61
62 /*
63 * The number of bits in an AWKNUM fraction, assuming FLT_RADIX is
64 * either 2 or 16. IEEE and VAX formats use radix 2, and IBM
65 * mainframe format uses radix 16; we know of no other radices in
66 * practical use.
67 */
68 #if FLT_RADIX != 2 && FLT_RADIX != 16
69 Please port the following code to your weird host;
70 #endif
71 #define AWKNUM_FRACTION_BITS (AWKNUM_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4))
72 #define DBL_FRACTION_BITS (DBL_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4))
73
74 /* Return the number of trailing zeros in N. N must be nonzero. */
75 static int
76 count_trailing_zeros(uintmax_t n)
77 {
78 #if 3 < (__GNUC__ + (4 <= __GNUC_MINOR__)) && UINTMAX_MAX <= ULLONG_MAX
79 return __builtin_ctzll(n);
80 #else
81 int i = 0;
82 for (; (n & 3) == 0; n >>= 2)
83 i += 2;
84 return i + (1 & ~n);
85 #endif
86 }
87
88 /* adjust_uint --- fiddle with values, ask Paul Eggert to explain */
89
90 uintmax_t
91 adjust_uint(uintmax_t n)
92 {
93 /*
94 * If uintmax_t is so wide that AWKNUM cannot represent all its
95 * values, strip leading nonzero bits of integers that are so large
96 * that they cannot be represented exactly as AWKNUMs, so that their
97 * low order bits are represented exactly, without rounding errors.
98 * This is more desirable in practice, since it means the user sees
99 * integers that are the same width as the AWKNUM fractions.
100 */
101 int wordbits = CHAR_BIT * sizeof n;
102 if (AWKNUM_FRACTION_BITS < wordbits) {
103 uintmax_t one = 1;
104 uintmax_t sentinel = one << (wordbits - AWKNUM_FRACTION_BITS);
105 int shift = count_trailing_zeros(n | sentinel);
106 uintmax_t mask = (one << AWKNUM_FRACTION_BITS) - 1;
107
108 n &= mask << shift;
109 }
110
111 return n;
112 }
113 #endif /* HAVE_UINTMAX_T */