This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Bugs 6807 and 15901 report problems with the handling of errors from y0 / y1 / yn: negative arguments should, like other domain errors, produce a NaN result, while 0 is a pole error, should produce an ERANGE errno value with divide-by-zero exception and should produce an infinity whose sign depends on the value of n in the case of yn. This patch fixes those bugs in the way most consistent with the surrounding code. The wrapper functions are changed to raise FE_DIVBYZERO explicitly, just as they raise FE_INVALID explicitly (except for the ynl wrapper, which does things differently from all the other wrappers for some reason) - maybe they should all change to call the __ieee754_* functions first, like the __ynl wrapper does, but that's a separate issue. __kernel_standard is adjusted to produce the appropriate errno values and returns - errno values and exception structure are left unchanged in the deprecated matherr case as that seems safest for this deprecated interface. The underlying ynl implementations are changed to produce the appropriate return and exceptions for zero arguments, as required by the nature of that wrapper. (There may well be such bugs in other underlying implementations that would only show up with -lieee - clearly we do need tests of -ffinite-math-only and -lieee to test those function variants better, although I also think -lieee, which uses _LIB_VERSION, should be replaced by __*_noerrno function variants enabled with -fno-math-errno.) Tested x86_64 and x86 and ulps updated accordingly (for the new tests of yn with negative n and finite arguments; such tests were previously lacking). 2013-12-04 Joseph Myers <joseph@codesourcery.com> [BZ #6807] [BZ #15901] * math/w_j0.c (y0): Raise FE_DIVBYZERO on zero argument. * math/w_j0f.c (y0f): Likewise. * math/w_j0l.c (__y0l): Likewise. * math/w_j1.c (y1): Likewise. * math/w_j1f.c (y1f): Likewise. * math/w_j1l.c (__y1l): Likewise * math/w_jn.c (yn): Likewise. * math/w_jnf.c (ynf): Likewise. * sysdeps/ieee754/k_standard.c (__kernel_standard): Use ERANGE for Bessel function pole errors in _POSIX_ mode. Use NAN as return value for Bessel function domain errors outside _SVID_ mode. Adjust sign of return value for yn (negative integer, 0). * sysdeps/ieee754/ldbl-128/e_jnl.c (__ieee754_ynl): Use division by zero in return for negative x and set sign appropriately for negative n. * sysdeps/ieee754/ldbl-128ibm/e_jnl.c (__ieee754_ynl): Likewise. * sysdeps/ieee754/ldbl-96/e_jnl.c (__ieee754_ynl): Likewise. * math/libm-test.inc (y0_test_data): Add more tests and adjust expectations in error cases. (y1_test_data): Likewise. (yn_test_data): Likewise. * sysdeps/i386/fpu/libm-test-ulps: Update. * sysdeps/x86_64/fpu/libm-test-ulps: Likewise. diff --git a/math/libm-test.inc b/math/libm-test.inc index 2e3e684..a4b2d51 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -14278,9 +14278,11 @@ trunc_test (void) static const struct test_f_f_data y0_test_data[] = { /* y0 is the Bessel function of the second kind of order 0 */ - TEST_f_f (y0, -1.0, minus_infty, INVALID_EXCEPTION|ERRNO_EDOM), - TEST_f_f (y0, -max_value, minus_infty, INVALID_EXCEPTION|ERRNO_EDOM), - TEST_f_f (y0, 0.0, minus_infty), + TEST_f_f (y0, -1.0, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_f_f (y0, -max_value, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_f_f (y0, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_f_f (y0, 0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_f_f (y0, -0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), TEST_f_f (y0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), TEST_f_f (y0, plus_infty, 0), @@ -14329,9 +14331,11 @@ y0_test (void) static const struct test_f_f_data y1_test_data[] = { /* y1 is the Bessel function of the second kind of order 1 */ - TEST_f_f (y1, -1.0, minus_infty, INVALID_EXCEPTION|ERRNO_EDOM), - TEST_f_f (y1, -max_value, minus_infty, INVALID_EXCEPTION|ERRNO_EDOM), - TEST_f_f (y1, 0.0, minus_infty), + TEST_f_f (y1, -1.0, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_f_f (y1, -max_value, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_f_f (y1, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_f_f (y1, 0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_f_f (y1, -0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), TEST_f_f (y1, plus_infty, 0), TEST_f_f (y1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), @@ -14381,9 +14385,11 @@ static const struct test_if_f_data yn_test_data[] = { /* yn is the Bessel function of the second kind of order n */ /* yn (0, x) == y0 (x) */ - TEST_if_f (yn, 0, -1.0, minus_infty, INVALID_EXCEPTION|ERRNO_EDOM), - TEST_if_f (yn, 0, -max_value, minus_infty, INVALID_EXCEPTION|ERRNO_EDOM), - TEST_if_f (yn, 0, 0.0, minus_infty), + TEST_if_f (yn, 0, -1.0, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 0, -max_value, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 0, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 0, 0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, 0, -0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), TEST_if_f (yn, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), TEST_if_f (yn, 0, plus_infty, 0), @@ -14396,8 +14402,11 @@ static const struct test_if_f_data yn_test_data[] = TEST_if_f (yn, 0, 10.0, 0.0556711672835993914244598774101900481L), /* yn (1, x) == y1 (x) */ - TEST_if_f (yn, 1, -1.0, minus_infty, INVALID_EXCEPTION|ERRNO_EDOM), - TEST_if_f (yn, 1, 0.0, minus_infty), + TEST_if_f (yn, 1, -1.0, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 1, -max_value, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 1, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 1, 0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, 1, -0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), TEST_if_f (yn, 1, plus_infty, 0), TEST_if_f (yn, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), @@ -14409,7 +14418,40 @@ static const struct test_if_f_data yn_test_data[] = TEST_if_f (yn, 1, 8.0, -0.158060461731247494255555266187483550L), TEST_if_f (yn, 1, 10.0, 0.249015424206953883923283474663222803L), + /* yn (-1, x) == -y1 (x). */ + TEST_if_f (yn, -1, -1.0, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, -1, -max_value, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, -1, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, -1, 0.0, plus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, -1, -0.0, plus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, -1, plus_infty, minus_zero), + TEST_if_f (yn, -1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), + TEST_if_f (yn, -1, 1.0, 0.781212821300288716547150000047964821L), + + /* yn (2, x). */ + TEST_if_f (yn, 2, -1.0, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 2, -max_value, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 2, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 2, 0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, 2, -0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, 2, plus_infty, 0), + TEST_if_f (yn, 2, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), + + /* yn (-2, x) == yn (2, x). */ + TEST_if_f (yn, -2, -1.0, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, -2, -max_value, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, -2, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, -2, 0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, -2, -0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, -2, plus_infty, 0), + TEST_if_f (yn, -2, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), + /* yn (3, x) */ + TEST_if_f (yn, 3, -1.0, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 3, -max_value, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 3, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_if_f (yn, 3, 0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), + TEST_if_f (yn, 3, -0.0, minus_infty, DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE), TEST_if_f (yn, 3, plus_infty, 0), TEST_if_f (yn, 3, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), @@ -14429,6 +14471,8 @@ static const struct test_if_f_data yn_test_data[] = TEST_if_f (yn, 10, 2.0, -129184.542208039282635913145923304214L), TEST_if_f (yn, 10, 10.0, -0.359814152183402722051986577343560609L), + TEST_if_f (yn, -10, 1.0, -121618014.278689189288130426667971145L), + /* Check whether yn returns correct value for LDBL_MIN, DBL_MIN, and FLT_MIN. See Bug 14173. */ TEST_if_f (yn, 10, min_value, minus_infty, OVERFLOW_EXCEPTION|ERRNO_ERANGE), diff --git a/math/w_j0.c b/math/w_j0.c index 53671c3..0849abb 100644 --- a/math/w_j0.c +++ b/math/w_j0.c @@ -51,8 +51,11 @@ y0 (double x) return __kernel_standard (x, x, 9); } else if (x == 0.0) - /* d = -one/(x-x) */ - return __kernel_standard (x, x, 8); + { + /* d = -one/(x-x) */ + feraiseexcept (FE_DIVBYZERO); + return __kernel_standard (x, x, 8); + } else if (_LIB_VERSION != _POSIX_) /* y0(x>X_TLOSS) */ return __kernel_standard (x, x, 35); diff --git a/math/w_j0f.c b/math/w_j0f.c index c9a6c53..ef309d2 100644 --- a/math/w_j0f.c +++ b/math/w_j0f.c @@ -49,8 +49,11 @@ y0f (float x) return __kernel_standard_f (x, x, 109); } else if (x == 0.0f) - /* d = -one/(x-x) */ - return __kernel_standard_f (x, x, 108); + { + /* d = -one/(x-x) */ + feraiseexcept (FE_DIVBYZERO); + return __kernel_standard_f (x, x, 108); + } else if (_LIB_VERSION != _POSIX_) /* y0(x>X_TLOSS) */ return __kernel_standard_f (x, x, 135); diff --git a/math/w_j0l.c b/math/w_j0l.c index 717253c..01cd91c 100644 --- a/math/w_j0l.c +++ b/math/w_j0l.c @@ -49,8 +49,11 @@ __y0l (long double x) return __kernel_standard_l (x, x, 209); } else if (x == 0.0L) - /* d = -one/(x-x) */ - return __kernel_standard_l (x, x, 208); + { + /* d = -one/(x-x) */ + feraiseexcept (FE_DIVBYZERO); + return __kernel_standard_l (x, x, 208); + } else if (_LIB_VERSION != _POSIX_) /* y0(x>X_TLOSS) */ return __kernel_standard_l (x, x, 235); diff --git a/math/w_j1.c b/math/w_j1.c index 743c940..a9fb7ae 100644 --- a/math/w_j1.c +++ b/math/w_j1.c @@ -51,8 +51,11 @@ y1 (double x) return __kernel_standard (x, x, 11); } else if (x == 0.0) - /* d = -one/(x-x) */ - return __kernel_standard (x, x, 10); + { + /* d = -one/(x-x) */ + feraiseexcept (FE_DIVBYZERO); + return __kernel_standard (x, x, 10); + } else if (_LIB_VERSION != _POSIX_) /* y1(x>X_TLOSS) */ return __kernel_standard (x, x, 37); diff --git a/math/w_j1f.c b/math/w_j1f.c index bf7deb0..f70913d 100644 --- a/math/w_j1f.c +++ b/math/w_j1f.c @@ -49,8 +49,11 @@ y1f (float x) return __kernel_standard_f (x, x, 111); } else if (x == 0.0f) - /* d = -one/(x-x) */ - return __kernel_standard_f (x, x, 110); + { + /* d = -one/(x-x) */ + feraiseexcept (FE_DIVBYZERO); + return __kernel_standard_f (x, x, 110); + } else if (_LIB_VERSION != _POSIX_) /* y1(x>X_TLOSS) */ return __kernel_standard_f (x, x, 137); diff --git a/math/w_j1l.c b/math/w_j1l.c index c4f8111..e4242ec 100644 --- a/math/w_j1l.c +++ b/math/w_j1l.c @@ -49,8 +49,11 @@ __y1l (long double x) return __kernel_standard_l (x, x, 211); } else if (x == 0.0L) - /* d = -one/(x-x) */ - return __kernel_standard_l (x, x, 210); + { + /* d = -one/(x-x) */ + feraiseexcept (FE_DIVBYZERO); + return __kernel_standard_l (x, x, 210); + } else if (_LIB_VERSION != _POSIX_) /* y1(x>X_TLOSS) */ return __kernel_standard_l (x, x, 237); diff --git a/math/w_jn.c b/math/w_jn.c index e2e69b4..e917983 100644 --- a/math/w_jn.c +++ b/math/w_jn.c @@ -51,8 +51,11 @@ yn (int n, double x) return __kernel_standard (n, x, 13); } else if (x == 0.0) - /* d = -one/(x-x) */ - return __kernel_standard (n, x, 12); + { + /* d = -one/(x-x) */ + feraiseexcept (FE_DIVBYZERO); + return __kernel_standard (n, x, 12); + } else if (_LIB_VERSION != _POSIX_) /* yn(n,x>X_TLOSS) */ return __kernel_standard (n, x, 39); diff --git a/math/w_jnf.c b/math/w_jnf.c index c9114e7..cb1aab8 100644 --- a/math/w_jnf.c +++ b/math/w_jnf.c @@ -49,8 +49,11 @@ ynf (int n, float x) return __kernel_standard_f (n, x, 113); } else if (x == 0.0) - /* d = -one/(x-x) */ - return __kernel_standard_f (n, x, 112); + { + /* d = -one/(x-x) */ + feraiseexcept (FE_DIVBYZERO); + return __kernel_standard_f (n, x, 112); + } else if (_LIB_VERSION != _POSIX_) /* yn(n,x>X_TLOSS) */ return __kernel_standard_f (n, x, 139); diff --git a/sysdeps/i386/fpu/libm-test-ulps b/sysdeps/i386/fpu/libm-test-ulps index 4ed02a2..cf7c5e8 100644 --- a/sysdeps/i386/fpu/libm-test-ulps +++ b/sysdeps/i386/fpu/libm-test-ulps @@ -7563,6 +7563,9 @@ float: 2 ifloat: 2 # yn +Test "yn (-10, 1.0)": +float: 2 +ifloat: 2 Test "yn (0, 0.125)": ildouble: 1 ldouble: 1 diff --git a/sysdeps/ieee754/k_standard.c b/sysdeps/ieee754/k_standard.c index 4a0d82d..5399c66 100644 --- a/sysdeps/ieee754/k_standard.c +++ b/sysdeps/ieee754/k_standard.c @@ -248,7 +248,7 @@ __kernel_standard(double x, double y, int type) else exc.retval = -HUGE_VAL; if (_LIB_VERSION == _POSIX_) - __set_errno (EDOM); + __set_errno (ERANGE); else if (!matherr(&exc)) { if (_LIB_VERSION == _SVID_) { (void) WRITE2("y0: DOMAIN error\n", 17); @@ -265,7 +265,7 @@ __kernel_standard(double x, double y, int type) if (_LIB_VERSION == _SVID_) exc.retval = -HUGE; else - exc.retval = -HUGE_VAL; + exc.retval = NAN; if (_LIB_VERSION == _POSIX_) __set_errno (EDOM); else if (!matherr(&exc)) { @@ -286,7 +286,7 @@ __kernel_standard(double x, double y, int type) else exc.retval = -HUGE_VAL; if (_LIB_VERSION == _POSIX_) - __set_errno (EDOM); + __set_errno (ERANGE); else if (!matherr(&exc)) { if (_LIB_VERSION == _SVID_) { (void) WRITE2("y1: DOMAIN error\n", 17); @@ -303,7 +303,7 @@ __kernel_standard(double x, double y, int type) if (_LIB_VERSION == _SVID_) exc.retval = -HUGE; else - exc.retval = -HUGE_VAL; + exc.retval = NAN; if (_LIB_VERSION == _POSIX_) __set_errno (EDOM); else if (!matherr(&exc)) { @@ -322,9 +322,11 @@ __kernel_standard(double x, double y, int type) if (_LIB_VERSION == _SVID_) exc.retval = -HUGE; else - exc.retval = -HUGE_VAL; + exc.retval = ((x < 0 && ((int) x & 1) != 0) + ? HUGE_VAL + : -HUGE_VAL); if (_LIB_VERSION == _POSIX_) - __set_errno (EDOM); + __set_errno (ERANGE); else if (!matherr(&exc)) { if (_LIB_VERSION == _SVID_) { (void) WRITE2("yn: DOMAIN error\n", 17); @@ -341,7 +343,7 @@ __kernel_standard(double x, double y, int type) if (_LIB_VERSION == _SVID_) exc.retval = -HUGE; else - exc.retval = -HUGE_VAL; + exc.retval = NAN; if (_LIB_VERSION == _POSIX_) __set_errno (EDOM); else if (!matherr(&exc)) { diff --git a/sysdeps/ieee754/ldbl-128/e_jnl.c b/sysdeps/ieee754/ldbl-128/e_jnl.c index 70d5672..c2a4923 100644 --- a/sysdeps/ieee754/ldbl-128/e_jnl.c +++ b/sysdeps/ieee754/ldbl-128/e_jnl.c @@ -316,7 +316,7 @@ __ieee754_ynl (int n, long double x) if (x <= 0.0L) { if (x == 0.0L) - return -HUGE_VALL + x; + return ((n < 0 && (n & 1) != 0) ? 1.0L : -1.0L) / 0.0L; if (se & 0x80000000) return zero / (zero * x); } diff --git a/sysdeps/ieee754/ldbl-128ibm/e_jnl.c b/sysdeps/ieee754/ldbl-128ibm/e_jnl.c index 817977d..6761a0d 100644 --- a/sysdeps/ieee754/ldbl-128ibm/e_jnl.c +++ b/sysdeps/ieee754/ldbl-128ibm/e_jnl.c @@ -316,7 +316,7 @@ __ieee754_ynl (int n, long double x) if (x <= 0.0L) { if (x == 0.0L) - return -HUGE_VALL + x; + return ((n < 0 && (n & 1) != 0) ? 1.0L : -1.0L) / 0.0L; if (se & 0x80000000) return zero / (zero * x); } diff --git a/sysdeps/ieee754/ldbl-96/e_jnl.c b/sysdeps/ieee754/ldbl-96/e_jnl.c index 58a9107..fa8e27e 100644 --- a/sysdeps/ieee754/ldbl-96/e_jnl.c +++ b/sysdeps/ieee754/ldbl-96/e_jnl.c @@ -302,7 +302,8 @@ __ieee754_ynl (int n, long double x) if (__builtin_expect ((ix == 0x7fff) && ((i0 & 0x7fffffff) != 0), 0)) return x + x; if (__builtin_expect ((ix | i0 | i1) == 0, 0)) - return -HUGE_VALL + x; /* -inf and overflow exception. */ + /* -inf or inf and divide-by-zero exception. */ + return ((n < 0 && (n & 1) != 0) ? 1.0L : -1.0L) / 0.0L; if (__builtin_expect (se & 0x8000, 0)) return zero / (zero * x); sign = 1; diff --git a/sysdeps/x86_64/fpu/libm-test-ulps b/sysdeps/x86_64/fpu/libm-test-ulps index e785148..b3b40ef 100644 --- a/sysdeps/x86_64/fpu/libm-test-ulps +++ b/sysdeps/x86_64/fpu/libm-test-ulps @@ -8615,6 +8615,11 @@ idouble: 1 ifloat: 2 # yn +Test "yn (-10, 1.0)": +double: 1 +float: 2 +idouble: 1 +ifloat: 2 Test "yn (0, 0.125)": ildouble: 1 ldouble: 1 -- Joseph S. Myers joseph@codesourcery.com
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |