Fix catan, catanh, __ieee754_logf in round-downward mode (bug 16799, bug 16800)
Commit Message
This patch fixes incorrect results from catan and catanh of certain
special inputs in round-downward mode (bug 16799), and incorrect
results of __ieee754_logf (+/-0) in round-downward mode (bug 16800)
that show up through catan/catanh when tested in all rounding modes,
but not directly in the testing for logf because the bug gets hidden
by the wrappers.
Both bugs involve a zero that should be +0 being -0 instead: one
computed as (1-x)*(1+x) in the catan/catanh case, and one as (x-x) in
the logf case. The fixes ensure positive zero is used. Testing of
catan and catanh in all rounding modes is duly enabled.
I expect there are various other bugs in special cases in __ieee754_*
functions that are normally hidden by the wrappers but would show up
for testing with -lieee (or in future with -fno-math-errno if we
replace -lieee and _LIB_VERSION with compile-time redirection to new
*_noerrno symbol names).
Tested x86_64 and x86 and ulps updated accordingly.
2014-04-02 Joseph Myers <joseph@codesourcery.com>
[BZ #16799]
[BZ #16800]
* math/s_catan.c (__catan): Avoid passing -0 denominator to atan2
with 0 numerator.
* math/s_catanf.c (__catanf): Likewise.
* math/s_catanh.c (__catanh): Likewise.
* math/s_catanhf.c (__catanhf): Likewise.
* math/s_catanhl.c (__catanhl): Likewise.
* math/s_catanl.c (__catanl): Likewise.
* sysdeps/ieee754/flt-32/e_logf.c (__ieee754_logf): Always divide
by positive zero when computing -Inf result.
* math/libm-test.inc (catan_test): Use ALL_RM_TEST.
(catanh_test): Likewise.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
Comments
On 04/02/2014 04:26 PM, Joseph S. Myers wrote:
> This patch fixes incorrect results from catan and catanh of certain
> special inputs in round-downward mode (bug 16799), and incorrect
> results of __ieee754_logf (+/-0) in round-downward mode (bug 16800)
> that show up through catan/catanh when tested in all rounding modes,
> but not directly in the testing for logf because the bug gets hidden
> by the wrappers.
>
> Both bugs involve a zero that should be +0 being -0 instead: one
> computed as (1-x)*(1+x) in the catan/catanh case, and one as (x-x) in
> the logf case. The fixes ensure positive zero is used. Testing of
> catan and catanh in all rounding modes is duly enabled.
>
> I expect there are various other bugs in special cases in __ieee754_*
> functions that are normally hidden by the wrappers but would show up
> for testing with -lieee (or in future with -fno-math-errno if we
> replace -lieee and _LIB_VERSION with compile-time redirection to new
> *_noerrno symbol names).
Thanks,
Andreas
@@ -5239,9 +5239,7 @@ static const struct test_c_c_data catan_test_data[] =
static void
catan_test (void)
{
- START (catan, 0);
- RUN_TEST_LOOP_c_c (catan, catan_test_data, );
- END_COMPLEX;
+ ALL_RM_TEST (catan, 0, catan_test_data, RUN_TEST_LOOP_c_c, END_COMPLEX);
}
static const struct test_c_c_data catanh_test_data[] =
@@ -5746,9 +5744,7 @@ static const struct test_c_c_data catanh_test_data[] =
static void
catanh_test (void)
{
- START (catanh, 0);
- RUN_TEST_LOOP_c_c (catanh, catanh_test_data, );
- END_COMPLEX;
+ ALL_RM_TEST (catanh, 0, catanh_test_data, RUN_TEST_LOOP_c_c, END_COMPLEX);
}
static const struct test_f_f_data cbrt_test_data[] =
@@ -89,7 +89,11 @@ __catan (__complex__ double x)
}
if (absy < DBL_EPSILON / 2.0)
- den = (1.0 - absx) * (1.0 + absx);
+ {
+ den = (1.0 - absx) * (1.0 + absx);
+ if (den == -0.0)
+ den = 0.0;
+ }
else if (absx >= 1.0)
den = (1.0 - absx) * (1.0 + absx) - absy * absy;
else if (absx >= 0.75 || absy >= 0.5)
@@ -90,7 +90,11 @@ __catanf (__complex__ float x)
}
if (absy < FLT_EPSILON / 2.0f)
- den = (1.0f - absx) * (1.0f + absx);
+ {
+ den = (1.0f - absx) * (1.0f + absx);
+ if (den == -0.0f)
+ den = 0.0f;
+ }
else if (absx >= 1.0f)
den = (1.0f - absx) * (1.0f + absx) - absy * absy;
else if (absx >= 0.75f || absy >= 0.5f)
@@ -110,7 +110,11 @@ __catanh (__complex__ double x)
}
if (absy < DBL_EPSILON / 2.0)
- den = (1.0 - absx) * (1.0 + absx);
+ {
+ den = (1.0 - absx) * (1.0 + absx);
+ if (den == -0.0)
+ den = 0.0;
+ }
else if (absx >= 1.0)
den = (1.0 - absx) * (1.0 + absx) - absy * absy;
else if (absx >= 0.75 || absy >= 0.5)
@@ -112,7 +112,11 @@ __catanhf (__complex__ float x)
}
if (absy < FLT_EPSILON / 2.0f)
- den = (1.0f - absx) * (1.0f + absx);
+ {
+ den = (1.0f - absx) * (1.0f + absx);
+ if (den == -0.0f)
+ den = 0.0f;
+ }
else if (absx >= 1.0f)
den = (1.0f - absx) * (1.0f + absx) - absy * absy;
else if (absx >= 0.75f || absy >= 0.5f)
@@ -118,7 +118,11 @@ __catanhl (__complex__ long double x)
}
if (absy < LDBL_EPSILON / 2.0L)
- den = (1.0L - absx) * (1.0L + absx);
+ {
+ den = (1.0L - absx) * (1.0L + absx);
+ if (den == -0.0L)
+ den = 0.0L;
+ }
else if (absx >= 1.0L)
den = (1.0L - absx) * (1.0L + absx) - absy * absy;
else if (absx >= 0.75L || absy >= 0.5L)
@@ -97,7 +97,11 @@ __catanl (__complex__ long double x)
}
if (absy < LDBL_EPSILON / 2.0L)
- den = (1.0L - absx) * (1.0L + absx);
+ {
+ den = (1.0L - absx) * (1.0L + absx);
+ if (den == -0.0L)
+ den = 0.0L;
+ }
else if (absx >= 1.0L)
den = (1.0L - absx) * (1.0L + absx) - absy * absy;
else if (absx >= 0.75L || absy >= 0.5L)
@@ -383,6 +383,54 @@ ifloat: 1
ildouble: 1
ldouble: 1
+Function: Real part of "catan_downward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "catan_downward":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Real part of "catan_towardzero":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "catan_towardzero":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Real part of "catan_upward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "catan_upward":
+double: 2
+float: 2
+idouble: 2
+ifloat: 2
+ildouble: 3
+ldouble: 3
+
Function: Real part of "catanh":
double: 1
float: 1
@@ -391,6 +439,54 @@ ifloat: 1
ildouble: 1
ldouble: 1
+Function: Real part of "catanh_downward":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "catanh_downward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Real part of "catanh_towardzero":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "catanh_towardzero":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Real part of "catanh_upward":
+double: 2
+float: 2
+idouble: 2
+ifloat: 2
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "catanh_upward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
Function: "cbrt":
double: 1
idouble: 1
@@ -41,7 +41,7 @@ __ieee754_logf(float x)
k=0;
if (ix < 0x00800000) { /* x < 2**-126 */
if (__builtin_expect((ix&0x7fffffff)==0, 0))
- return -two25/(x-x); /* log(+-0)=-inf */
+ return -two25/zero; /* log(+-0)=-inf */
if (__builtin_expect(ix<0, 0))
return (x-x)/(x-x); /* log(-#) = NaN */
k -= 25; x *= two25; /* subnormal number, scale up x */
@@ -410,6 +410,54 @@ ifloat: 1
ildouble: 1
ldouble: 1
+Function: Real part of "catan_downward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "catan_downward":
+double: 2
+float: 2
+idouble: 2
+ifloat: 2
+ildouble: 4
+ldouble: 4
+
+Function: Real part of "catan_towardzero":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "catan_towardzero":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Real part of "catan_upward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "catan_upward":
+double: 3
+float: 3
+idouble: 3
+ifloat: 3
+ildouble: 3
+ldouble: 3
+
Function: Real part of "catanh":
double: 1
float: 1
@@ -422,6 +470,54 @@ Function: Imaginary part of "catanh":
float: 1
ifloat: 1
+Function: Real part of "catanh_downward":
+double: 2
+float: 2
+idouble: 2
+ifloat: 2
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "catanh_downward":
+double: 1
+float: 2
+idouble: 1
+ifloat: 2
+ildouble: 1
+ldouble: 1
+
+Function: Real part of "catanh_towardzero":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "catanh_towardzero":
+double: 1
+float: 2
+idouble: 1
+ifloat: 2
+ildouble: 1
+ldouble: 1
+
+Function: Real part of "catanh_upward":
+double: 4
+float: 3
+idouble: 4
+ifloat: 3
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "catanh_upward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
Function: "cbrt":
double: 1
float: 1