This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]