+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.
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;
}
}
Depends-on:
math
isnand [test $REPLACE_LDEXP = 1]
+stdbool [test $REPLACE_LDEXP = 1]
configure.ac:
gl_FUNC_LDEXP
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
/* Written by Bruno Haible <bruno@clisp.org>, 2007, 2010. */
+#include <limits.h>
+
static void
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))
{