diff -Naurd mpfr-4.0.1-a/PATCHES mpfr-4.0.1-b/PATCHES --- mpfr-4.0.1-a/PATCHES 2018-04-27 12:40:46.838268769 +0000 +++ mpfr-4.0.1-b/PATCHES 2018-04-27 12:40:46.870268475 +0000 @@ -0,0 +1 @@ +sub1sp1n-reuse diff -Naurd mpfr-4.0.1-a/VERSION mpfr-4.0.1-b/VERSION --- mpfr-4.0.1-a/VERSION 2018-02-07 12:50:31.000000000 +0000 +++ mpfr-4.0.1-b/VERSION 2018-04-27 12:40:46.870268475 +0000 @@ -1 +1 @@ -4.0.1 +4.0.1-p1 diff -Naurd mpfr-4.0.1-a/src/mpfr.h mpfr-4.0.1-b/src/mpfr.h --- mpfr-4.0.1-a/src/mpfr.h 2018-02-07 12:50:31.000000000 +0000 +++ mpfr-4.0.1-b/src/mpfr.h 2018-04-27 12:40:46.870268475 +0000 @@ -27,7 +27,7 @@ #define MPFR_VERSION_MAJOR 4 #define MPFR_VERSION_MINOR 0 #define MPFR_VERSION_PATCHLEVEL 1 -#define MPFR_VERSION_STRING "4.0.1" +#define MPFR_VERSION_STRING "4.0.1-p1" /* User macros: MPFR_USE_FILE: Define it to make MPFR define functions dealing diff -Naurd mpfr-4.0.1-a/src/sub1sp.c mpfr-4.0.1-b/src/sub1sp.c --- mpfr-4.0.1-a/src/sub1sp.c 2018-01-09 12:30:58.000000000 +0000 +++ mpfr-4.0.1-b/src/sub1sp.c 2018-04-27 12:40:46.858268585 +0000 @@ -375,13 +375,15 @@ } else /* cases (a), (c), (d) and (e) */ { - ap[0] = -MPFR_LIMB_ONE; /* rb=1 in case (e) and case (c) */ rb = d > GMP_NUMB_BITS + 1 || (d == GMP_NUMB_BITS + 1 && cp[0] == MPFR_LIMB_HIGHBIT); /* sb = 1 in case (d) and (e) */ sb = d > GMP_NUMB_BITS + 1 || (d == GMP_NUMB_BITS + 1 && cp[0] > MPFR_LIMB_HIGHBIT); + /* Warning: only set ap[0] last, otherwise in case ap=cp, + the above comparisons involving cp[0] would be wrong */ + ap[0] = -MPFR_LIMB_ONE; } } } diff -Naurd mpfr-4.0.1-a/src/version.c mpfr-4.0.1-b/src/version.c --- mpfr-4.0.1-a/src/version.c 2018-02-07 12:50:31.000000000 +0000 +++ mpfr-4.0.1-b/src/version.c 2018-04-27 12:40:46.870268475 +0000 @@ -25,5 +25,5 @@ const char * mpfr_get_version (void) { - return "4.0.1"; + return "4.0.1-p1"; } diff -Naurd mpfr-4.0.1-a/tests/tsub.c mpfr-4.0.1-b/tests/tsub.c --- mpfr-4.0.1-a/tests/tsub.c 2018-01-09 12:30:58.000000000 +0000 +++ mpfr-4.0.1-b/tests/tsub.c 2018-04-27 12:40:46.858268585 +0000 @@ -22,12 +22,13 @@ #include "mpfr-test.h" -#ifdef CHECK_EXTERNAL static int test_sub (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode) { +#ifdef CHECK_EXTERNAL int res; int ok = rnd_mode == MPFR_RNDN && mpfr_number_p (b) && mpfr_number_p (c); + if (ok) { mpfr_print_raw (b); @@ -42,10 +43,69 @@ printf ("\n"); } return res; -} -#else -#define test_sub mpfr_sub +#else /* reuse test */ + int inex; + + inex = mpfr_sub (a, b, c, rnd_mode); + + if (a != b && a != c && ! MPFR_IS_NAN (a)) + { + mpfr_t t; + int reuse_b, reuse_c, inex_r; + + reuse_b = MPFR_PREC (a) == MPFR_PREC (b); + reuse_c = MPFR_PREC (a) == MPFR_PREC (c); + + if (reuse_b || reuse_c) + mpfr_init2 (t, MPFR_PREC (a)); + + if (reuse_b) + { + mpfr_set (t, b, MPFR_RNDN); + inex_r = mpfr_sub (t, t, c, rnd_mode); + if (!(mpfr_equal_p (t, a) && SAME_SIGN (inex_r, inex))) + { + printf ("reuse of b error in b - c in %s for\n", + mpfr_print_rnd_mode (rnd_mode)); + printf ("b = "); + mpfr_dump (b); + printf ("c = "); + mpfr_dump (c); + printf ("Expected "); mpfr_dump (a); + printf (" with inex = %d\n", inex); + printf ("Got "); mpfr_dump (t); + printf (" with inex = %d\n", inex_r); + exit (1); + } + } + + if (reuse_c) + { + mpfr_set (t, c, MPFR_RNDN); + inex_r = mpfr_sub (t, b, t, rnd_mode); + if (!(mpfr_equal_p (t, a) && SAME_SIGN (inex_r, inex))) + { + printf ("reuse of c error in b - c in %s for\n", + mpfr_print_rnd_mode (rnd_mode)); + printf ("b = "); + mpfr_dump (b); + printf ("c = "); + mpfr_dump (c); + printf ("Expected "); mpfr_dump (a); + printf (" with inex = %d\n", inex); + printf ("Got "); mpfr_dump (t); + printf (" with inex = %d\n", inex_r); + exit (1); + } + } + + if (reuse_b || reuse_c) + mpfr_clear (t); + } + + return inex; #endif +} static void check_diverse (void) @@ -940,6 +1000,80 @@ } } +/* Fails with r12281: "reuse of c error in b - c in MPFR_RNDN". */ +static void +bug20180217 (void) +{ + mpfr_t x, y, z1, z2; + int r, p, d, i, inex1, inex2; + + for (p = 3; p <= 3 + 4 * GMP_NUMB_BITS; p++) + { + mpfr_inits2 (p, x, y, z1, z2, (mpfr_ptr) 0); + for (d = p; d <= p+4; d++) + { + mpfr_set_ui (x, 1, MPFR_RNDN); + mpfr_set_ui_2exp (y, 1, -d, MPFR_RNDN); + for (i = 0; i < 3; i++) + { + RND_LOOP_NO_RNDF (r) + { + mpfr_set (z1, x, MPFR_RNDN); + if (d == p) + { + mpfr_nextbelow (z1); + if (i == 0) + inex1 = 0; + else if (r == MPFR_RNDD || r == MPFR_RNDZ || + (r == MPFR_RNDN && i > 1)) + { + mpfr_nextbelow (z1); + inex1 = -1; + } + else + inex1 = 1; + } + else if (r == MPFR_RNDD || r == MPFR_RNDZ || + (r == MPFR_RNDN && d == p+1 && i > 0)) + { + mpfr_nextbelow (z1); + inex1 = -1; + } + else + inex1 = 1; + inex2 = test_sub (z2, x, y, (mpfr_rnd_t) r); + if (!(mpfr_equal_p (z1, z2) && SAME_SIGN (inex1, inex2))) + { + printf ("Error in bug20180217 with " + "p=%d, d=%d, i=%d, %s\n", p, d, i, + mpfr_print_rnd_mode ((mpfr_rnd_t) r)); + printf ("x = "); + mpfr_dump (x); + printf ("y = "); + mpfr_dump (y); + printf ("Expected "); mpfr_dump (z1); + printf (" with inex = %d\n", inex1); + printf ("Got "); mpfr_dump (z2); + printf (" with inex = %d\n", inex2); + exit (1); + } + } + if (i == 0) + mpfr_nextabove (y); + else + { + if (p < 6) + break; + mpfr_nextbelow (y); + mpfr_mul_ui (y, y, 25, MPFR_RNDD); + mpfr_div_2ui (y, y, 4, MPFR_RNDN); + } + } + } + mpfr_clears (x, y, z1, z2, (mpfr_ptr) 0); + } +} + #define TEST_FUNCTION test_sub #define TWO_ARGS #define RAND_FUNCTION(x) mpfr_random2(x, MPFR_LIMB_SIZE (x), randlimb () % 100, RANDS) @@ -962,6 +1096,7 @@ check_inexact (); check_max_almosteven (); bug_ddefour (); + bug20180217 (); for (p=2; p<200; p++) for (i=0; i<50; i++) check_two_sum (p); diff -Naurd mpfr-4.0.1-a/tests/tsub1sp.c mpfr-4.0.1-b/tests/tsub1sp.c --- mpfr-4.0.1-a/tests/tsub1sp.c 2018-01-09 12:30:58.000000000 +0000 +++ mpfr-4.0.1-b/tests/tsub1sp.c 2018-04-27 12:40:46.858268585 +0000 @@ -284,6 +284,91 @@ } } +static void +coverage (void) +{ + mpfr_t a, b, c, d, u; + int inex; + + /* coverage test in mpfr_sub1sp: case d=1, limb > MPFR_LIMB_HIGHBIT, RNDF + and also RNDZ */ + mpfr_init2 (a, 3 * GMP_NUMB_BITS); + mpfr_init2 (b, 3 * GMP_NUMB_BITS); + mpfr_init2 (c, 3 * GMP_NUMB_BITS); + mpfr_init2 (d, 3 * GMP_NUMB_BITS); + mpfr_init2 (u, 3 * GMP_NUMB_BITS); + mpfr_set_ui (b, 1, MPFR_RNDN); + mpfr_nextbelow (b); /* b = 1 - 2^(-p) */ + mpfr_set_prec (c, GMP_NUMB_BITS); + mpfr_set_ui_2exp (c, 1, -1, MPFR_RNDN); + mpfr_nextbelow (c); + mpfr_nextbelow (c); /* c = 1/2 - 2*2^(-GMP_NUMB_BITS-1) */ + mpfr_prec_round (c, 3 * GMP_NUMB_BITS, MPFR_RNDN); + mpfr_nextbelow (c); /* c = 1/2 - 2*2^(-GMP_NUMB_BITS-1) - 2^(-p-1) */ + /* b-c = c */ + mpfr_sub (a, b, c, MPFR_RNDF); + mpfr_sub (d, b, c, MPFR_RNDD); + mpfr_sub (u, b, c, MPFR_RNDU); + /* check a = d or u */ + MPFR_ASSERTN(mpfr_equal_p (a, d) || mpfr_equal_p (a, u)); + + /* coverage test in mpfr_sub1sp: case d=p, RNDN, sb = 0, significand of b + is even but b<>2^e, (case 1e) */ + mpfr_set_prec (a, 3 * GMP_NUMB_BITS); + mpfr_set_prec (b, 3 * GMP_NUMB_BITS); + mpfr_set_prec (c, 3 * GMP_NUMB_BITS); + mpfr_set_ui (b, 1, MPFR_RNDN); + mpfr_nextabove (b); + mpfr_nextabove (b); + mpfr_set_ui_2exp (c, 1, -3 * GMP_NUMB_BITS, MPFR_RNDN); + inex = mpfr_sub (a, b, c, MPFR_RNDN); + MPFR_ASSERTN(inex > 0); + MPFR_ASSERTN(mpfr_equal_p (a, b)); + + mpfr_clear (a); + mpfr_clear (b); + mpfr_clear (c); + mpfr_clear (d); + mpfr_clear (u); +} + +/* bug in mpfr_sub1sp1n, made generic */ +static void +bug20180217 (mpfr_prec_t pmax) +{ + mpfr_t a, b, c; + int inex; + mpfr_prec_t p; + + for (p = MPFR_PREC_MIN; p <= pmax; p++) + { + mpfr_init2 (a, p); + mpfr_init2 (b, p); + mpfr_init2 (c, p); + mpfr_set_ui (b, 1, MPFR_RNDN); /* b = 1 */ + mpfr_set_ui_2exp (c, 1, -p-1, MPFR_RNDN); /* c = 2^(-p-1) */ + /* a - b = 1 - 2^(-p-1) and should be rounded to 1 (case 2f of + mpfr_sub1sp) */ + inex = mpfr_sub (a, b, c, MPFR_RNDN); + MPFR_ASSERTN(inex > 0); + MPFR_ASSERTN(mpfr_cmp_ui (a, 1) == 0); + /* check also when a=b */ + mpfr_set_ui (a, 1, MPFR_RNDN); + inex = mpfr_sub (a, a, c, MPFR_RNDN); + MPFR_ASSERTN(inex > 0); + MPFR_ASSERTN(mpfr_cmp_ui (a, 1) == 0); + /* and when a=c */ + mpfr_set_ui (b, 1, MPFR_RNDN); /* b = 1 */ + mpfr_set_ui_2exp (a, 1, -p-1, MPFR_RNDN); + inex = mpfr_sub (a, b, a, MPFR_RNDN); + MPFR_ASSERTN(inex > 0); + MPFR_ASSERTN(mpfr_cmp_ui (a, 1) == 0); + mpfr_clear (a); + mpfr_clear (b); + mpfr_clear (c); + } +} + int main (void) { @@ -291,6 +376,8 @@ tests_start_mpfr (); + bug20180217 (1024); + coverage (); compare_sub_sub1sp (); test20170208 (); bug20170109 ();