diff options
author | Joseph Myers <joseph@codesourcery.com> | 2015-06-23 22:24:20 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2015-06-23 22:24:20 +0000 |
commit | ad39cce0da0161dba69781c53349acf2e23f156c (patch) | |
tree | 1c7b29a8fe9358aa720485ca439db53d6749b379 /sysdeps/ieee754 | |
parent | 8b1bab5ffa235bc494c33fdbe4c9994202936cfc (diff) | |
download | glibc-ad39cce0da0161dba69781c53349acf2e23f156c.tar glibc-ad39cce0da0161dba69781c53349acf2e23f156c.tar.gz glibc-ad39cce0da0161dba69781c53349acf2e23f156c.tar.bz2 glibc-ad39cce0da0161dba69781c53349acf2e23f156c.zip |
Fix sin, sincos missing underflows (bug 16526, bug 16538).
Similar to various other bugs in this area, some sin and sincos
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.
Tested for x86_64, x86, mips64 and powerpc.
[BZ #16526]
[BZ #16538]
* sysdeps/ieee754/dbl-64/s_sin.c: Include <float.h>.
(__sin): Force underflow exception for arguments with small
absolute value.
* sysdeps/ieee754/flt-32/k_sinf.c: Include <float.h>.
(__kernel_sinf): Force underflow exception for arguments with
small absolute value.
* sysdeps/ieee754/ldbl-128/k_sincosl.c: Include <float.h>.
(__kernel_sincosl): Force underflow exception for arguments with
small absolute value.
* sysdeps/ieee754/ldbl-128/k_sinl.c: Include <float.h>.
(__kernel_sinl): Force underflow exception for arguments with
small absolute value.
* sysdeps/ieee754/ldbl-128ibm/k_sincosl.c: Include <float.h>.
(__kernel_sincosl): Force underflow exception for arguments with
small absolute value.
* sysdeps/ieee754/ldbl-128ibm/k_sinl.c: Include <float.h>.
(__kernel_sinl): Force underflow exception for arguments with
small absolute value.
* sysdeps/ieee754/ldbl-96/k_sinl.c: Include <float.h>.
(__kernel_sinl): Force underflow exception for arguments with
small absolute value.
* sysdeps/powerpc/fpu/k_sinf.c: Include <float.h>.
(__kernel_sinf): Force underflow exception for arguments with
small absolute value.
* math/auto-libm-test-in: Add more tests of sin and sincos.
* math/auto-libm-test-out: Regenerated.
Diffstat (limited to 'sysdeps/ieee754')
-rw-r--r-- | sysdeps/ieee754/dbl-64/s_sin.c | 10 | ||||
-rw-r--r-- | sysdeps/ieee754/flt-32/k_sinf.c | 11 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-128/k_sincosl.c | 20 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-128/k_sinl.c | 10 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-128ibm/k_sincosl.c | 20 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-128ibm/k_sinl.c | 10 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-96/k_sinl.c | 10 |
7 files changed, 74 insertions, 17 deletions
diff --git a/sysdeps/ieee754/dbl-64/s_sin.c b/sysdeps/ieee754/dbl-64/s_sin.c index ea89ad5cb2..eff120e88d 100644 --- a/sysdeps/ieee754/dbl-64/s_sin.c +++ b/sysdeps/ieee754/dbl-64/s_sin.c @@ -48,6 +48,7 @@ #include <errno.h> +#include <float.h> #include "endian.h" #include "mydefs.h" #include "usncs.h" @@ -295,7 +296,14 @@ __sin (double x) m = u.i[HIGH_HALF]; k = 0x7fffffff & m; /* no sign */ if (k < 0x3e500000) /* if x->0 =>sin(x)=x */ - retval = x; + { + if (fabs (x) < DBL_MIN) + { + double force_underflow = x * x; + math_force_eval (force_underflow); + } + retval = x; + } /*---------------------------- 2^-26 < |x|< 0.25 ----------------------*/ else if (k < 0x3fd00000) { diff --git a/sysdeps/ieee754/flt-32/k_sinf.c b/sysdeps/ieee754/flt-32/k_sinf.c index 0bafd83cf0..0c98a2ae91 100644 --- a/sysdeps/ieee754/flt-32/k_sinf.c +++ b/sysdeps/ieee754/flt-32/k_sinf.c @@ -17,6 +17,7 @@ static char rcsid[] = "$NetBSD: k_sinf.c,v 1.4 1995/05/10 20:46:33 jtc Exp $"; #endif +#include <float.h> #include <math.h> #include <math_private.h> @@ -36,7 +37,15 @@ float __kernel_sinf(float x, float y, int iy) GET_FLOAT_WORD(ix,x); ix &= 0x7fffffff; /* high word of x */ if(ix<0x32000000) /* |x| < 2**-27 */ - {if((int)x==0) return x;} /* generate inexact */ + { + if (fabsf (x) < FLT_MIN) + { + float force_underflow = x * x; + math_force_eval (force_underflow); + } + if ((int) x == 0) + return x; /* generate inexact */ + } z = x*x; v = z*x; r = S2+z*(S3+z*(S4+z*(S5+z*S6))); diff --git a/sysdeps/ieee754/ldbl-128/k_sincosl.c b/sysdeps/ieee754/ldbl-128/k_sincosl.c index 2f66dee6d8..7b5c4b0e81 100644 --- a/sysdeps/ieee754/ldbl-128/k_sincosl.c +++ b/sysdeps/ieee754/ldbl-128/k_sincosl.c @@ -17,6 +17,7 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#include <float.h> #include <math.h> #include <math_private.h> @@ -109,12 +110,19 @@ __kernel_sincosl(long double x, long double y, long double *sinx, long double *c /* Argument is small enough to approximate it by a Chebyshev polynomial of degree 16(17). */ if (tix < 0x3fc60000) /* |x| < 2^-57 */ - if (!((int)x)) /* generate inexact */ - { - *sinx = x; - *cosx = ONE; - return; - } + { + if (fabsl (x) < LDBL_MIN) + { + long double force_underflow = x * x; + math_force_eval (force_underflow); + } + if (!((int)x)) /* generate inexact */ + { + *sinx = x; + *cosx = ONE; + return; + } + } z = x * x; *sinx = x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+ z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8))))))))); diff --git a/sysdeps/ieee754/ldbl-128/k_sinl.c b/sysdeps/ieee754/ldbl-128/k_sinl.c index b15521badf..04d539ff1a 100644 --- a/sysdeps/ieee754/ldbl-128/k_sinl.c +++ b/sysdeps/ieee754/ldbl-128/k_sinl.c @@ -17,6 +17,7 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#include <float.h> #include <math.h> #include <math_private.h> @@ -90,7 +91,14 @@ __kernel_sinl(long double x, long double y, int iy) /* Argument is small enough to approximate it by a Chebyshev polynomial of degree 17. */ if (tix < 0x3fc60000) /* |x| < 2^-57 */ - if (!((int)x)) return x; /* generate inexact */ + { + if (fabsl (x) < LDBL_MIN) + { + long double force_underflow = x * x; + math_force_eval (force_underflow); + } + if (!((int)x)) return x; /* generate inexact */ + } z = x * x; return x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+ z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8))))))))); diff --git a/sysdeps/ieee754/ldbl-128ibm/k_sincosl.c b/sysdeps/ieee754/ldbl-128ibm/k_sincosl.c index f831e3f1f3..0a76e1c7e7 100644 --- a/sysdeps/ieee754/ldbl-128ibm/k_sincosl.c +++ b/sysdeps/ieee754/ldbl-128ibm/k_sincosl.c @@ -17,6 +17,7 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#include <float.h> #include <math.h> #include <math_private.h> @@ -112,12 +113,19 @@ __kernel_sincosl(long double x, long double y, long double *sinx, long double *c /* Argument is small enough to approximate it by a Chebyshev polynomial of degree 16(17). */ if (tix < 0x3c600000) /* |x| < 2^-57 */ - if (!((int)x)) /* generate inexact */ - { - *sinx = x; - *cosx = ONE; - return; - } + { + if (fabsl (x) < LDBL_MIN) + { + long double force_underflow = x * x; + math_force_eval (force_underflow); + } + if (!((int)x)) /* generate inexact */ + { + *sinx = x; + *cosx = ONE; + return; + } + } z = x * x; *sinx = x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+ z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8))))))))); diff --git a/sysdeps/ieee754/ldbl-128ibm/k_sinl.c b/sysdeps/ieee754/ldbl-128ibm/k_sinl.c index d6602fe365..2050cd2b49 100644 --- a/sysdeps/ieee754/ldbl-128ibm/k_sinl.c +++ b/sysdeps/ieee754/ldbl-128ibm/k_sinl.c @@ -17,6 +17,7 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#include <float.h> #include <math.h> #include <math_private.h> @@ -93,7 +94,14 @@ __kernel_sinl(long double x, long double y, int iy) /* Argument is small enough to approximate it by a Chebyshev polynomial of degree 17. */ if (tix < 0x3c600000) /* |x| < 2^-57 */ - if (!((int)x)) return x; /* generate inexact */ + { + if (fabsl (x) < LDBL_MIN) + { + long double force_underflow = x * x; + math_force_eval (force_underflow); + } + if (!((int)x)) return x; /* generate inexact */ + } z = x * x; return x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+ z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8))))))))); diff --git a/sysdeps/ieee754/ldbl-96/k_sinl.c b/sysdeps/ieee754/ldbl-96/k_sinl.c index 179262a735..b7b5ae359d 100644 --- a/sysdeps/ieee754/ldbl-96/k_sinl.c +++ b/sysdeps/ieee754/ldbl-96/k_sinl.c @@ -20,6 +20,7 @@ /* The polynomials have not been optimized for extended-precision and may contain more terms than needed. */ +#include <float.h> #include <math.h> #include <math_private.h> @@ -94,7 +95,14 @@ __kernel_sinl(long double x, long double y, int iy) /* Argument is small enough to approximate it by a Chebyshev polynomial of degree 17. */ if (absx < 0x1p-33L) - if (!((int)x)) return x; /* generate inexact */ + { + if (fabsl (x) < LDBL_MIN) + { + long double force_underflow = x * x; + math_force_eval (force_underflow); + } + if (!((int)x)) return x; /* generate inexact */ + } z = x * x; return x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+ z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8))))))))); |