diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2015-07-17 00:26:03 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2015-07-17 00:26:03 +0000 |
commit | 210e6b5e4aa5bd17a6bf7555a7427a61a34c5c0b (patch) | |
tree | 1d521b8f4b4be2380cc50c2f0a4615bd8ab465a9 | |
parent | efa390ebecd6cbaa0315fe4062899acfe52a9314 (diff) | |
download | mpfr-210e6b5e4aa5bd17a6bf7555a7427a61a34c5c0b.tar.gz |
[src/{div_2si.c,div_2ui.c,mul_2si.c}] Fixed some underflow cases in
rounding to nearest when the exact result is -2^(emin-2), i.e. the
middle of 0 and the minimum negative number in absolute value (the
correction in r5517 was incorrect/incomplete).
[tests/tmul_2exp.c] Extended the underflow() test to negative numbers,
triggering the bug fixed here.
(merged changesets r9614,9616 from the trunk)
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/branches/3.1@9620 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r-- | src/div_2si.c | 3 | ||||
-rw-r--r-- | src/div_2ui.c | 4 | ||||
-rw-r--r-- | src/mul_2si.c | 3 | ||||
-rw-r--r-- | tests/tmul_2exp.c | 121 |
4 files changed, 70 insertions, 61 deletions
diff --git a/src/div_2si.c b/src/div_2si.c index 0a86b79f2..b73309419 100644 --- a/src/div_2si.c +++ b/src/div_2si.c @@ -45,7 +45,8 @@ mpfr_div_2si (mpfr_ptr y, mpfr_srcptr x, long int n, mpfr_rnd_t rnd_mode) if (rnd_mode == MPFR_RNDN && (__gmpfr_emin > MPFR_EMAX_MAX - (n - 1) || exp < __gmpfr_emin + (n - 1) || - (inexact >= 0 && mpfr_powerof2_raw (y)))) + ((MPFR_IS_NEG (y) ? inexact <= 0 : inexact >= 0) && + mpfr_powerof2_raw (y)))) rnd_mode = MPFR_RNDZ; return mpfr_underflow (y, rnd_mode, MPFR_SIGN(y)); } diff --git a/src/div_2ui.c b/src/div_2ui.c index 3aa8b6ae8..e548744d0 100644 --- a/src/div_2ui.c +++ b/src/div_2ui.c @@ -44,7 +44,9 @@ mpfr_div_2ui (mpfr_ptr y, mpfr_srcptr x, unsigned long n, mpfr_rnd_t rnd_mode) if (MPFR_UNLIKELY (n >= diffexp)) /* exp - n <= emin - 1 */ { if (rnd_mode == MPFR_RNDN && - (n > diffexp || (inexact >= 0 && mpfr_powerof2_raw (y)))) + (n > diffexp || + ((MPFR_IS_NEG (y) ? inexact <= 0 : inexact >= 0) && + mpfr_powerof2_raw (y)))) rnd_mode = MPFR_RNDZ; return mpfr_underflow (y, rnd_mode, MPFR_SIGN (y)); } diff --git a/src/mul_2si.c b/src/mul_2si.c index 0b02e2940..bc5e47934 100644 --- a/src/mul_2si.c +++ b/src/mul_2si.c @@ -48,7 +48,8 @@ mpfr_mul_2si (mpfr_ptr y, mpfr_srcptr x, long int n, mpfr_rnd_t rnd_mode) if (rnd_mode == MPFR_RNDN && (__gmpfr_emin > MPFR_EMAX_MAX + (n + 1) || exp < __gmpfr_emin - (n + 1) || - (inexact >= 0 && mpfr_powerof2_raw (y)))) + ((MPFR_IS_NEG (y) ? inexact <= 0 : inexact >= 0) && + mpfr_powerof2_raw (y)))) rnd_mode = MPFR_RNDZ; return mpfr_underflow (y, rnd_mode, MPFR_SIGN(y)); } diff --git a/tests/tmul_2exp.c b/tests/tmul_2exp.c index 5c5972bad..86a750e46 100644 --- a/tests/tmul_2exp.c +++ b/tests/tmul_2exp.c @@ -50,77 +50,82 @@ underflow (mpfr_exp_t e) { mpfr_t x, y, z1, z2; mpfr_exp_t emin; - int i, k; + int i, k, s; int prec; int rnd; int div; int inex1, inex2; unsigned int flags1, flags2; - /* Test mul_2si(x, e - k), div_2si(x, k - e) and div_2ui(x, k - e) - * with emin = e, x = 1 + i/16, i in { -1, 0, 1 }, and k = 1 to 4, - * by comparing the result with the one of a simple division. + /* Test mul_2si(x, e - k), div_2si(x, k - e) and div_2ui(x, k - e) with + * emin = e, x = s * (1 + i/16), i in { -1, 0, 1 }, s in { -1, 1 }, and + * k = 1 to 4, by comparing the result with the one of a simple division. */ emin = mpfr_get_emin (); set_emin (e); mpfr_inits2 (8, x, y, (mpfr_ptr) 0); for (i = 15; i <= 17; i++) - { - inex1 = mpfr_set_ui_2exp (x, i, -4, MPFR_RNDN); - MPFR_ASSERTN (inex1 == 0); - for (prec = 6; prec >= 3; prec -= 3) - { - mpfr_inits2 (prec, z1, z2, (mpfr_ptr) 0); - RND_LOOP (rnd) - for (k = 1; k <= 4; k++) - { - /* The following one is assumed to be correct. */ - inex1 = mpfr_mul_2si (y, x, e, MPFR_RNDN); - MPFR_ASSERTN (inex1 == 0); - inex1 = mpfr_set_ui (z1, 1 << k, MPFR_RNDN); - MPFR_ASSERTN (inex1 == 0); - mpfr_clear_flags (); - /* Do not use mpfr_div_ui to avoid the optimization - by mpfr_div_2si. */ - inex1 = mpfr_div (z1, y, z1, (mpfr_rnd_t) rnd); - flags1 = __gmpfr_flags; - - for (div = 0; div <= 2; div++) + for (s = 1; s >= -1; s -= 2) + { + inex1 = mpfr_set_si_2exp (x, s * i, -4, MPFR_RNDN); + MPFR_ASSERTN (inex1 == 0); + for (prec = 6; prec >= 3; prec -= 3) + { + mpfr_inits2 (prec, z1, z2, (mpfr_ptr) 0); + RND_LOOP (rnd) + for (k = 1; k <= 4; k++) { + /* The following one is assumed to be correct. */ + inex1 = mpfr_mul_2si (y, x, e, MPFR_RNDN); + MPFR_ASSERTN (inex1 == 0); + inex1 = mpfr_set_ui (z1, 1 << k, MPFR_RNDN); + MPFR_ASSERTN (inex1 == 0); mpfr_clear_flags (); - inex2 = div == 0 ? - mpfr_mul_2si (z2, x, e - k, (mpfr_rnd_t) rnd) : div == 1 ? - mpfr_div_2si (z2, x, k - e, (mpfr_rnd_t) rnd) : - mpfr_div_2ui (z2, x, k - e, (mpfr_rnd_t) rnd); - flags2 = __gmpfr_flags; - if (flags1 == flags2 && SAME_SIGN (inex1, inex2) && - mpfr_equal_p (z1, z2)) - continue; - printf ("Error in underflow("); - if (e == MPFR_EMIN_MIN) - printf ("MPFR_EMIN_MIN"); - else if (e == emin) - printf ("default emin"); - else if (e >= LONG_MIN) - printf ("%ld", (long) e); - else - printf ("<LONG_MIN"); - printf (") with mpfr_%s,\nx = %d/16, prec = %d, k = %d, " - "%s\n", div == 0 ? "mul_2si" : div == 1 ? - "div_2si" : "div_2ui", i, prec, k, - mpfr_print_rnd_mode ((mpfr_rnd_t) rnd)); - printf ("Expected "); - mpfr_out_str (stdout, 16, 0, z1, MPFR_RNDN); - printf (", inex = %d, flags = %u\n", SIGN (inex1), flags1); - printf ("Got "); - mpfr_out_str (stdout, 16, 0, z2, MPFR_RNDN); - printf (", inex = %d, flags = %u\n", SIGN (inex2), flags2); - exit (1); - } /* div */ - } /* k */ - mpfr_clears (z1, z2, (mpfr_ptr) 0); - } /* prec */ - } /* i */ + /* Do not use mpfr_div_ui to avoid the optimization + by mpfr_div_2si. */ + inex1 = mpfr_div (z1, y, z1, (mpfr_rnd_t) rnd); + flags1 = __gmpfr_flags; + + for (div = 0; div <= 2; div++) + { + mpfr_clear_flags (); + inex2 = + div == 0 ? + mpfr_mul_2si (z2, x, e - k, (mpfr_rnd_t) rnd) : + div == 1 ? + mpfr_div_2si (z2, x, k - e, (mpfr_rnd_t) rnd) : + mpfr_div_2ui (z2, x, k - e, (mpfr_rnd_t) rnd); + flags2 = __gmpfr_flags; + if (flags1 == flags2 && SAME_SIGN (inex1, inex2) && + mpfr_equal_p (z1, z2)) + continue; + printf ("Error in underflow("); + if (e == MPFR_EMIN_MIN) + printf ("MPFR_EMIN_MIN"); + else if (e == emin) + printf ("default emin"); + else if (e >= LONG_MIN) + printf ("%ld", (long) e); + else + printf ("<LONG_MIN"); + printf (") with mpfr_%s,\nx = %d/16, prec = %d, k = %d," + " %s\n", div == 0 ? "mul_2si" : div == 1 ? + "div_2si" : "div_2ui", s * i, prec, k, + mpfr_print_rnd_mode ((mpfr_rnd_t) rnd)); + printf ("Expected "); + mpfr_out_str (stdout, 16, 0, z1, MPFR_RNDN); + printf (", inex = %d, flags = %u\n", + SIGN (inex1), flags1); + printf ("Got "); + mpfr_out_str (stdout, 16, 0, z2, MPFR_RNDN); + printf (", inex = %d, flags = %u\n", + SIGN (inex2), flags2); + exit (1); + } /* div */ + } /* k */ + mpfr_clears (z1, z2, (mpfr_ptr) 0); + } /* prec */ + } /* i */ mpfr_clears (x, y, (mpfr_ptr) 0); set_emin (emin); } |