# Fix cosh spurious underflows from expm1 (bug 16354), inaccurate results near 0 (bug 17061)

Message ID | Pine.LNX.4.64.1406162136430.14606@digraph.polyomino.org.uk |
---|---|

State | Committed |

Headers |

## Commit Message

## Comments

diff --git a/math/auto-libm-test-in b/math/auto-libm-test-in index 6edad5a..c29abbf 100644 --- a/math/auto-libm-test-in +++ b/math/auto-libm-test-in @@ -624,11 +624,14 @@ cosh 50 # GCC bug 59666: results on directed rounding may be incorrect. cosh max no-test-inline xfail-rounding:ldbl-128ibm cosh -max no-test-inline xfail-rounding:ldbl-128ibm -# Bug 16354: spurious underflow may occur. -cosh min spurious-underflow -cosh -min spurious-underflow -cosh min_subnorm spurious-underflow -cosh -min_subnorm spurious-underflow +cosh min +cosh -min +cosh min_subnorm +cosh -min_subnorm +cosh 0x1p-56 +cosh -0x1p-56 +cosh 0x1p-72 +cosh -0x1p-72 # Test values either side of overflow for each floating-point format. cosh 0x5.96a7ep+4 cosh 0x5.96a7e8p+4 diff --git a/sysdeps/i386/fpu/libm-test-ulps b/sysdeps/i386/fpu/libm-test-ulps index d7424a6..148584e 100644 --- a/sysdeps/i386/fpu/libm-test-ulps +++ b/sysdeps/i386/fpu/libm-test-ulps @@ -895,6 +895,7 @@ ldouble: 2 Function: "cosh_upward": double: 1 +float: 1 idouble: 1 ifloat: 1 ildouble: 2 diff --git a/sysdeps/ieee754/dbl-64/e_cosh.c b/sysdeps/ieee754/dbl-64/e_cosh.c index 6caf943..af3910d 100644 --- a/sysdeps/ieee754/dbl-64/e_cosh.c +++ b/sysdeps/ieee754/dbl-64/e_cosh.c @@ -53,10 +53,10 @@ __ieee754_cosh (double x) /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ if (ix < 0x3fd62e43) { + if (ix < 0x3c800000) + return one; /* cosh(tiny) = 1 */ t = __expm1 (fabs (x)); w = one + t; - if (ix < 0x3c800000) - return w; /* cosh(tiny) = 1 */ return one + (t * t) / (w + w); } diff --git a/sysdeps/ieee754/flt-32/e_coshf.c b/sysdeps/ieee754/flt-32/e_coshf.c index 7eeea4d..dedda47 100644 --- a/sysdeps/ieee754/flt-32/e_coshf.c +++ b/sysdeps/ieee754/flt-32/e_coshf.c @@ -33,9 +33,9 @@ __ieee754_coshf (float x) if (ix < 0x41b00000) { /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ if(ix<0x3eb17218) { + if (ix<0x24000000) return one; /* cosh(tiny) = 1 */ t = __expm1f(fabsf(x)); w = one+t; - if (ix<0x24000000) return w; /* cosh(tiny) = 1 */ return one+(t*t)/(w+w); } diff --git a/sysdeps/ieee754/ldbl-128/e_coshl.c b/sysdeps/ieee754/ldbl-128/e_coshl.c index 59f2030..488c318 100644 --- a/sysdeps/ieee754/ldbl-128/e_coshl.c +++ b/sysdeps/ieee754/ldbl-128/e_coshl.c @@ -77,10 +77,10 @@ __ieee754_coshl (long double x) /* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expl(|x|)) */ if (ex < 0x3ffd62e4) /* 0.3465728759765625 */ { + if (ex < 0x3fb80000) /* |x| < 2^-116 */ + return one; /* cosh(tiny) = 1 */ t = __expm1l (u.value); w = one + t; - if (ex < 0x3fb80000) /* |x| < 2^-116 */ - return w; /* cosh(tiny) = 1 */ return one + (t * t) / (w + w); } diff --git a/sysdeps/ieee754/ldbl-128ibm/e_coshl.c b/sysdeps/ieee754/ldbl-128ibm/e_coshl.c index 92313e2..327b2ab 100644 --- a/sysdeps/ieee754/ldbl-128ibm/e_coshl.c +++ b/sysdeps/ieee754/ldbl-128ibm/e_coshl.c @@ -53,9 +53,9 @@ __ieee754_coshl (long double x) /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ if(ix<0x3fd62e42fefa39efLL) { + if (ix<0x3c80000000000000LL) return one; /* cosh(tiny) = 1 */ t = __expm1l(fabsl(x)); w = one+t; - if (ix<0x3c80000000000000LL) return w; /* cosh(tiny) = 1 */ return one+(t*t)/(w+w); } diff --git a/sysdeps/ieee754/ldbl-96/e_coshl.c b/sysdeps/ieee754/ldbl-96/e_coshl.c index 995c992..dd22cae 100644 --- a/sysdeps/ieee754/ldbl-96/e_coshl.c +++ b/sysdeps/ieee754/ldbl-96/e_coshl.c @@ -54,9 +54,9 @@ __ieee754_coshl (long double x) if (ex < 0x4003 || (ex == 0x4003 && mx < 0xb0000000u)) { /* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expl(|x|)) */ if(ex < 0x3ffd || (ex == 0x3ffd && mx < 0xb17217f7u)) { + if (ex<0x3fbc) return one; /* cosh(tiny) = 1 */ t = __expm1l(fabsl(x)); w = one+t; - if (ex<0x3fbc) return w; /* cosh(tiny) = 1 */ return one+(t*t)/(w+w); }