This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Fix acosf underflow (bug 14153)
- From: "Joseph S. Myers" <joseph at codesourcery dot com>
- To: libc-alpha at sourceware dot org
- Date: Thu, 24 May 2012 21:52:46 +0000 (UTC)
- Subject: Fix acosf underflow (bug 14153)
Bug 14153 is a spurious underflow exception from acosf (2e-17); the
cause is the acosf implementation calculating a value on the order of
the cube of its argument, which underflows. There is a test for very
small arguments, maybe to avoid underflow, and if such an argument is
encountered it returns pi/2 (computed by adding high and low parts, I
suppose to get correct results for the current rounding mode and to
raise the inexact exception). However, this tests for values no more
than 2**-57, as if the test was unchanged from a "double" version of
the function; it suffices to test for values no more than 2**-26,
which avoids the problem with internal underflows. (For small x, the
correct value is essentially pi/2 - x. Compute pi/2 rounded to 25
bits - one more bit than float - which is the nearest value that is
representable as float or half way between two representable values.
Compute the difference of pi/2 and that rounded values; if |x| is
smaller than that difference then the result of rounding pi/2 - x will
be the same in any rounding mode as the result of rounding pi/2. Now
that difference is more than 2**-26.)
I propose this patch fixing the bug that way. Tested x86_64 and x86.
2012-05-24 Joseph Myers <joseph@codesourcery.com>
[BZ #14153]
* sysdeps/ieee754/flt-32/e_acosf.c (__ieee754_acosf): Return pi/2
for |x| <= 2**-26, not 2**-57.
* math/libm-test.inc (acos_test): Do not allow spurious underflow
exception.
diff --git a/math/libm-test.inc b/math/libm-test.inc
index 5946ca8..ed13f53 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -804,8 +804,7 @@ acos_test (void)
TEST_f_f (acos, 0.5, M_PI_6l*2.0);
TEST_f_f (acos, -0.5, M_PI_6l*4.0);
TEST_f_f (acos, 0.75L, 0.722734247813415611178377352641333362L);
- /* Bug 14153: spurious exception may occur. */
- TEST_f_f (acos, 2e-17L, 1.57079632679489659923132169163975144L, UNDERFLOW_EXCEPTION_OK_FLOAT);
+ TEST_f_f (acos, 2e-17L, 1.57079632679489659923132169163975144L);
TEST_f_f (acos, 0.0625L, 1.50825556499840522843072005474337068L);
TEST_f_f (acos, 0x0.ffffffp0L, 3.4526698471620358760324948263873649728491e-4L);
TEST_f_f (acos, -0x0.ffffffp0L, 3.1412473866050770348750401337968641476999L);
diff --git a/sysdeps/ieee754/flt-32/e_acosf.c b/sysdeps/ieee754/flt-32/e_acosf.c
index c0f1d4e..6f792f6 100644
--- a/sysdeps/ieee754/flt-32/e_acosf.c
+++ b/sysdeps/ieee754/flt-32/e_acosf.c
@@ -46,7 +46,7 @@ __ieee754_acosf(float x)
return (x-x)/(x-x); /* acos(|x|>1) is NaN */
}
if(ix<0x3f000000) { /* |x| < 0.5 */
- if(ix<=0x23000000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+ if(ix<=0x32800000) return pio2_hi+pio2_lo;/*if|x|<=2**-26*/
z = x*x;
p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
--
Joseph S. Myers
joseph@codesourcery.com