diff -Naurd mpfr-3.1.3-a/PATCHES mpfr-3.1.3-b/PATCHES --- mpfr-3.1.3-a/PATCHES 2016-02-23 07:54:06.617533218 +0000 +++ mpfr-3.1.3-b/PATCHES 2016-02-23 07:54:06.641532898 +0000 @@ -0,0 +1 @@ +rem1 diff -Naurd mpfr-3.1.3-a/VERSION mpfr-3.1.3-b/VERSION --- mpfr-3.1.3-a/VERSION 2016-02-23 07:43:23.726095285 +0000 +++ mpfr-3.1.3-b/VERSION 2016-02-23 07:54:06.641532898 +0000 @@ -1 +1 @@ -3.1.3-p13 +3.1.3-p14 diff -Naurd mpfr-3.1.3-a/src/mpfr.h mpfr-3.1.3-b/src/mpfr.h --- mpfr-3.1.3-a/src/mpfr.h 2016-02-23 07:43:23.726095285 +0000 +++ mpfr-3.1.3-b/src/mpfr.h 2016-02-23 07:54:06.641532898 +0000 @@ -27,7 +27,7 @@ #define MPFR_VERSION_MAJOR 3 #define MPFR_VERSION_MINOR 1 #define MPFR_VERSION_PATCHLEVEL 3 -#define MPFR_VERSION_STRING "3.1.3-p13" +#define MPFR_VERSION_STRING "3.1.3-p14" /* Macros dealing with MPFR VERSION */ #define MPFR_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c)) diff -Naurd mpfr-3.1.3-a/src/rem1.c mpfr-3.1.3-b/src/rem1.c --- mpfr-3.1.3-a/src/rem1.c 2015-06-19 19:55:10.000000000 +0000 +++ mpfr-3.1.3-b/src/rem1.c 2016-02-23 07:54:06.633533004 +0000 @@ -59,6 +59,7 @@ mpfr_exp_t ex, ey; int compare, inex, q_is_odd, sign, signx = MPFR_SIGN (x); mpz_t mx, my, r; + int tiny = 0; MPFR_ASSERTD (rnd_q == MPFR_RNDN || rnd_q == MPFR_RNDZ); @@ -109,13 +110,27 @@ if (ex <= ey) { /* q = x/y = mx/(my*2^(ey-ex)) */ - mpz_mul_2exp (my, my, ey - ex); /* divide mx by my*2^(ey-ex) */ - if (rnd_q == MPFR_RNDZ) - /* 0 <= |r| <= |my|, r has the same sign as mx */ - mpz_tdiv_qr (mx, r, mx, my); + + /* First detect cases where q=0, to avoid creating a huge number + my*2^(ey-ex): if sx = mpz_sizeinbase (mx, 2) and sy = + mpz_sizeinbase (my, 2), we have x < 2^(ex + sx) and + y >= 2^(ey + sy - 1), thus if ex + sx <= ey + sy - 1 + the quotient is 0 */ + if (ex + (mpfr_exp_t) mpz_sizeinbase (mx, 2) < + ey + (mpfr_exp_t) mpz_sizeinbase (my, 2)) + { + tiny = 1; + mpz_set (r, mx); + mpz_set_ui (mx, 0); + } else - /* 0 <= |r| <= |my|, r has the same sign as my */ - mpz_fdiv_qr (mx, r, mx, my); + { + mpz_mul_2exp (my, my, ey - ex); /* divide mx by my*2^(ey-ex) */ + + /* since mx > 0 and my > 0, we can use mpz_tdiv_qr in all cases */ + mpz_tdiv_qr (mx, r, mx, my); + /* 0 <= |r| <= |my|, r has the same sign as mx */ + } if (rnd_q == MPFR_RNDN) q_is_odd = mpz_tstbit (mx, 0); @@ -181,7 +196,20 @@ /* FIXME: the comparison 2*r < my could be done more efficiently at the mpn level */ mpz_mul_2exp (r, r, 1); - compare = mpz_cmpabs (r, my); + /* if tiny=1, we should compare r with my*2^(ey-ex) */ + if (tiny) + { + if (ex + (mpfr_exp_t) mpz_sizeinbase (r, 2) < + ey + (mpfr_exp_t) mpz_sizeinbase (my, 2)) + compare = 0; /* r*2^ex < my*2^ey */ + else + { + mpz_mul_2exp (my, my, ey - ex); + compare = mpz_cmpabs (r, my); + } + } + else + compare = mpz_cmpabs (r, my); mpz_fdiv_q_2exp (r, r, 1); compare = ((compare > 0) || ((rnd_q == MPFR_RNDN) && (compare == 0) && q_is_odd)); diff -Naurd mpfr-3.1.3-a/src/version.c mpfr-3.1.3-b/src/version.c --- mpfr-3.1.3-a/src/version.c 2016-02-23 07:43:23.726095285 +0000 +++ mpfr-3.1.3-b/src/version.c 2016-02-23 07:54:06.641532898 +0000 @@ -25,5 +25,5 @@ const char * mpfr_get_version (void) { - return "3.1.3-p13"; + return "3.1.3-p14"; } diff -Naurd mpfr-3.1.3-a/tests/tfmod.c mpfr-3.1.3-b/tests/tfmod.c --- mpfr-3.1.3-a/tests/tfmod.c 2015-06-19 19:55:10.000000000 +0000 +++ mpfr-3.1.3-b/tests/tfmod.c 2016-02-23 07:54:06.633533004 +0000 @@ -137,89 +137,90 @@ special (void) { int inexact; - mpfr_t x, y, r, nan; - mpfr_inits (x, y, r, nan, (mpfr_ptr) 0); + mpfr_t x, y, r, t; - mpfr_set_nan (nan); + mpfr_inits (x, y, r, t, (mpfr_ptr) 0); + + mpfr_set_nan (t); /* fmod (NaN, NaN) is NaN */ mpfr_set_nan (x); mpfr_set_nan (y); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (NaN, +0) is NaN */ mpfr_set_ui (y, 0, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (+1, 0) is NaN */ mpfr_set_ui (x, 1, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (0, 0) is NaN */ mpfr_set_ui (x, 0, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (+inf, +0) is NaN */ mpfr_set_inf (x, +1); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (-inf, +0) is NaN */ mpfr_set_inf (x, -1); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (-inf, -0) is NaN */ mpfr_neg (x, x, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (-inf, +1) is NaN */ mpfr_set_ui (y, +1, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (+inf, +1) is NaN */ mpfr_neg (x, x, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (+inf, -inf) is NaN */ mpfr_set_inf (y, -1); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (-inf, -inf) is NaN */ mpfr_neg (x, x, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (-inf, +inf) is NaN */ mpfr_neg (y, y, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (+inf, +inf) is NaN */ mpfr_neg (x, x, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (x, +inf) = x, if x is finite */ mpfr_set_ui (x, 1, MPFR_RNDN); @@ -271,13 +272,13 @@ mpfr_set_ui (y, 0, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (+0, -0) is NaN */ mpfr_neg (y, y, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_nan_p (r) || inexact != 0) - test_failed (r, nan, 0, inexact, x, y, MPFR_RNDN); + test_failed (r, t, 0, inexact, x, y, MPFR_RNDN); /* fmod (+0, +1) = +0 */ mpfr_set_ui (y, 1, MPFR_RNDN); @@ -303,7 +304,18 @@ if (!mpfr_equal_p (r, x) || inexact != 0) test_failed (r, x, 0, inexact, x, y, MPFR_RNDN); - mpfr_clears (x, y, r, nan, (mpfr_ptr) 0); + mpfr_set_prec (x, 380); + mpfr_set_prec (y, 385); + mpfr_set_str_binary (x, "0.11011010010110011101011000100100101100101011010001011100110001100101111001010100001011111110111100101110101010110011010101000100000100011101101100001011101110100111101111111010001001000010000110010110011100111000001110111010000100101001010111100100010001101001110100011110010000000001110001111001101100111011001000110110011100100011111110010100011001000001001011010111010000000000E0"); + mpfr_set_str_binary (y, "0.1100011000011101011010001100010111001110110111001101010010111100111100011010010011011101111101111001010111111110001001100001111101001000000010100101111001001110010110000111001000101010111001001000100101011111000010100110001111000110011011010101111101100110010101011010011101100001011101001000101111110110110110000001001101110111110110111110111111001001011110001110011111100000000000000E-1"); + mpfr_set_prec (r, 2); + inexact = mpfr_fmod (r, x, y, MPFR_RNDA); + mpfr_set_prec (t, 2); + mpfr_set_ui_2exp (t, 3, -5, MPFR_RNDN); + if (mpfr_cmp_ui_2exp (r, 3, -5) || inexact <= 0) + test_failed (r, t, 1, inexact, x, y, MPFR_RNDA); + + mpfr_clears (x, y, r, t, (mpfr_ptr) 0); return; } @@ -313,6 +325,7 @@ { mpfr_t x, y, r; int inexact; + mpfr_inits2 (100, x, y, r, (mpfr_ptr) 0); mpfr_set_prec (x, 3); @@ -353,7 +366,46 @@ mpfr_sin (y, y, MPFR_RNDN); check (r, x, y, MPFR_RNDN); - mpfr_clears(r, x, y, (mpfr_ptr) 0); + mpfr_clears (x, y, r, (mpfr_ptr) 0); +} + +static void +bug20160217 (void) +{ + mpfr_t x, y, r; + int inexact, i; + mpfr_exp_t emin, emax; + + mpfr_inits2 (53, x, y, r, (mpfr_ptr) 0); + + emin = mpfr_get_emin (); + emax = mpfr_get_emax (); + + for (i = 0; i <= 1; i++) + { + mpfr_set_zero (x, 1); + mpfr_nextabove (x); + mpfr_set_inf (y, 1); + mpfr_nextbelow (y); + inexact = mpfr_fmod (r, x, y, MPFR_RNDN); + if (!mpfr_equal_p (r, x) || inexact != 0) + { + printf ("Error for mpfr_fmod (r, nextabove(0), nextbelow(+inf)," + " MPFR_RNDN)%s\n", i ? "extended exponent range" : ""); + printf ("Expected inex = 0, r = "); + mpfr_dump (x); + printf ("Got inex = %d, r = ", inexact); + mpfr_dump (r); + exit (1); + } + set_emin (MPFR_EMIN_MIN); + set_emax (MPFR_EMAX_MAX); + } + + set_emin (emin); + set_emax (emax); + + mpfr_clears (x, y, r, (mpfr_ptr) 0); } int @@ -362,6 +414,7 @@ tests_start_mpfr (); bug20090519 (); + bug20160217 (); test_generic (2, 100, 100); diff -Naurd mpfr-3.1.3-a/tests/tremquo.c mpfr-3.1.3-b/tests/tremquo.c --- mpfr-3.1.3-a/tests/tremquo.c 2015-06-19 19:55:10.000000000 +0000 +++ mpfr-3.1.3-b/tests/tremquo.c 2016-02-23 07:54:06.633533004 +0000 @@ -59,6 +59,7 @@ { mpfr_t x, y, r; long q[1]; + int inex; if (argc == 3) /* usage: tremquo x y (rnd=MPFR_RNDN implicit) */ { @@ -281,6 +282,15 @@ MPFR_ASSERTN (mpfr_zero_p (r) && MPFR_SIGN (r) > 0); MPFR_ASSERTN (q[0] == 0); + mpfr_set_prec (x, 380); + mpfr_set_prec (y, 385); + mpfr_set_str_binary (x, "0.11011010010110011101011000100100101100101011010001011100110001100101111001010100001011111110111100101110101010110011010101000100000100011101101100001011101110100111101111111010001001000010000110010110011100111000001110111010000100101001010111100100010001101001110100011110010000000001110001111001101100111011001000110110011100100011111110010100011001000001001011010111010000000000E-2"); + mpfr_set_str_binary (y, "0.1100011000011101011010001100010111001110110111001101010010111100111100011010010011011101111101111001010111111110001001100001111101001000000010100101111001001110010110000111001000101010111001001000100101011111000010100110001111000110011011010101111101100110010101011010011101100001011101001000101111110110110110000001001101110111110110111110111111001001011110001110011111100000000000000E-1"); + mpfr_set_prec (r, 2); + inex = mpfr_remainder (r, x, y, MPFR_RNDA); + MPFR_ASSERTN(mpfr_cmp_si_2exp (r, -3, -4) == 0); + MPFR_ASSERTN(inex < 0); + mpfr_clear (x); mpfr_clear (y); mpfr_clear (r);