]> Savannah Git Hosting - gnulib.git/commitdiff
ldexp: fix INT_MIN infloop
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 20 Aug 2023 20:23:11 +0000 (13:23 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 20 Aug 2023 20:23:33 +0000 (13:23 -0700)
* lib/ldexp.c (FUNC): Instead of converting EXP to unsigned,
work on it directly.  This simplifies the code and avoids
an infinite loop when EXP == INT_MIN.
* modules/ldexp, modules/ldexpl: Depend on stdbool.
* tests/test-ldexp.h: Include <limits.h> for INT_MIN.
(test_function): Test for infloop.

ChangeLog
lib/ldexp.c
modules/ldexp
modules/ldexpl
tests/test-ldexp.h

index bad59ebcf664edc1fb7d6d00c4726e2b4232e341..764176466ff73b2fb6d2304242c1f0d0bb5906a0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2023-08-20  Paul Eggert  <eggert@cs.ucla.edu>
+
+       ldexp: fix INT_MIN infloop
+       * lib/ldexp.c (FUNC): Instead of converting EXP to unsigned,
+       work on it directly.  This simplifies the code and avoids
+       an infinite loop when EXP == INT_MIN.
+       * modules/ldexp, modules/ldexpl: Depend on stdbool.
+       * tests/test-ldexp.h: Include <limits.h> for INT_MIN.
+       (test_function): Test for infloop.
+
 2023-08-20  Bruno Haible  <bruno@clisp.org>
 
        ldexp: Fix compilation error in C++ mode.
index dd09ca3814060fbd6617ab73ff8df3400be55678..844fd11f534f9e6f0850acc5802e355cff4c62fe 100644 (file)
@@ -57,38 +57,19 @@ FUNC (DOUBLE x, int exp)
   BEGIN_ROUNDING ();
 
   /* Check for zero, nan and infinity. */
-  if (!(ISNAN (x) || x + x == x))
+  if (!(ISNAN (x) || x + x == x || exp == 0))
     {
-      unsigned int uexp;
-      DOUBLE factor;
+      bool negexp = exp < 0;
+      DOUBLE factor = negexp ? L_(0.5) : L_(2.0);
 
-      if (exp < 0)
+      while (true)
         {
-          /* Avoid signed integer overflow when exp == INT_MIN.  */
-          uexp = (unsigned int) (-1 - exp) + 1;
-          factor = L_(0.5);
-        }
-      else
-        {
-          uexp = exp;
-          factor = L_(2.0);
-        }
-
-      if (uexp > 0)
-        {
-          unsigned int bit;
-
-          for (bit = 1;;)
-            {
-              /* Invariant: Here bit = 2^i, factor = 2^-2^i or = 2^2^i,
-                 and bit <= uexp.  */
-              if (uexp & bit)
-                x *= factor;
-              bit <<= 1;
-              if (bit > uexp)
-                break;
-              factor = factor * factor;
-            }
+          if (exp & 1)
+            x *= factor;
+          exp = (exp + negexp) >> 1;
+          if (exp == 0)
+            break;
+          factor = factor * factor;
         }
     }
 
index 2f55db64161f0c449c4f0f5bcb1e21f782eb2219..528efaad772d427136e94ab6c906da4ea07f87f2 100644 (file)
@@ -8,6 +8,7 @@ m4/ldexp.m4
 Depends-on:
 math
 isnand          [test $REPLACE_LDEXP = 1]
+stdbool         [test $REPLACE_LDEXP = 1]
 
 configure.ac:
 gl_FUNC_LDEXP
index 515ce713cde55b89b2f7ff027d2f36d36cb8e637..622cad6ef5e184e10d96a9301dee14bd6d558349 100644 (file)
@@ -12,6 +12,7 @@ extensions
 ldexp           [{ test $HAVE_DECL_LDEXPL = 0 || test $gl_func_ldexpl = no; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1]
 isnanl          [{ test $HAVE_DECL_LDEXPL = 0 || test $gl_func_ldexpl = no; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
 fpucw           [{ test $HAVE_DECL_LDEXPL = 0 || test $gl_func_ldexpl = no; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+stdbool         [{ test $HAVE_DECL_LDEXPL = 0 || test $gl_func_ldexpl = no; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
 
 configure.ac:
 gl_FUNC_LDEXPL
index b1aac4f325a1e8c8a96241865d14efbb815c0233..5252b1424c5148ffbab1fc58e930026c3d8954f4 100644 (file)
@@ -16,6 +16,8 @@
 
 /* Written by Bruno Haible <bruno@clisp.org>, 2007, 2010.  */
 
+#include <limits.h>
+
 static void
 test_function (void)
 {
@@ -99,6 +101,7 @@ test_function (void)
         ASSERT (y == expected);
       }
       y = LDEXP (x, -5); ASSERT (y == x * 0.03125L);
+      y = LDEXP (x, INT_MIN); ASSERT (y == 0);
     }
   for (i = 1, x = L_(1.73205); i >= MIN_EXP; i--, x *= L_(0.5))
     {