This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Fix missing overflow exceptions from pow (bug 13873)
- From: "Joseph S. Myers" <joseph at codesourcery dot com>
- To: libc-alpha at sourceware dot org
- Date: Sun, 8 Apr 2012 22:04:30 +0000 (UTC)
- Subject: Fix missing overflow exceptions from pow (bug 13873)
Bug 13873 is a failure of pow to raise overflow exceptions on x86_64
when the absolute value of the exponent is so large that taking that
power of any floating-point value other than plus or minus zero, one,
infinity or NaN would overflow or underflow. I propose this patch to
fix this bug by doing computations at runtime that overflow or
underflow as required, as done in various other places in libm. (The
"huge" and "tiny" constants are the same as used for this purpose
elsewhere in dbl-64, so will be merged with the other instances since
glibc is built with -fmerge-all-constants.)
Tested x86 and x86_64.
2012-04-08 Joseph Myers <joseph@codesourcery.com>
[BZ #13873]
* sysdeps/ieee754/dbl-64/e_pow.c (huge, tiny): New variables.
(__ieee754_pow): Generate overflow and underflow using huge*huge
and tiny*tiny rather than just returning constant infinity or zero
for large exponents.
* math/libm-test.inc (pow_test): Require overflow exceptions for
applicable cases of large exponents.
diff --git a/math/libm-test.inc b/math/libm-test.inc
index 32bce45..2fd7c3b 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -5622,8 +5622,7 @@ pow_test (void)
TEST_ff_f (pow, 0x1p72L, 0x1p72L, plus_infty, OVERFLOW_EXCEPTION);
TEST_ff_f (pow, 10, -0x1p72L, 0);
- /* Bug 13873: OVERFLOW exception may be missing. */
- TEST_ff_f (pow, max_value, max_value, plus_infty, OVERFLOW_EXCEPTION_OK);
+ TEST_ff_f (pow, max_value, max_value, plus_infty, OVERFLOW_EXCEPTION);
/* Bug 13872: spurious OVERFLOW exception may be present. */
TEST_ff_f (pow, 10, -max_value, 0, OVERFLOW_EXCEPTION_OK);
@@ -5909,8 +5908,7 @@ pow_test (void)
TEST_ff_f (pow, -2.0, 0x1.ffffffffffffffffffffffffffffp+113L, plus_infty, OVERFLOW_EXCEPTION);
# endif
#endif
- /* Bug 13873: OVERFLOW exception may be missing. */
- TEST_ff_f (pow, -2.0, max_value, plus_infty, OVERFLOW_EXCEPTION_OK);
+ TEST_ff_f (pow, -2.0, max_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_ff_f (pow, -max_value, 0.5, nan_value, INVALID_EXCEPTION);
TEST_ff_f (pow, -max_value, 1.5, nan_value, INVALID_EXCEPTION);
@@ -5963,8 +5961,7 @@ pow_test (void)
TEST_ff_f (pow, -max_value, 0x1.ffffffffffffffffffffffffffffp+113L, plus_infty, OVERFLOW_EXCEPTION);
# endif
#endif
- /* Bug 13873: OVERFLOW exception may be missing. */
- TEST_ff_f (pow, -max_value, max_value, plus_infty, OVERFLOW_EXCEPTION_OK);
+ TEST_ff_f (pow, -max_value, max_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_ff_f (pow, -0.5, 126, 0x1p-126);
TEST_ff_f (pow, -0.5, 127, -0x1p-127);
@@ -5991,8 +5988,7 @@ pow_test (void)
TEST_ff_f (pow, -0.5, -0x1.ffffffffffffffffffffffffffffp+113L, plus_infty, OVERFLOW_EXCEPTION);
# endif
#endif
- /* Bug 13873: OVERFLOW exception may be missing. */
- TEST_ff_f (pow, -0.5, -max_value, plus_infty, OVERFLOW_EXCEPTION_OK);
+ TEST_ff_f (pow, -0.5, -max_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_ff_f (pow, -0.5, 0xffffff, minus_zero);
TEST_ff_f (pow, -0.5, 0x1fffffe, plus_zero);
@@ -6045,8 +6041,7 @@ pow_test (void)
TEST_ff_f (pow, -min_value, -0x1.ffffffffffffffffffffffffffffp+113L, plus_infty, OVERFLOW_EXCEPTION);
# endif
#endif
- /* Bug 13873: OVERFLOW exception may be missing. */
- TEST_ff_f (pow, -min_value, -max_value, plus_infty, OVERFLOW_EXCEPTION_OK);
+ TEST_ff_f (pow, -min_value, -max_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_ff_f (pow, -min_value, 0xffffff, minus_zero);
TEST_ff_f (pow, -min_value, 0x1fffffe, plus_zero);
diff --git a/sysdeps/ieee754/dbl-64/e_pow.c b/sysdeps/ieee754/dbl-64/e_pow.c
index 26ffaad..6c41af9 100644
--- a/sysdeps/ieee754/dbl-64/e_pow.c
+++ b/sysdeps/ieee754/dbl-64/e_pow.c
@@ -47,6 +47,7 @@
# define SECTION
#endif
+static const double huge = 1.0e300, tiny = 1.0e-300;
double __exp1(double x, double xx, double error);
static double log1(double x, double *delta, double *error);
@@ -156,8 +157,8 @@ __ieee754_pow(double x, double y) {
if (qy > 0x45f00000 && qy < 0x7ff00000) {
if (x == 1.0) return 1.0;
- if (y>0) return (x>1.0)?INF.x:0;
- if (y<0) return (x<1.0)?INF.x:0;
+ if (y>0) return (x>1.0)?huge*huge:tiny*tiny;
+ if (y<0) return (x<1.0)?huge*huge:tiny*tiny;
}
if (x == 1.0) return 1.0;
--
Joseph S. Myers
joseph@codesourcery.com