bug-gnu-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Problem with compl() in gawk-3.1.3


From: Paul Eggert
Subject: Re: Problem with compl() in gawk-3.1.3
Date: 27 Sep 2003 23:36:15 -0700
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3

Thanks for reporting that interesting bug in Gawk.
Here is a proposed patch, relative to gawk 3.1.3.

2003-09-27  Paul Eggert  <address@hidden>

        Fix a bug reported by Mike Romaniw <address@hidden>
        to bug-gnu-utils today: compl(compl(0xf0f)) returned 0xfff on hosts
        with 64-bit uintmax_t and 64-bit IEEE-764 double, due to rounding
        errors.
        * doc/gawk.texi (Bitwise Functions): Leading nonzero bits are
        removed in order to fit the result into a C 'double' without rounding
        error.
        * builtin.c: Include <float.h> if available.
        (FLT_RADIX, FLT_MANT_DIG, DBL_MANT_DIG): Define if not already defined.
        (AWKSMALL_MANT_DIG, AWKNUM_MANT_DIG, AWKNUM_FRACTION_BITS): New macros.
        (tmp_integer): New function.
        (do_lshift, do_rshift, do_and, do_or, do_xor, do_compl): Use them.

===================================================================
RCS file: doc/gawk.texi,v
retrieving revision 3.1.3.0
retrieving revision 3.1.3.1
diff -pu -r3.1.3.0 -r3.1.3.1
--- doc/gawk.texi       2003/07/04 17:40:47     3.1.3.0
+++ doc/gawk.texi       2003/09/28 06:14:51     3.1.3.1
@@ -13906,7 +13906,9 @@ Return the value of @var{val}, shifted r
 
 For all of these functions, first the double-precision floating-point value is
 converted to the widest C unsigned integer type, then the bitwise operation is
-performed and then the result is converted back into a C @code{double}. (If
+performed.  If the result cannot be represented exactly as a C @code{double},
+leading nonzero bits are removed one by one until it can be represented
+exactly.  The result is then converted back into a C @code{double}.  (If
 you don't understand this paragraph, don't worry about it.)
 
 Here is a user-defined function
===================================================================
RCS file: builtin.c,v
retrieving revision 3.1.3.0
retrieving revision 3.1.3.1
diff -pu -r3.1.3.0 -r3.1.3.1
--- builtin.c   2003/07/06 22:08:08     3.1.3.0
+++ builtin.c   2003/09/28 06:14:51     3.1.3.1
@@ -75,9 +75,22 @@ extern int output_is_tty;
 
 static NODE *sub_common P((NODE *tree, long how_many, int backdigs));
 
+#ifdef STDC_HEADERS
+#include <float.h>
+#endif
+/* Assume IEEE-754 arithmetic on pre-C89 hosts.  */
+#ifndef FLT_RADIX
+#define FLT_RADIX 2
+#endif
+#ifndef FLT_MANT_DIG
+#define FLT_MANT_DIG 24
+#endif
+#ifndef DBL_MANT_DIG
+#define DBL_MANT_DIG 53
+#endif
+
 #ifdef _CRAY
 /* Work around a problem in conversion of doubles to exact integers. */
-#include <float.h>
 #define Floor(n) floor((n) * (1.0 + DBL_EPSILON))
 #define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON))
 
@@ -2397,6 +2410,56 @@ sgfmt(char *buf, /* return buffer; assum
 }
 #endif /* GFMT_WORKAROUND */
 
+/*
+ * The number of base-FLT_RADIX digits in an AWKNUM fraction, assuming
+ * that AWKNUM is not long double.
+ */
+#define AWKSMALL_MANT_DIG \
+  (sizeof (AWKNUM) == sizeof (double) ? DBL_MANT_DIG : FLT_MANT_DIG)
+
+/*
+ * The number of base-FLT_DIGIT digits in an AWKNUM fraction, even if
+ * AWKNUM is long double.  Don't mention 'long double' unless
+ * LDBL_MANT_DIG is defined, for the sake of ancient compilers that
+ * lack 'long double'.
+ */
+#ifdef LDBL_MANT_DIG
+#define AWKNUM_MANT_DIG \
+  (sizeof (AWKNUM) == sizeof (long double) ? LDBL_MANT_DIG : AWKSMALL_MANT_DIG)
+#else
+#define AWKNUM_MANT_DIG AWKSMALL_MANT_DIG
+#endif
+
+/*
+ * The number of bits in an AWKNUM fraction, assuming FLT_RADIX is
+ * either 2 or 16.  IEEE and VAX formats use radix 2, and IBM
+ * mainframe format uses radix 16; we know of no other radices in
+ * practical use.
+ */
+#if FLT_RADIX != 2 && FLT_RADIX != 16
+Please port the following code to your weird host;
+#endif
+#define AWKNUM_FRACTION_BITS (AWKNUM_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4))
+ 
+/* tmp_integer - Convert an integer to a temporary number node.  */
+
+static NODE *
+tmp_integer(uintmax_t n)
+{
+  /*
+   * If uintmax_t is so wide that AWKNUM cannot represent all its
+   * values, strip leading nonzero bits of integers that are so large
+   * that they cannot be represented exactly as AWKNUMs, so that their
+   * low order bits are represented exactly, without rounding errors.
+   * 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;
+
+  return tmp_number((AWKNUM) n);
+}
+
 /* do_lshift --- perform a << operation */
 
 NODE *
@@ -2431,7 +2494,7 @@ do_lshift(NODE *tree)
        ushift = (uintmax_t) shift;
 
        res = uval << ushift;
-       return tmp_number((AWKNUM) res);
+       return tmp_integer(res);
 }
 
 /* do_rshift --- perform a >> operation */
@@ -2468,7 +2531,7 @@ do_rshift(NODE *tree)
        ushift = (uintmax_t) shift;
 
        res = uval >> ushift;
-       return tmp_number((AWKNUM) res);
+       return tmp_integer(res);
 }
 
 /* do_and --- perform an & operation */
@@ -2503,7 +2566,7 @@ do_and(NODE *tree)
        uright = (uintmax_t) right;
 
        res = uleft & uright;
-       return tmp_number((AWKNUM) res);
+       return tmp_integer(res);
 }
 
 /* do_or --- perform an | operation */
@@ -2538,7 +2601,7 @@ do_or(NODE *tree)
        uright = (uintmax_t) right;
 
        res = uleft | uright;
-       return tmp_number((AWKNUM) res);
+       return tmp_integer(res);
 }
 
 /* do_xor --- perform an ^ operation */
@@ -2573,7 +2636,7 @@ do_xor(NODE *tree)
        uright = (uintmax_t) right;
 
        res = uleft ^ uright;
-       return tmp_number((AWKNUM) res);
+       return tmp_integer(res);
 }
 
 /* do_compl --- perform a ~ operation */
@@ -2600,7 +2663,7 @@ do_compl(NODE *tree)
 
        uval = (uintmax_t) d;
        uval = ~ uval;
-       return tmp_number((AWKNUM) uval);
+       return tmp_integer(uval);
 }
 
 /* do_strtonum --- the strtonum function */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]