Fix cexp, ccos, ccosh, csin, csinh spurious underflows (bug 18594).

cexp, ccos, ccosh, csin and csinh have spurious underflows in cases
where they compute sin of the smallest normal, that produces an
underflow exception (depending on which sin implementation is in use)
but the final result does not underflow.  ctan and ctanh may also have
such underflows, or they may be latent (the issue there is that
e.g. ctan (DBL_MIN) should, rounded upwards, be the next double value
above DBL_MIN, which under glibc's accuracy goals may not have an
underflow exception, but the intermediate computation of sin (DBL_MIN)
would legitimately underflow on before-rounding architectures).

This patch fixes all those functions so they use plain comparisons (>
DBL_MIN etc.) instead of comparing the result of fpclassify with
FP_SUBNORMAL (in all these cases, we already know the number being
compared is finite).  Note that in the case of csin / csinf / csinl,
there is no need for fabs calls in the comparison because the real
part has already been reduced to its absolute value.

As the patch fixes the failures that previously obstructed moving
tests of cexp to use ALL_RM_TEST, those tests are moved to ALL_RM_TEST
by the patch (two functions remain yet to be converted).

Tested for x86_64 and x86 and ulps updated accordingly.

	[BZ #18594]
	* math/s_ccosh.c (__ccosh): Compare with least normal value
	instead of comparing class with FP_SUBNORMAL.
	* math/s_ccoshf.c (__ccoshf): Likewise.
	* math/s_ccoshl.c (__ccoshl): Likewise.
	* math/s_cexp.c (__cexp): Likewise.
	* math/s_cexpf.c (__cexpf): Likewise.
	* math/s_cexpl.c (__cexpl): Likewise.
	* math/s_csin.c (__csin): Likewise.
	* math/s_csinf.c (__csinf): Likewise.
	* math/s_csinh.c (__csinh): Likewise.
	* math/s_csinhf.c (__csinhf): Likewise.
	* math/s_csinhl.c (__csinhl): Likewise.
	* math/s_csinl.c (__csinl): Likewise.
	* math/s_ctan.c (__ctan): Likewise.
	* math/s_ctanf.c (__ctanf): Likewise.
	* math/s_ctanh.c (__ctanh): Likewise.
	* math/s_ctanhf.c (__ctanhf): Likewise.
	* math/s_ctanhl.c (__ctanhl): Likewise.
	* math/s_ctanl.c (__ctanl): Likewise.
	* math/auto-libm-test-in: Add more tests of ccos, ccosh, cexp,
	csin, csinh, ctan and ctanh.
	* math/auto-libm-test-out: Regenerated.
	* math/libm-test.inc (cexp_test): Use ALL_RM_TEST.
	* sysdeps/i386/fpu/libm-test-ulps: Update.
	* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
This commit is contained in:
Joseph Myers 2015-06-24 21:04:51 +00:00
parent 010186901d
commit a67894c505
25 changed files with 2414 additions and 38 deletions

View File

@ -1,3 +1,32 @@
2015-06-24 Joseph Myers <joseph@codesourcery.com>
[BZ #18594]
* math/s_ccosh.c (__ccosh): Compare with least normal value
instead of comparing class with FP_SUBNORMAL.
* math/s_ccoshf.c (__ccoshf): Likewise.
* math/s_ccoshl.c (__ccoshl): Likewise.
* math/s_cexp.c (__cexp): Likewise.
* math/s_cexpf.c (__cexpf): Likewise.
* math/s_cexpl.c (__cexpl): Likewise.
* math/s_csin.c (__csin): Likewise.
* math/s_csinf.c (__csinf): Likewise.
* math/s_csinh.c (__csinh): Likewise.
* math/s_csinhf.c (__csinhf): Likewise.
* math/s_csinhl.c (__csinhl): Likewise.
* math/s_csinl.c (__csinl): Likewise.
* math/s_ctan.c (__ctan): Likewise.
* math/s_ctanf.c (__ctanf): Likewise.
* math/s_ctanh.c (__ctanh): Likewise.
* math/s_ctanhf.c (__ctanhf): Likewise.
* math/s_ctanhl.c (__ctanhl): Likewise.
* math/s_ctanl.c (__ctanl): Likewise.
* math/auto-libm-test-in: Add more tests of ccos, ccosh, cexp,
csin, csinh, ctan and ctanh.
* math/auto-libm-test-out: Regenerated.
* math/libm-test.inc (cexp_test): Use ALL_RM_TEST.
* sysdeps/i386/fpu/libm-test-ulps: Update.
* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
2015-06-24 Roland McGrath <roland@hack.frob.com>
* sysdeps/unix/sysv/linux/tst-getcpu.c (do_test): When sched_getcpu

2
NEWS
View File

@ -24,7 +24,7 @@ Version 2.22
18444, 18468, 18469, 18470, 18479, 18483, 18495, 18496, 18497, 18498,
18507, 18512, 18513, 18519, 18520, 18522, 18527, 18528, 18529, 18530,
18532, 18533, 18534, 18536, 18539, 18540, 18542, 18544, 18545, 18546,
18547, 18553, 18558, 18569, 18583, 18585, 18586, 18593.
18547, 18553, 18558, 18569, 18583, 18585, 18586, 18593, 18594.
* Cache information can be queried via sysconf() function on s390 e.g. with
_SC_LEVEL1_ICACHE_SIZE as argument.

View File

@ -496,6 +496,11 @@ ccos 0x1p-16434 22730
ccos min_subnorm_p120 0x1p-120
ccos 0x1p-120 min_subnorm_p120
ccos min 1
ccos -min 1
ccos min_subnorm 80
ccos -min_subnorm 80
ccosh 0.0 0.0
ccosh -0 0.0
ccosh 0.0 -0
@ -524,6 +529,11 @@ ccosh 22730 0x1p-16434
ccosh min_subnorm_p120 0x1p-120
ccosh 0x1p-120 min_subnorm_p120
ccosh 1 min
ccosh 1 -min
ccosh 80 min_subnorm
ccosh 80 -min_subnorm
cexp 0 0
cexp -0 0
cexp 0 -0
@ -558,6 +568,11 @@ cexp 1e6 0
cexp 1e6 min
cexp 1e6 -min
cexp 1 min
cexp 1 -min
cexp 80 min_subnorm
cexp 80 -min_subnorm
cexp min min_subnorm
cexp min -min_subnorm
@ -985,6 +1000,11 @@ csin 0x1p-149 180
csin 0x1p-1074 1440
csin 0x1p-16434 22730
csin min 1
csin -min 1
csin min_subnorm 80
csin -min_subnorm 80
csinh 0.0 0.0
csinh -0 0.0
csinh 0.0 -0
@ -1015,6 +1035,11 @@ csinh 180 0x1p-149
csinh 1440 0x1p-1074
csinh 22730 0x1p-16434
csinh 1 min
csinh 1 -min
csinh 80 min_subnorm
csinh 80 -min_subnorm
csqrt 0 0
csqrt 0 -0
csqrt -0 0
@ -1132,6 +1157,12 @@ ctan 0x1.921fb6p+0 0x1p-149
ctan 0x1.921fb54442d18p+0 0x1p-1074
ctan 0x1.921fb54442d1846ap+0 0x1p-16445
# Bug 18595: underflow exception may be missing
ctan min 0 missing-underflow
ctan -min 0 missing-underflow
ctan min_subnorm 0 missing-underflow
ctan -min_subnorm 0 missing-underflow
ctanh 0 0
ctanh 0 -0
ctanh -0 0
@ -1166,6 +1197,12 @@ ctanh 0x1p-149 0x1.921fb6p+0
ctanh 0x1p-1074 0x1.921fb54442d18p+0
ctanh 0x1p-16445 0x1.921fb54442d1846ap+0
# Bug 18595: underflow exception may be missing
ctanh 0 min missing-underflow
ctanh 0 -min missing-underflow
ctanh 0 min_subnorm missing-underflow
ctanh 0 -min_subnorm missing-underflow
erf 0
erf -0
erf 0.125

File diff suppressed because it is too large Load Diff

View File

@ -6040,9 +6040,7 @@ static const struct test_c_c_data cexp_test_data[] =
static void
cexp_test (void)
{
START (cexp,, 0);
RUN_TEST_LOOP_c_c (cexp, cexp_test_data, );
END_COMPLEX;
ALL_RM_TEST (cexp, 0, cexp_test_data, RUN_TEST_LOOP_c_c, END_COMPLEX);
}

View File

@ -39,7 +39,7 @@ __ccosh (__complex__ double x)
const int t = (int) ((DBL_MAX_EXP - 1) * M_LN2);
double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabs (__imag__ x) > DBL_MIN))
{
__sincos (__imag__ x, &sinix, &cosix);
}
@ -113,7 +113,7 @@ __ccosh (__complex__ double x)
/* Imaginary part is finite. */
double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabs (__imag__ x) > DBL_MIN))
{
__sincos (__imag__ x, &sinix, &cosix);
}

View File

@ -39,7 +39,7 @@ __ccoshf (__complex__ float x)
const int t = (int) ((FLT_MAX_EXP - 1) * M_LN2);
float sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsf (__imag__ x) > FLT_MIN))
{
__sincosf (__imag__ x, &sinix, &cosix);
}
@ -113,7 +113,7 @@ __ccoshf (__complex__ float x)
/* Imaginary part is finite. */
float sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsf (__imag__ x) > FLT_MIN))
{
__sincosf (__imag__ x, &sinix, &cosix);
}

View File

@ -39,7 +39,7 @@ __ccoshl (__complex__ long double x)
const int t = (int) ((LDBL_MAX_EXP - 1) * M_LN2l);
long double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsl (__imag__ x) > LDBL_MIN))
{
__sincosl (__imag__ x, &sinix, &cosix);
}
@ -113,7 +113,7 @@ __ccoshl (__complex__ long double x)
/* Imaginary part is finite. */
long double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsl (__imag__ x) > LDBL_MIN))
{
__sincosl (__imag__ x, &sinix, &cosix);
}

View File

@ -39,7 +39,7 @@ __cexp (__complex__ double x)
const int t = (int) ((DBL_MAX_EXP - 1) * M_LN2);
double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabs (__imag__ x) > DBL_MIN))
{
__sincos (__imag__ x, &sinix, &cosix);
}
@ -115,7 +115,7 @@ __cexp (__complex__ double x)
{
double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabs (__imag__ x) > DBL_MIN))
{
__sincos (__imag__ x, &sinix, &cosix);
}

View File

@ -39,7 +39,7 @@ __cexpf (__complex__ float x)
const int t = (int) ((FLT_MAX_EXP - 1) * M_LN2);
float sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsf (__imag__ x) > FLT_MIN))
{
__sincosf (__imag__ x, &sinix, &cosix);
}
@ -115,7 +115,7 @@ __cexpf (__complex__ float x)
{
float sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsf (__imag__ x) > FLT_MIN))
{
__sincosf (__imag__ x, &sinix, &cosix);
}

View File

@ -39,7 +39,7 @@ __cexpl (__complex__ long double x)
const int t = (int) ((LDBL_MAX_EXP - 1) * M_LN2l);
long double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsl (__imag__ x) > LDBL_MIN))
{
__sincosl (__imag__ x, &sinix, &cosix);
}
@ -115,7 +115,7 @@ __cexpl (__complex__ long double x)
{
long double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsl (__imag__ x) > LDBL_MIN))
{
__sincosl (__imag__ x, &sinix, &cosix);
}

View File

@ -42,7 +42,7 @@ __csin (__complex__ double x)
const int t = (int) ((DBL_MAX_EXP - 1) * M_LN2);
double sinix, cosix;
if (__glibc_likely (rcls != FP_SUBNORMAL))
if (__glibc_likely (__real__ x > DBL_MIN))
{
__sincos (__real__ x, &sinix, &cosix);
}
@ -136,7 +136,7 @@ __csin (__complex__ double x)
/* Real part is finite. */
double sinix, cosix;
if (__glibc_likely (rcls != FP_SUBNORMAL))
if (__glibc_likely (__real__ x > DBL_MIN))
{
__sincos (__real__ x, &sinix, &cosix);
}

View File

@ -42,7 +42,7 @@ __csinf (__complex__ float x)
const int t = (int) ((FLT_MAX_EXP - 1) * M_LN2);
float sinix, cosix;
if (__glibc_likely (rcls != FP_SUBNORMAL))
if (__glibc_likely (__real__ x > FLT_MIN))
{
__sincosf (__real__ x, &sinix, &cosix);
}
@ -136,7 +136,7 @@ __csinf (__complex__ float x)
/* Real part is finite. */
float sinix, cosix;
if (__glibc_likely (rcls != FP_SUBNORMAL))
if (__glibc_likely (__real__ x > FLT_MIN))
{
__sincosf (__real__ x, &sinix, &cosix);
}

View File

@ -42,7 +42,7 @@ __csinh (__complex__ double x)
const int t = (int) ((DBL_MAX_EXP - 1) * M_LN2);
double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabs (__imag__ x) > DBL_MIN))
{
__sincos (__imag__ x, &sinix, &cosix);
}
@ -130,7 +130,7 @@ __csinh (__complex__ double x)
/* Imaginary part is finite. */
double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabs (__imag__ x) > DBL_MIN))
{
__sincos (__imag__ x, &sinix, &cosix);
}

View File

@ -42,7 +42,7 @@ __csinhf (__complex__ float x)
const int t = (int) ((FLT_MAX_EXP - 1) * M_LN2);
float sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsf (__imag__ x) > FLT_MIN))
{
__sincosf (__imag__ x, &sinix, &cosix);
}
@ -130,7 +130,7 @@ __csinhf (__complex__ float x)
/* Imaginary part is finite. */
float sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsf (__imag__ x) > FLT_MIN))
{
__sincosf (__imag__ x, &sinix, &cosix);
}

View File

@ -42,7 +42,7 @@ __csinhl (__complex__ long double x)
const int t = (int) ((LDBL_MAX_EXP - 1) * M_LN2l);
long double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsl (__imag__ x) > LDBL_MIN))
{
__sincosl (__imag__ x, &sinix, &cosix);
}
@ -130,7 +130,7 @@ __csinhl (__complex__ long double x)
/* Imaginary part is finite. */
long double sinix, cosix;
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsl (__imag__ x) > LDBL_MIN))
{
__sincosl (__imag__ x, &sinix, &cosix);
}

View File

@ -42,7 +42,7 @@ __csinl (__complex__ long double x)
const int t = (int) ((LDBL_MAX_EXP - 1) * M_LN2l);
long double sinix, cosix;
if (__glibc_likely (rcls != FP_SUBNORMAL))
if (__glibc_likely (__real__ x > LDBL_MIN))
{
__sincosl (__real__ x, &sinix, &cosix);
}
@ -136,7 +136,7 @@ __csinl (__complex__ long double x)
/* Real part is finite. */
long double sinix, cosix;
if (__glibc_likely (rcls != FP_SUBNORMAL))
if (__glibc_likely (__real__ x > LDBL_MIN))
{
__sincosl (__real__ x, &sinix, &cosix);
}

View File

@ -53,12 +53,11 @@ __ctan (__complex__ double x)
double sinrx, cosrx;
double den;
const int t = (int) ((DBL_MAX_EXP - 1) * M_LN2 / 2);
int rcls = fpclassify (__real__ x);
/* tan(x+iy) = (sin(2x) + i*sinh(2y))/(cos(2x) + cosh(2y))
= (sin(x)*cos(x) + i*sinh(y)*cosh(y)/(cos(x)^2 + sinh(y)^2). */
if (__glibc_likely (rcls != FP_SUBNORMAL))
if (__glibc_likely (fabs (__real__ x) > DBL_MIN))
{
__sincos (__real__ x, &sinrx, &cosrx);
}

View File

@ -57,7 +57,7 @@ __ctanf (__complex__ float x)
/* tan(x+iy) = (sin(2x) + i*sinh(2y))/(cos(2x) + cosh(2y))
= (sin(x)*cos(x) + i*sinh(y)*cosh(y)/(cos(x)^2 + sinh(y)^2). */
if (__glibc_likely (fpclassify(__real__ x) != FP_SUBNORMAL))
if (__glibc_likely (fabsf (__real__ x) > FLT_MIN))
{
__sincosf (__real__ x, &sinrx, &cosrx);
}

View File

@ -53,12 +53,11 @@ __ctanh (__complex__ double x)
double sinix, cosix;
double den;
const int t = (int) ((DBL_MAX_EXP - 1) * M_LN2 / 2);
int icls = fpclassify (__imag__ x);
/* tanh(x+iy) = (sinh(2x) + i*sin(2y))/(cosh(2x) + cos(2y))
= (sinh(x)*cosh(x) + i*sin(y)*cos(y))/(sinh(x)^2 + cos(y)^2). */
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabs (__imag__ x) > DBL_MIN))
{
__sincos (__imag__ x, &sinix, &cosix);
}

View File

@ -57,7 +57,7 @@ __ctanhf (__complex__ float x)
/* tanh(x+iy) = (sinh(2x) + i*sin(2y))/(cosh(2x) + cos(2y))
= (sinh(x)*cosh(x) + i*sin(y)*cos(y))/(sinh(x)^2 + cos(y)^2). */
if (__glibc_likely (fpclassify(__imag__ x) != FP_SUBNORMAL))
if (__glibc_likely (fabsf (__imag__ x) > FLT_MIN))
{
__sincosf (__imag__ x, &sinix, &cosix);
}

View File

@ -60,12 +60,11 @@ __ctanhl (__complex__ long double x)
long double sinix, cosix;
long double den;
const int t = (int) ((LDBL_MAX_EXP - 1) * M_LN2l / 2);
int icls = fpclassify (__imag__ x);
/* tanh(x+iy) = (sinh(2x) + i*sin(2y))/(cosh(2x) + cos(2y))
= (sinh(x)*cosh(x) + i*sin(y)*cos(y))/(sinh(x)^2 + cos(y)^2). */
if (__glibc_likely (icls != FP_SUBNORMAL))
if (__glibc_likely (fabsl (__imag__ x) > LDBL_MIN))
{
__sincosl (__imag__ x, &sinix, &cosix);
}

View File

@ -60,12 +60,11 @@ __ctanl (__complex__ long double x)
long double sinrx, cosrx;
long double den;
const int t = (int) ((LDBL_MAX_EXP - 1) * M_LN2l / 2);
int rcls = fpclassify (__real__ x);
/* tan(x+iy) = (sin(2x) + i*sinh(2y))/(cos(2x) + cosh(2y))
= (sin(x)*cos(x) + i*sinh(y)*cosh(y)/(cos(x)^2 + sinh(y)^2). */
if (__glibc_likely (rcls != FP_SUBNORMAL))
if (__glibc_likely (fabsl (__real__ x) > LDBL_MIN))
{
__sincosl (__real__ x, &sinrx, &cosrx);
}

View File

@ -668,6 +668,8 @@ double: 1
float: 1
idouble: 1
ifloat: 1
ildouble: 1
ldouble: 1
Function: Imaginary part of "ccosh":
double: 1
@ -741,6 +743,54 @@ ifloat: 1
ildouble: 1
ldouble: 1
Function: Real part of "cexp_downward":
double: 1
float: 1
idouble: 1
ifloat: 1
ildouble: 3
ldouble: 3
Function: Imaginary part of "cexp_downward":
double: 2
float: 2
idouble: 2
ifloat: 2
ildouble: 3
ldouble: 3
Function: Real part of "cexp_towardzero":
double: 1
float: 1
idouble: 1
ifloat: 1
ildouble: 3
ldouble: 3
Function: Imaginary part of "cexp_towardzero":
double: 2
float: 2
idouble: 2
ifloat: 2
ildouble: 3
ldouble: 3
Function: Real part of "cexp_upward":
double: 1
float: 1
idouble: 1
ifloat: 1
ildouble: 2
ldouble: 2
Function: Imaginary part of "cexp_upward":
double: 1
float: 1
idouble: 1
ifloat: 1
ildouble: 3
ldouble: 3
Function: Real part of "clog":
double: 3
float: 2
@ -1052,6 +1102,8 @@ double: 1
float: 1
idouble: 1
ifloat: 1
ildouble: 1
ldouble: 1
Function: Real part of "csinh_downward":
double: 1

View File

@ -744,6 +744,8 @@ double: 1
float: 1
idouble: 1
ifloat: 1
ildouble: 1
ldouble: 1
Function: Imaginary part of "ccosh":
double: 1
@ -817,6 +819,54 @@ ifloat: 2
ildouble: 1
ldouble: 1
Function: Real part of "cexp_downward":
double: 1
float: 2
idouble: 1
ifloat: 2
ildouble: 3
ldouble: 3
Function: Imaginary part of "cexp_downward":
double: 1
float: 3
idouble: 1
ifloat: 3
ildouble: 3
ldouble: 3
Function: Real part of "cexp_towardzero":
double: 1
float: 2
idouble: 1
ifloat: 2
ildouble: 3
ldouble: 3
Function: Imaginary part of "cexp_towardzero":
double: 1
float: 3
idouble: 1
ifloat: 3
ildouble: 3
ldouble: 3
Function: Real part of "cexp_upward":
double: 1
float: 2
idouble: 1
ifloat: 2
ildouble: 2
ldouble: 2
Function: Imaginary part of "cexp_upward":
double: 1
float: 2
idouble: 1
ifloat: 2
ildouble: 3
ldouble: 3
Function: Real part of "clog":
double: 3
float: 2
@ -1146,6 +1196,8 @@ double: 1
float: 1
idouble: 1
ifloat: 1
ildouble: 1
ldouble: 1
Function: Real part of "csinh_downward":
double: 2