diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2015-05-30 23:42:51 -0400 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2015-05-30 23:42:51 -0400 |
commit | 501c2e5e720e3dbcb2e830c28037dd8b8d46bfcf (patch) | |
tree | e47fc4eded939744788371f2b26ddeb0c5d1f196 /floatcomp.c | |
parent | 7ae0f019e5636657d449d20ac0546c3bc6ac1bb2 (diff) | |
download | egawk-501c2e5e720e3dbcb2e830c28037dd8b8d46bfcf.tar.gz egawk-501c2e5e720e3dbcb2e830c28037dd8b8d46bfcf.tar.bz2 egawk-501c2e5e720e3dbcb2e830c28037dd8b8d46bfcf.zip |
Improve handling and doc of compl().
Diffstat (limited to 'floatcomp.c')
-rw-r--r-- | floatcomp.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/floatcomp.c b/floatcomp.c index 16a6d88e..d8d35694 100644 --- a/floatcomp.c +++ b/floatcomp.c @@ -71,6 +71,20 @@ Please port the following code to your weird host; #define AWKNUM_FRACTION_BITS (AWKNUM_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4)) #define DBL_FRACTION_BITS (DBL_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4)) +/* Return the number of trailing zeros in N. N must be nonzero. */ +static int +count_trailing_zeros(uintmax_t n) +{ +#if 3 < (__GNUC__ + (4 <= __GNUC_MINOR__)) && UINTMAX_MAX <= ULLONG_MAX + return __builtin_ctzll(n); +#else + int i = 0; + for (; (n & 3) == 0; n >>= 2) + i += 2; + return i + (1 & ~n); +#endif +} + /* adjust_uint --- fiddle with values, ask Paul Eggert to explain */ uintmax_t @@ -84,8 +98,15 @@ adjust_uint(uintmax_t n) * This is more desirable in practice, since it means the user sees * integers that are the same width as the AWKNUM fractions. */ - if (AWKNUM_FRACTION_BITS < CHAR_BIT * sizeof n) - n &= ((uintmax_t) 1 << AWKNUM_FRACTION_BITS) - 1; + int wordbits = CHAR_BIT * sizeof n; + if (AWKNUM_FRACTION_BITS < wordbits) { + uintmax_t one = 1; + uintmax_t sentinel = one << (wordbits - AWKNUM_FRACTION_BITS); + int shift = count_trailing_zeros(n | sentinel); + uintmax_t mask = (one << AWKNUM_FRACTION_BITS) - 1; + + n &= mask << shift; + } return n; } |