From bb38759d6dc78b1818f5d23129a362d6f5aba267 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 17 May 2013 19:04:08 +0000 Subject: [PATCH] Fix remainder exceptions and directed-rounding results (bugs 15480, 15485). --- ChangeLog | 17 +++ NEWS | 2 +- math/libm-test.inc | 169 +++++++++++++++++++++++++-- sysdeps/ieee754/dbl-64/e_remainder.c | 1 + 4 files changed, 181 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index cec25f7a15..fe2a644718 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 2013-05-17 Joseph Myers + [BZ #15480] + [BZ #15485] + * sysdeps/ieee754/dbl-64/e_remainder.c (__ieee754_remainder): For + main case of finite arguments, set rounding mode to FE_TONEAREST + and discard exceptions. + * math/libm-test.inc (remainder_test_data): Disallow "inexact" + exceptions. + (remainder_tonearest_test_data): New variable. + (remainder_test_tonearest): New function. + (remainder_towardzero_test_data): New variable. + (remainder_test_towardzero): New function. + (remainder_downward_test_data): New variable. + (remainder_test_downward): New function. + (remainder_upward_test_data): New variable. + (remainder_test_upward): New function. + (main): Call the new test functions. + * math/libm-test.inc (struct test_f_f1_data): Remove field extra_init. (struct test_fF_f1_data): Likewise. diff --git a/NEWS b/NEWS index 57c7ee0a8f..7fc3e397f6 100644 --- a/NEWS +++ b/NEWS @@ -17,7 +17,7 @@ Version 2.18 15086, 15160, 15214, 15221, 15232, 15234, 15283, 15285, 15287, 15304, 15305, 15307, 15309, 15327, 15330, 15335, 15336, 15337, 15342, 15346, 15359, 15361, 15366, 15380, 15394, 15395, 15405, 15406, 15409, 15416, - 15418, 15419, 15423, 15424, 15426, 15429, 15442, 15448. + 15418, 15419, 15423, 15424, 15426, 15429, 15442, 15448, 15480, 15485. * CVE-2013-0242 Buffer overrun in regexp matcher has been fixed (Bugzilla #15078). diff --git a/math/libm-test.inc b/math/libm-test.inc index 360112c1e3..41344bc865 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -12276,13 +12276,12 @@ static const struct test_ff_f_data remainder_test_data[] = TEST_ff_f (remainder, 7.0, plus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (remainder, 7.0, minus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - /* Bug 15480: spurious "inexact" exception may occur. */ - TEST_ff_f (remainder, 1.625, 1.0, -0.375), - TEST_ff_f (remainder, -1.625, 1.0, 0.375), - TEST_ff_f (remainder, 1.625, -1.0, -0.375), - TEST_ff_f (remainder, -1.625, -1.0, 0.375), - TEST_ff_f (remainder, 5.0, 2.0, 1.0), - TEST_ff_f (remainder, 3.0, 2.0, -1.0), + TEST_ff_f (remainder, 1.625, 1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, 1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 1.625, -1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, -1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 5.0, 2.0, 1.0, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 3.0, 2.0, -1.0, NO_INEXACT_EXCEPTION), END_DATA (remainder) }; @@ -12294,6 +12293,158 @@ remainder_test (void) END (remainder); } + +static const struct test_ff_f_data remainder_tonearest_test_data[] = + { + START_DATA (remainder_tonearest), + TEST_ff_f (remainder, 1, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, 1, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (remainder, 7.0, plus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, 7.0, minus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (remainder, 1.625, 1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, 1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 1.625, -1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, -1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 5.0, 2.0, 1.0, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 3.0, 2.0, -1.0, NO_INEXACT_EXCEPTION), + END_DATA (remainder_tonearest) + }; + +static void +remainder_test_tonearest (void) +{ + START (remainder_tonearest); + RUN_TEST_LOOP_ff_f (remainder, remainder_tonearest_test_data, FE_TONEAREST); + END (remainder_tonearest); +} + + +static const struct test_ff_f_data remainder_towardzero_test_data[] = + { + START_DATA (remainder_towardzero), + TEST_ff_f (remainder, 1, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, 1, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (remainder, 7.0, plus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, 7.0, minus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (remainder, 1.625, 1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, 1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 1.625, -1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, -1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 5.0, 2.0, 1.0, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 3.0, 2.0, -1.0, NO_INEXACT_EXCEPTION), + END_DATA (remainder_towardzero) + }; + +static void +remainder_test_towardzero (void) +{ + START (remainder_towardzero); + RUN_TEST_LOOP_ff_f (remainder, remainder_towardzero_test_data, FE_TOWARDZERO); + END (remainder_towardzero); +} + + +static const struct test_ff_f_data remainder_downward_test_data[] = + { + START_DATA (remainder_downward), + TEST_ff_f (remainder, 1, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, 1, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (remainder, 7.0, plus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, 7.0, minus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (remainder, 1.625, 1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, 1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 1.625, -1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, -1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 5.0, 2.0, 1.0, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 3.0, 2.0, -1.0, NO_INEXACT_EXCEPTION), + END_DATA (remainder_downward) + }; + +static void +remainder_test_downward (void) +{ + START (remainder_downward); + RUN_TEST_LOOP_ff_f (remainder, remainder_downward_test_data, FE_DOWNWARD); + END (remainder_downward); +} + + +static const struct test_ff_f_data remainder_upward_test_data[] = + { + START_DATA (remainder_upward), + TEST_ff_f (remainder, 1, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, 1, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, plus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, minus_infty, 2, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM), + TEST_ff_f (remainder, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (remainder, 7.0, plus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (remainder, 7.0, minus_infty, 7.0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + + TEST_ff_f (remainder, 1.625, 1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, 1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 1.625, -1.0, -0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, -1.625, -1.0, 0.375, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 5.0, 2.0, 1.0, NO_INEXACT_EXCEPTION), + TEST_ff_f (remainder, 3.0, 2.0, -1.0, NO_INEXACT_EXCEPTION), + END_DATA (remainder_upward) + }; + +static void +remainder_test_upward (void) +{ + START (remainder_upward); + RUN_TEST_LOOP_ff_f (remainder, remainder_upward_test_data, FE_UPWARD); + END (remainder_upward); +} + static const struct test_ffI_f1_data remquo_test_data[] = { START_DATA (remquo), @@ -14766,6 +14917,10 @@ main (int argc, char **argv) /* Remainder functions: */ fmod_test (); remainder_test (); + remainder_test_tonearest (); + remainder_test_towardzero (); + remainder_test_downward (); + remainder_test_upward (); remquo_test (); /* Manipulation functions: */ diff --git a/sysdeps/ieee754/dbl-64/e_remainder.c b/sysdeps/ieee754/dbl-64/e_remainder.c index 39ca0c2d0e..2d20bb1dfe 100644 --- a/sysdeps/ieee754/dbl-64/e_remainder.c +++ b/sysdeps/ieee754/dbl-64/e_remainder.c @@ -51,6 +51,7 @@ double __ieee754_remainder(double x, double y) ky=t.i[HIGH_HALF]; /*------ |x| < 2^1023 and 2^-970 < |y| < 2^1024 ------------------*/ if (kx<0x7fe00000 && ky<0x7ff00000 && ky>=0x03500000) { + SET_RESTORE_ROUND_NOEX (FE_TONEAREST); if (kx+0x00100000