diff -Naurd mpfr-3.1.4-a/PATCHES mpfr-3.1.4-b/PATCHES --- mpfr-3.1.4-a/PATCHES 2016-06-01 13:00:30.748711490 +0000 +++ mpfr-3.1.4-b/PATCHES 2016-06-01 13:00:30.772711162 +0000 @@ -0,0 +1 @@ +sub1-overflow diff -Naurd mpfr-3.1.4-a/VERSION mpfr-3.1.4-b/VERSION --- mpfr-3.1.4-a/VERSION 2016-05-22 19:59:43.866399168 +0000 +++ mpfr-3.1.4-b/VERSION 2016-06-01 13:00:30.772711162 +0000 @@ -1 +1 @@ -3.1.4-p2 +3.1.4-p3 diff -Naurd mpfr-3.1.4-a/src/mpfr.h mpfr-3.1.4-b/src/mpfr.h --- mpfr-3.1.4-a/src/mpfr.h 2016-05-22 19:59:43.862399241 +0000 +++ mpfr-3.1.4-b/src/mpfr.h 2016-06-01 13:00:30.772711162 +0000 @@ -27,7 +27,7 @@ #define MPFR_VERSION_MAJOR 3 #define MPFR_VERSION_MINOR 1 #define MPFR_VERSION_PATCHLEVEL 4 -#define MPFR_VERSION_STRING "3.1.4-p2" +#define MPFR_VERSION_STRING "3.1.4-p3" /* Macros dealing with MPFR VERSION */ #define MPFR_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c)) diff -Naurd mpfr-3.1.4-a/src/sub1.c mpfr-3.1.4-b/src/sub1.c --- mpfr-3.1.4-a/src/sub1.c 2016-03-06 11:33:05.000000000 +0000 +++ mpfr-3.1.4-b/src/sub1.c 2016-06-01 13:00:30.760711326 +0000 @@ -96,16 +96,15 @@ /* A = S*ABS(B) +/- ulp(a) */ MPFR_SET_EXP (a, MPFR_GET_EXP (b)); MPFR_RNDRAW_EVEN (inexact, a, MPFR_MANT (b), MPFR_PREC (b), - rnd_mode, MPFR_SIGN (a), - if (MPFR_UNLIKELY ( ++MPFR_EXP (a) > __gmpfr_emax)) - inexact = mpfr_overflow (a, rnd_mode, MPFR_SIGN (a))); - /* inexact = mpfr_set4 (a, b, rnd_mode, MPFR_SIGN (a)); */ + rnd_mode, MPFR_SIGN (a), ++ MPFR_EXP (a)); if (inexact == 0) { /* a = b (Exact) But we know it isn't (Since we have to remove `c') So if we round to Zero, we have to remove one ulp. Otherwise the result is correctly rounded. */ + /* An overflow is not possible. */ + MPFR_ASSERTD (MPFR_EXP (a) <= __gmpfr_emax); if (MPFR_IS_LIKE_RNDZ (rnd_mode, MPFR_IS_NEG (a))) { mpfr_nexttozero (a); @@ -136,9 +135,14 @@ i.e. inexact= MPFR_EVEN_INEX */ if (MPFR_UNLIKELY (inexact == MPFR_EVEN_INEX*MPFR_INT_SIGN (a))) { - mpfr_nexttozero (a); + if (MPFR_UNLIKELY (MPFR_EXP (a) > __gmpfr_emax)) + mpfr_setmax (a, __gmpfr_emax); + else + mpfr_nexttozero (a); inexact = -MPFR_INT_SIGN (a); } + else if (MPFR_UNLIKELY (MPFR_EXP (a) > __gmpfr_emax)) + inexact = mpfr_overflow (a, rnd_mode, MPFR_SIGN (a)); MPFR_RET (inexact); } } diff -Naurd mpfr-3.1.4-a/src/version.c mpfr-3.1.4-b/src/version.c --- mpfr-3.1.4-a/src/version.c 2016-05-22 19:59:43.866399168 +0000 +++ mpfr-3.1.4-b/src/version.c 2016-06-01 13:00:30.772711162 +0000 @@ -25,5 +25,5 @@ const char * mpfr_get_version (void) { - return "3.1.4-p2"; + return "3.1.4-p3"; } diff -Naurd mpfr-3.1.4-a/tests/tsub.c mpfr-3.1.4-b/tests/tsub.c --- mpfr-3.1.4-a/tests/tsub.c 2016-03-06 11:33:03.000000000 +0000 +++ mpfr-3.1.4-b/tests/tsub.c 2016-06-01 13:00:30.760711326 +0000 @@ -630,6 +630,135 @@ } } +static void +check_max_almosteven (void) +{ + mpfr_exp_t old_emin, old_emax; + mpfr_exp_t emin[2] = { MPFR_EMIN_MIN, -1000 }; + mpfr_exp_t emax[2] = { MPFR_EMAX_MAX, 1000 }; + int i; + + old_emin = mpfr_get_emin (); + old_emax = mpfr_get_emax (); + + for (i = 0; i < 2; i++) + { + mpfr_t a1, a2, b, c; + mpfr_prec_t p; + int neg, j, rnd; + + set_emin (emin[i]); + set_emax (emax[i]); + + p = MPFR_PREC_MIN + randlimb () % 70; + mpfr_init2 (a1, p); + mpfr_init2 (a2, p); + mpfr_init2 (b, p+1); + mpfr_init2 (c, MPFR_PREC_MIN); + + mpfr_setmax (b, 0); + mpfr_set_ui (c, 1, MPFR_RNDN); + + for (neg = 0; neg < 2; neg++) + { + for (j = 1; j >= 0; j--) + { + mpfr_set_exp (b, __gmpfr_emax - j); + RND_LOOP (rnd) + { + unsigned int flags1, flags2; + int inex1, inex2; + + flags1 = MPFR_FLAGS_INEXACT; + if (rnd == MPFR_RNDN || MPFR_IS_LIKE_RNDZ (rnd, neg)) + { + inex1 = neg ? 1 : -1; + mpfr_setmax (a1, __gmpfr_emax - j); + } + else + { + inex1 = neg ? -1 : 1; + if (j == 0) + { + flags1 |= MPFR_FLAGS_OVERFLOW; + mpfr_set_inf (a1, 1); + } + else + { + mpfr_setmin (a1, __gmpfr_emax); + } + } + MPFR_SET_SIGN (a1, neg ? -1 : 1); + + mpfr_clear_flags (); + inex2 = mpfr_sub (a2, b, c, (mpfr_rnd_t) rnd); + flags2 = __gmpfr_flags; + + if (! (flags1 == flags2 && SAME_SIGN (inex1, inex2) && + mpfr_equal_p (a1, a2))) + { + printf ("Error 1 in check_max_almosteven for %s," + " i = %d, j = %d, neg = %d\n", + mpfr_print_rnd_mode ((mpfr_rnd_t) rnd), + i, j, neg); + printf (" b = "); + mpfr_dump (b); + printf ("Expected "); + mpfr_dump (a1); + printf (" with inex = %d, flags =", inex1); + flags_out (flags1); + printf ("Got "); + mpfr_dump (a2); + printf (" with inex = %d, flags =", inex2); + flags_out (flags2); + exit (1); + } + + if (i == 0) + break; + + mpfr_clear_flags (); + set_emin (MPFR_EMIN_MIN); + set_emax (MPFR_EMAX_MAX); + inex2 = mpfr_sub (a2, b, c, (mpfr_rnd_t) rnd); + set_emin (emin[i]); + set_emax (emax[i]); + inex2 = mpfr_check_range (a2, inex2, (mpfr_rnd_t) rnd); + flags2 = __gmpfr_flags; + + if (! (flags1 == flags2 && SAME_SIGN (inex1, inex2) && + mpfr_equal_p (a1, a2))) + { + printf ("Error 2 in check_max_almosteven for %s," + " i = %d, j = %d, neg = %d\n", + mpfr_print_rnd_mode ((mpfr_rnd_t) rnd), + i, j, neg); + printf (" b = "); + mpfr_dump (b); + printf ("Expected "); + mpfr_dump (a1); + printf (" with inex = %d, flags =", inex1); + flags_out (flags1); + printf ("Got "); + mpfr_dump (a2); + printf (" with inex = %d, flags =", inex2); + flags_out (flags2); + exit (1); + } + } + } /* j */ + + mpfr_neg (b, b, MPFR_RNDN); + mpfr_neg (c, c, MPFR_RNDN); + } /* neg */ + + mpfr_clears (a1, a2, b, c, (mpfr_ptr) 0); + } /* i */ + + set_emin (old_emin); + set_emax (old_emax); +} + #define TEST_FUNCTION test_sub #define TWO_ARGS #define RAND_FUNCTION(x) mpfr_random2(x, MPFR_LIMB_SIZE (x), randlimb () % 100, RANDS) @@ -647,6 +776,7 @@ check_rounding (); check_diverse (); check_inexact (); + check_max_almosteven (); bug_ddefour (); for (p=2; p<200; p++) for (i=0; i<50; i++)