diff options
author | Joseph Myers <joseph@codesourcery.com> | 2015-06-22 21:06:19 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2015-06-22 21:06:19 +0000 |
commit | 554edb23ffc7a953ca86309cc5f02dbd1a63abe0 (patch) | |
tree | 35ceb89ac22f1987f944539728fda653acd418f2 /sysdeps | |
parent | 6b142b3a1d007d7e6f50c26710de7177bc4aca74 (diff) | |
download | glibc-554edb23ffc7a953ca86309cc5f02dbd1a63abe0.tar.gz glibc-554edb23ffc7a953ca86309cc5f02dbd1a63abe0.tar.xz glibc-554edb23ffc7a953ca86309cc5f02dbd1a63abe0.zip |
Fix expm1 missing underflows (bug 16353).
Similar to various other bugs in this area, some expm1 implementations do not raise the underflow exception for subnormal arguments, when the result is tiny and inexact. This patch forces the exception in a similar way to previous fixes. (The issue does not apply to the ldbl-* implementations or to those for x86 / x86_64 long double. The change to sysdeps/ieee754/dbl-64/wordsize-64/e_cosh.c is one I missed when previously fixing bug 16354; the bug in that implementation was previously latent, but the expm1 fixes stopped it being latent and so required it to be fixed to avoid spurious underflows from cosh.) Tested for x86_64 and x86. [BZ #16353] * sysdeps/i386/fpu/s_expm1.S (dbl_min): New object. (__expm1): Force underflow exception for arguments with small absolute value. * sysdeps/i386/fpu/s_expm1f.S (flt_min): New object. (__expm1f): Force underflow exception for arguments with small absolute value. * sysdeps/ieee754/dbl-64/s_expm1.c: Include <float.h>. (__expm1): Force underflow exception for arguments with small absolute value. * sysdeps/ieee754/flt-32/s_expm1f.c: Include <float.h>. (__expm1f): Force underflow exception for arguments with small absolute value. * sysdeps/ieee754/dbl-64/wordsize-64/e_cosh.c (__ieee754_cosh): Check for small arguments before calling __expm1. * math/auto-libm-test-in: Do not mark underflow exceptions as possibly missing for bug 16353. * math/auto-libm-test-out: Regenerated.
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/i386/fpu/s_expm1.S | 22 | ||||
-rw-r--r-- | sysdeps/i386/fpu/s_expm1f.S | 22 | ||||
-rw-r--r-- | sysdeps/ieee754/dbl-64/s_expm1.c | 6 | ||||
-rw-r--r-- | sysdeps/ieee754/dbl-64/wordsize-64/e_cosh.c | 3 | ||||
-rw-r--r-- | sysdeps/ieee754/flt-32/s_expm1f.c | 6 |
5 files changed, 58 insertions, 1 deletions
diff --git a/sysdeps/i386/fpu/s_expm1.S b/sysdeps/i386/fpu/s_expm1.S index 65426c5984..05e5285d7b 100644 --- a/sysdeps/i386/fpu/s_expm1.S +++ b/sysdeps/i386/fpu/s_expm1.S @@ -37,6 +37,13 @@ one: .double 1.0 l2e: .tfloat 1.442695040888963407359924681002 ASM_SIZE_DIRECTIVE(l2e) + .section .rodata.cst8,"aM",@progbits,8 + + .p2align 3 + .type dbl_min,@object +dbl_min: .byte 0, 0, 0, 0, 0, 0, 0x10, 0 + ASM_SIZE_DIRECTIVE(dbl_min) + #ifdef PIC #define MO(op) op##@GOTOFF(%edx) #else @@ -74,6 +81,21 @@ ENTRY(__expm1) #ifdef PIC LOAD_PIC_REG (dx) #endif + fld %st + fabs + fcoml MO(dbl_min) + fstp %st + fnstsw + sahf + jae 5f + subl $8, %esp + cfi_adjust_cfa_offset (8) + fld %st(0) + fmul %st(0) + fstpl (%esp) + addl $8, %esp + cfi_adjust_cfa_offset (-8) + ret 5: fldt MO(l2e) // log2(e) : x fmulp // log2(e)*x diff --git a/sysdeps/i386/fpu/s_expm1f.S b/sysdeps/i386/fpu/s_expm1f.S index 748b7b8791..a83e435e22 100644 --- a/sysdeps/i386/fpu/s_expm1f.S +++ b/sysdeps/i386/fpu/s_expm1f.S @@ -37,6 +37,13 @@ one: .double 1.0 l2e: .tfloat 1.442695040888963407359924681002 ASM_SIZE_DIRECTIVE(l2e) + .section .rodata.cst4,"aM",@progbits,4 + + .p2align 2 + .type flt_min,@object +flt_min: .byte 0, 0, 0x80, 0 + ASM_SIZE_DIRECTIVE(flt_min) + #ifdef PIC #define MO(op) op##@GOTOFF(%edx) #else @@ -74,6 +81,21 @@ ENTRY(__expm1f) #ifdef PIC LOAD_PIC_REG (dx) #endif + fld %st + fabs + fcoms MO(flt_min) + fstp %st + fnstsw + sahf + jae 5f + subl $4, %esp + cfi_adjust_cfa_offset (4) + fld %st(0) + fmul %st(0) + fstps (%esp) + addl $4, %esp + cfi_adjust_cfa_offset (-4) + ret 5: fldt MO(l2e) // log2(e) : x fmulp // log2(e)*x diff --git a/sysdeps/ieee754/dbl-64/s_expm1.c b/sysdeps/ieee754/dbl-64/s_expm1.c index 9c9bb34559..41ef63a786 100644 --- a/sysdeps/ieee754/dbl-64/s_expm1.c +++ b/sysdeps/ieee754/dbl-64/s_expm1.c @@ -109,6 +109,7 @@ */ #include <errno.h> +#include <float.h> #include <math.h> #include <math_private.h> #define one Q[0] @@ -194,6 +195,11 @@ __expm1 (double x) } else if (hx < 0x3c900000) /* when |x|<2**-54, return x */ { + if (fabs (x) < DBL_MIN) + { + double force_underflow = x * x; + math_force_eval (force_underflow); + } t = huge + x; /* return x with inexact flags when x!=0 */ return x - (t - (huge + x)); } diff --git a/sysdeps/ieee754/dbl-64/wordsize-64/e_cosh.c b/sysdeps/ieee754/dbl-64/wordsize-64/e_cosh.c index 84593521cc..fca80b13f9 100644 --- a/sysdeps/ieee754/dbl-64/wordsize-64/e_cosh.c +++ b/sysdeps/ieee754/dbl-64/wordsize-64/e_cosh.c @@ -50,9 +50,10 @@ __ieee754_cosh (double x) if (ix < 0x40360000) { /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ if(ix<0x3fd62e43) { + if (ix<0x3c800000) /* cosh(tiny) = 1 */ + return one; 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/s_expm1f.c b/sysdeps/ieee754/flt-32/s_expm1f.c index ca8839fa22..c81b057f24 100644 --- a/sysdeps/ieee754/flt-32/s_expm1f.c +++ b/sysdeps/ieee754/flt-32/s_expm1f.c @@ -14,6 +14,7 @@ */ #include <errno.h> +#include <float.h> #include <math.h> #include <math_private.h> @@ -80,6 +81,11 @@ __expm1f(float x) c = (hi-x)-lo; } else if(hx < 0x33000000) { /* when |x|<2**-25, return x */ + if (fabsf (x) < FLT_MIN) + { + float force_underflow = x * x; + math_force_eval (force_underflow); + } t = huge+x; /* return x with inexact flags when x!=0 */ return x - (t-(huge+x)); } |