diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | NEWS | 10 | ||||
-rwxr-xr-x | math/gen-libm-test.pl | 10 | ||||
-rw-r--r-- | math/libm-test.inc | 134 | ||||
-rw-r--r-- | math/w_scalb.c | 30 | ||||
-rw-r--r-- | math/w_scalbf.c | 30 | ||||
-rw-r--r-- | math/w_scalbl.c | 30 |
7 files changed, 175 insertions, 80 deletions
diff --git a/ChangeLog b/ChangeLog index 17d5c09f8b..22122b3323 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2014-03-31 Joseph Myers <joseph@codesourcery.com> + [BZ #6803] + [BZ #6804] + * math/w_scalb.c (__scalb): For non-SVID mode, check result and + set errno as appropriate. + * math/w_scalbf.c (__scalbf): Likewise. + * math/w_scalbl.c (__scalbl): Likewise. + * math/gen-libm-test.pl (parse_args): Handle ERRNO_PLUS_OFLOW, + ERRNO_MINUS_OFLOW, ERRNO_PLUS_UFLOW and ERRNO_MINUS_UFLOW. + * math/libm-test.inc (scalb_test_data): Add errno expectations. + Add more NaN tests. + [BZ #16349] * math/w_atan2.c: Include <errno.h>. (__atan2): Set errno for result underflowing to zero. diff --git a/NEWS b/NEWS index 06d137a79b..1574ab4f0c 100644 --- a/NEWS +++ b/NEWS @@ -9,11 +9,11 @@ Version 2.20 * The following bugs are resolved with this release: - 15347, 15804, 15894, 16002, 16198, 16284, 16348, 16349, 16357, 16362, - 16447, 16532, 16545, 16574, 16599, 16600, 16609, 16610, 16611, 16613, - 16623, 16632, 16634, 16639, 16642, 16648, 16649, 16670, 16674, 16677, - 16680, 16683, 16689, 16695, 16701, 16706, 16707, 16712, 16713, 16714, - 16731, 16743, 16758, 16759, 16760, 16770. + 6804, 15347, 15804, 15894, 16002, 16198, 16284, 16348, 16349, 16357, + 16362, 16447, 16532, 16545, 16574, 16599, 16600, 16609, 16610, 16611, + 16613, 16623, 16632, 16634, 16639, 16642, 16648, 16649, 16670, 16674, + 16677, 16680, 16683, 16689, 16695, 16701, 16706, 16707, 16712, 16713, + 16714, 16731, 16743, 16758, 16759, 16760, 16770. * Running the testsuite no longer terminates as soon as a test fails. Instead, a file tests.sum (xtests.sum from "make xcheck") is generated, diff --git a/math/gen-libm-test.pl b/math/gen-libm-test.pl index 6b3a21df40..5f62872b21 100755 --- a/math/gen-libm-test.pl +++ b/math/gen-libm-test.pl @@ -160,6 +160,8 @@ sub parse_args { my ($ignore_result_any, $ignore_result_all); my ($num_res, @args_res, @start_rm, $rm); my (@plus_oflow, @minus_oflow, @plus_uflow, @minus_uflow); + my (@errno_plus_oflow, @errno_minus_oflow); + my (@errno_plus_uflow, @errno_minus_uflow); ($descr_args, $descr_res) = split /_/,$descr, 2; @@ -258,6 +260,10 @@ sub parse_args { @minus_oflow = qw(minus_infty minus_infty -max_value -max_value); @plus_uflow = qw(plus_zero plus_zero plus_zero min_subnorm_value); @minus_uflow = qw(-min_subnorm_value minus_zero minus_zero minus_zero); + @errno_plus_oflow = qw(0 ERRNO_ERANGE 0 ERRNO_ERANGE); + @errno_minus_oflow = qw(ERRNO_ERANGE ERRNO_ERANGE 0 0); + @errno_plus_uflow = qw(ERRNO_ERANGE ERRNO_ERANGE ERRNO_ERANGE 0); + @errno_minus_uflow = qw(0 ERRNO_ERANGE ERRNO_ERANGE ERRNO_ERANGE); for ($rm = 0; $rm <= 3; $rm++) { $current_arg = $start_rm[$rm]; $ignore_result_any = 0; @@ -322,6 +328,10 @@ sub parse_args { $cline_res =~ s/minus_oflow/$minus_oflow[$rm]/g; $cline_res =~ s/plus_uflow/$plus_uflow[$rm]/g; $cline_res =~ s/minus_uflow/$minus_uflow[$rm]/g; + $cline_res =~ s/ERRNO_PLUS_OFLOW/$errno_plus_oflow[$rm]/g; + $cline_res =~ s/ERRNO_MINUS_OFLOW/$errno_minus_oflow[$rm]/g; + $cline_res =~ s/ERRNO_PLUS_UFLOW/$errno_plus_uflow[$rm]/g; + $cline_res =~ s/ERRNO_MINUS_UFLOW/$errno_minus_uflow[$rm]/g; $cline .= ", { $cline_res }"; } print $file " $cline },\n"; diff --git a/math/libm-test.inc b/math/libm-test.inc index 0eff34a0ca..19194f63e9 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -9087,72 +9087,74 @@ round_test (void) static const struct test_ff_f_data scalb_test_data[] = { - TEST_ff_f (scalb, 2.0, 0.5, qnan_value, INVALID_EXCEPTION), - TEST_ff_f (scalb, 3.0, -2.5, qnan_value, INVALID_EXCEPTION), - - TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), - TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), - - TEST_ff_f (scalb, 1, 0, 1), - TEST_ff_f (scalb, -1, 0, -1), - - TEST_ff_f (scalb, 0, plus_infty, qnan_value, INVALID_EXCEPTION), - TEST_ff_f (scalb, minus_zero, plus_infty, qnan_value, INVALID_EXCEPTION), - - TEST_ff_f (scalb, 0, 2, 0), - TEST_ff_f (scalb, minus_zero, -4, minus_zero), - TEST_ff_f (scalb, 0, 0, 0), - TEST_ff_f (scalb, minus_zero, 0, minus_zero), - TEST_ff_f (scalb, 0, -1, 0), - TEST_ff_f (scalb, minus_zero, -10, minus_zero), - TEST_ff_f (scalb, 0, minus_infty, 0), - TEST_ff_f (scalb, minus_zero, minus_infty, minus_zero), - - TEST_ff_f (scalb, plus_infty, -1, plus_infty), - TEST_ff_f (scalb, minus_infty, -10, minus_infty), - TEST_ff_f (scalb, plus_infty, 0, plus_infty), - TEST_ff_f (scalb, minus_infty, 0, minus_infty), - TEST_ff_f (scalb, plus_infty, 2, plus_infty), - TEST_ff_f (scalb, minus_infty, 100, minus_infty), - - TEST_ff_f (scalb, 0.1L, minus_infty, 0.0), - TEST_ff_f (scalb, -0.1L, minus_infty, minus_zero), - - TEST_ff_f (scalb, 1, plus_infty, plus_infty), - TEST_ff_f (scalb, -1, plus_infty, minus_infty), - TEST_ff_f (scalb, plus_infty, plus_infty, plus_infty), - TEST_ff_f (scalb, minus_infty, plus_infty, minus_infty), - - TEST_ff_f (scalb, plus_infty, minus_infty, qnan_value, INVALID_EXCEPTION), - TEST_ff_f (scalb, minus_infty, minus_infty, qnan_value, INVALID_EXCEPTION), - - TEST_ff_f (scalb, qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION), - TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), - TEST_ff_f (scalb, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION), - TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), - TEST_ff_f (scalb, qnan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION), - TEST_ff_f (scalb, plus_infty, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), - TEST_ff_f (scalb, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION), - - TEST_ff_f (scalb, max_value, max_value, plus_oflow, OVERFLOW_EXCEPTION), - TEST_ff_f (scalb, max_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION), - TEST_ff_f (scalb, 1, max_value, plus_oflow, OVERFLOW_EXCEPTION), - TEST_ff_f (scalb, 1, -max_value, plus_uflow, UNDERFLOW_EXCEPTION), - TEST_ff_f (scalb, min_value, max_value, plus_oflow, OVERFLOW_EXCEPTION), - TEST_ff_f (scalb, min_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION), - TEST_ff_f (scalb, min_subnorm_value, max_value, plus_oflow, OVERFLOW_EXCEPTION), - TEST_ff_f (scalb, min_subnorm_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION), - TEST_ff_f (scalb, -max_value, max_value, minus_oflow, OVERFLOW_EXCEPTION), - TEST_ff_f (scalb, -max_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION), - TEST_ff_f (scalb, -1, max_value, minus_oflow, OVERFLOW_EXCEPTION), - TEST_ff_f (scalb, -1, -max_value, minus_uflow, UNDERFLOW_EXCEPTION), - TEST_ff_f (scalb, -min_value, max_value, minus_oflow, OVERFLOW_EXCEPTION), - TEST_ff_f (scalb, -min_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION), - TEST_ff_f (scalb, -min_subnorm_value, max_value, minus_oflow, OVERFLOW_EXCEPTION), - TEST_ff_f (scalb, -min_subnorm_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION), - - TEST_ff_f (scalb, 0.8L, 4, 12.8L), - TEST_ff_f (scalb, -0.854375L, 5, -27.34L), + TEST_ff_f (scalb, 2.0, 0.5, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (scalb, 3.0, -2.5, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + + TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (scalb, 1, 0, 1, ERRNO_UNCHANGED), + TEST_ff_f (scalb, -1, 0, -1, ERRNO_UNCHANGED), + + TEST_ff_f (scalb, 0, plus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (scalb, minus_zero, plus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + + TEST_ff_f (scalb, 0, 2, 0, ERRNO_UNCHANGED), + TEST_ff_f (scalb, minus_zero, -4, minus_zero, ERRNO_UNCHANGED), + TEST_ff_f (scalb, 0, 0, 0, ERRNO_UNCHANGED), + TEST_ff_f (scalb, minus_zero, 0, minus_zero, ERRNO_UNCHANGED), + TEST_ff_f (scalb, 0, -1, 0, ERRNO_UNCHANGED), + TEST_ff_f (scalb, minus_zero, -10, minus_zero, ERRNO_UNCHANGED), + TEST_ff_f (scalb, 0, minus_infty, 0, ERRNO_UNCHANGED), + TEST_ff_f (scalb, minus_zero, minus_infty, minus_zero, ERRNO_UNCHANGED), + + TEST_ff_f (scalb, plus_infty, -1, plus_infty, ERRNO_UNCHANGED), + TEST_ff_f (scalb, minus_infty, -10, minus_infty, ERRNO_UNCHANGED), + TEST_ff_f (scalb, plus_infty, 0, plus_infty, ERRNO_UNCHANGED), + TEST_ff_f (scalb, minus_infty, 0, minus_infty, ERRNO_UNCHANGED), + TEST_ff_f (scalb, plus_infty, 2, plus_infty, ERRNO_UNCHANGED), + TEST_ff_f (scalb, minus_infty, 100, minus_infty, ERRNO_UNCHANGED), + + TEST_ff_f (scalb, 0.1L, minus_infty, 0.0, ERRNO_UNCHANGED), + TEST_ff_f (scalb, -0.1L, minus_infty, minus_zero, ERRNO_UNCHANGED), + + TEST_ff_f (scalb, 1, plus_infty, plus_infty, ERRNO_UNCHANGED), + TEST_ff_f (scalb, -1, plus_infty, minus_infty, ERRNO_UNCHANGED), + TEST_ff_f (scalb, plus_infty, plus_infty, plus_infty, ERRNO_UNCHANGED), + TEST_ff_f (scalb, minus_infty, plus_infty, minus_infty, ERRNO_UNCHANGED), + + TEST_ff_f (scalb, plus_infty, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (scalb, minus_infty, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM), + + TEST_ff_f (scalb, qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, qnan_value, 0.5, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, 0.5, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, qnan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, plus_infty, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (scalb, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (scalb, max_value, max_value, plus_oflow, OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW), + TEST_ff_f (scalb, max_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW), + TEST_ff_f (scalb, 1, max_value, plus_oflow, OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW), + TEST_ff_f (scalb, 1, -max_value, plus_uflow, UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW), + TEST_ff_f (scalb, min_value, max_value, plus_oflow, OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW), + TEST_ff_f (scalb, min_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW), + TEST_ff_f (scalb, min_subnorm_value, max_value, plus_oflow, OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW), + TEST_ff_f (scalb, min_subnorm_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW), + TEST_ff_f (scalb, -max_value, max_value, minus_oflow, OVERFLOW_EXCEPTION|ERRNO_MINUS_OFLOW), + TEST_ff_f (scalb, -max_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION|ERRNO_MINUS_UFLOW), + TEST_ff_f (scalb, -1, max_value, minus_oflow, OVERFLOW_EXCEPTION|ERRNO_MINUS_OFLOW), + TEST_ff_f (scalb, -1, -max_value, minus_uflow, UNDERFLOW_EXCEPTION|ERRNO_MINUS_UFLOW), + TEST_ff_f (scalb, -min_value, max_value, minus_oflow, OVERFLOW_EXCEPTION|ERRNO_MINUS_OFLOW), + TEST_ff_f (scalb, -min_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION|ERRNO_MINUS_UFLOW), + TEST_ff_f (scalb, -min_subnorm_value, max_value, minus_oflow, OVERFLOW_EXCEPTION|ERRNO_MINUS_OFLOW), + TEST_ff_f (scalb, -min_subnorm_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION|ERRNO_MINUS_UFLOW), + + TEST_ff_f (scalb, 0.8L, 4, 12.8L, ERRNO_UNCHANGED), + TEST_ff_f (scalb, -0.854375L, 5, -27.34L, ERRNO_UNCHANGED), }; static void diff --git a/math/w_scalb.c b/math/w_scalb.c index dbfefaf9d5..0f1e2df8ef 100644 --- a/math/w_scalb.c +++ b/math/w_scalb.c @@ -45,9 +45,33 @@ sysv_scalb (double x, double fn) double __scalb (double x, double fn) { - return (__builtin_expect (_LIB_VERSION == _SVID_, 0) - ? sysv_scalb (x, fn) - : __ieee754_scalb (x, fn)); + if (__glibc_unlikely (_LIB_VERSION == _SVID_)) + return sysv_scalb (x, fn); + else + { + double z = __ieee754_scalb (x, fn); + + if (__glibc_unlikely (!__finite (z) || z == 0.0)) + { + if (__isnan (z)) + { + if (!__isnan (x) && !__isnan (fn)) + __set_errno (EDOM); + } + else if (__isinf_ns (z)) + { + if (!__isinf_ns (x) && !__isinf_ns (fn)) + __set_errno (ERANGE); + } + else + { + /* z == 0. */ + if (x != 0.0 && !__isinf_ns (fn)) + __set_errno (ERANGE); + } + } + return z; + } } weak_alias (__scalb, scalb) #ifdef NO_LONG_DOUBLE diff --git a/math/w_scalbf.c b/math/w_scalbf.c index 244fd1e91b..7ab0b8a4ac 100644 --- a/math/w_scalbf.c +++ b/math/w_scalbf.c @@ -45,8 +45,32 @@ sysv_scalbf (float x, float fn) float __scalbf (float x, float fn) { - return (__builtin_expect (_LIB_VERSION == _SVID_, 0) - ? sysv_scalbf (x, fn) - : __ieee754_scalbf (x, fn)); + if (__glibc_unlikely (_LIB_VERSION == _SVID_)) + return sysv_scalbf (x, fn); + else + { + float z = __ieee754_scalbf (x, fn); + + if (__glibc_unlikely (!__finitef (z) || z == 0.0f)) + { + if (__isnanf (z)) + { + if (!__isnanf (x) && !__isnanf (fn)) + __set_errno (EDOM); + } + else if (__isinf_nsf (z)) + { + if (!__isinf_nsf (x) && !__isinf_nsf (fn)) + __set_errno (ERANGE); + } + else + { + /* z == 0. */ + if (x != 0.0f && !__isinf_nsf (fn)) + __set_errno (ERANGE); + } + } + return z; + } } weak_alias (__scalbf, scalbf) diff --git a/math/w_scalbl.c b/math/w_scalbl.c index cffaa67cc7..40cc68e865 100644 --- a/math/w_scalbl.c +++ b/math/w_scalbl.c @@ -45,8 +45,32 @@ sysv_scalbl (long double x, long double fn) long double __scalbl (long double x, long double fn) { - return (__builtin_expect (_LIB_VERSION == _SVID_, 0) - ? sysv_scalbl (x, fn) - : __ieee754_scalbl (x, fn)); + if (__glibc_unlikely (_LIB_VERSION == _SVID_)) + return sysv_scalbl (x, fn); + else + { + long double z = __ieee754_scalbl (x, fn); + + if (__glibc_unlikely (!__finitel (z) || z == 0.0L)) + { + if (__isnanl (z)) + { + if (!__isnanl (x) && !__isnanl (fn)) + __set_errno (EDOM); + } + else if (__isinf_nsl (z)) + { + if (!__isinf_nsl (x) && !__isinf_nsl (fn)) + __set_errno (ERANGE); + } + else + { + /* z == 0. */ + if (x != 0.0L && !__isinf_nsl (fn)) + __set_errno (ERANGE); + } + } + return z; + } } weak_alias (__scalbl, scalbl) |