aboutsummaryrefslogtreecommitdiffstats
path: root/floatcomp.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2015-05-30 23:42:51 -0400
committerArnold D. Robbins <arnold@skeeve.com>2015-05-30 23:42:51 -0400
commit501c2e5e720e3dbcb2e830c28037dd8b8d46bfcf (patch)
treee47fc4eded939744788371f2b26ddeb0c5d1f196 /floatcomp.c
parent7ae0f019e5636657d449d20ac0546c3bc6ac1bb2 (diff)
downloadegawk-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.c25
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;
}