/* This bug occurs in mpfr_exp_2 on a Linux-64 machine, r5475. */ static void bug20080731 (void) { mpfr_exp_t emin; mpfr_t x, y1, y2; mpfr_prec_t prec = 64; emin = mpfr_get_emin (); set_emin (MPFR_EMIN_MIN); mpfr_init2 (x, 200); mpfr_set_str (x, "-2.c5c85fdf473de6af278ece700fcbdabd03cd0cb9ca62d8b62c@7", 16, MPFR_RNDN); mpfr_init2 (y1, prec); mpfr_exp (y1, x, MPFR_RNDU); /* Compute the result with a higher internal precision. */ mpfr_init2 (y2, 300); mpfr_exp (y2, x, MPFR_RNDU); mpfr_prec_round (y2, prec, MPFR_RNDU); if (mpfr_cmp0 (y1, y2) != 0) { printf ("Error in bug20080731\nExpected "); mpfr_out_str (stdout, 16, 0, y2, MPFR_RNDN); printf ("\nGot "); mpfr_out_str (stdout, 16, 0, y1, MPFR_RNDN); printf ("\n"); exit (1); } mpfr_clears (x, y1, y2, (mpfr_ptr) 0); set_emin (emin); }
/* Worst case incorrectly rounded in r5573, found with the bad_cases test */ static void bad_case1 (void) { mpfr_t x, y, z; mpfr_init2 (x, 72); mpfr_inits2 (6, y, z, (mpfr_ptr) 0); mpfr_set_str (x, "1.08310518720928b30e@-120", 16, MPFR_RNDN); mpfr_set_str (z, "f.8@59", 16, MPFR_RNDN); /* z = rec_sqrt(x) rounded on 6 bits toward 0, the exact value being ~= f.bffffffffffffffffa11@59. */ mpfr_rec_sqrt (y, x, MPFR_RNDZ); if (mpfr_cmp0 (y, z) != 0) { printf ("Error in bad_case1\nexpected "); mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN); printf ("\ngot "); mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN); printf ("\n"); exit (1); } mpfr_clears (x, y, z, (mpfr_ptr) 0); }
static void underflow_up (int extended_emin) { mpfr_t minpos, x, y, t, t2; int precx, precy; int inex; int rnd; int e3; int i, j; mpfr_init2 (minpos, 2); mpfr_set_ui (minpos, 0, MPFR_RNDN); mpfr_nextabove (minpos); /* Let's test values near the underflow boundary. * * Minimum representable positive number: minpos = 2^(emin - 1). * Let's choose an MPFR number x = log(minpos) + eps, with |eps| small * (note: eps cannot be 0, and cannot be a rational number either). * Then exp(x) = minpos * exp(eps) ~= minpos * (1 + eps + eps^2). * We will compute y = rnd(exp(x)) in some rounding mode, precision p. * 1. If eps > 0, then in any rounding mode: * rnd(exp(x)) >= minpos and no underflow. * So, let's take x1 = rndu(log(minpos)) in some precision. * 2. If eps < 0, then exp(x) < minpos and the result will be either 0 * or minpos. An underflow always occurs in MPFR_RNDZ and MPFR_RNDD, * but not necessarily in MPFR_RNDN and MPFR_RNDU (this is underflow * after rounding in an unbounded exponent range). If -a < eps < -b, * minpos * (1 - a) < exp(x) < minpos * (1 - b + b^2). * - If eps > -2^(-p), no underflow in MPFR_RNDU. * - If eps > -2^(-p-1), no underflow in MPFR_RNDN. * - If eps < - (2^(-p-1) + 2^(-2p-1)), underflow in MPFR_RNDN. * - If eps < - (2^(-p) + 2^(-2p+1)), underflow in MPFR_RNDU. * - In MPFR_RNDN, result is minpos iff exp(eps) > 1/2, i.e. * - log(2) < eps < ... * * Moreover, since precy < MPFR_EXP_THRESHOLD (to avoid tests that take * too much time), mpfr_exp() always selects mpfr_exp_2(); so, we need * to test mpfr_exp_3() too. This will be done via the e3 variable: * e3 = 0: mpfr_exp(), thus mpfr_exp_2(). * e3 = 1: mpfr_exp_3(), via the exp_3() wrapper. * i.e.: inex = e3 ? exp_3 (y, x, rnd) : mpfr_exp (y, x, rnd); */ /* Case eps > 0. In revision 5461 (trunk) on a 64-bit Linux machine: * Incorrect flags in underflow_up, eps > 0, MPFR_RNDN and extended emin * for precx = 96, precy = 16, mpfr_exp_3 * Got 9 instead of 8. * Note: testing this case in several precisions for x and y introduces * some useful random. Indeed, the bug is not always triggered. * Fixed in r5469. */ for (precx = 16; precx <= 128; precx += 16) { mpfr_init2 (x, precx); mpfr_log (x, minpos, MPFR_RNDU); for (precy = 16; precy <= 128; precy += 16) { mpfr_init2 (y, precy); for (e3 = 0; e3 <= 1; e3++) { RND_LOOP (rnd) { int err = 0; mpfr_clear_flags (); inex = e3 ? exp_3 (y, x, (mpfr_rnd_t) rnd) : mpfr_exp (y, x, (mpfr_rnd_t) rnd); if (__gmpfr_flags != MPFR_FLAGS_INEXACT) { printf ("Incorrect flags in underflow_up, eps > 0, %s", mpfr_print_rnd_mode ((mpfr_rnd_t) rnd)); if (extended_emin) printf (" and extended emin"); printf ("\nfor precx = %d, precy = %d, %s\n", precx, precy, e3 ? "mpfr_exp_3" : "mpfr_exp"); printf ("Got %u instead of %u.\n", __gmpfr_flags, (unsigned int) MPFR_FLAGS_INEXACT); err = 1; } if (mpfr_cmp0 (y, minpos) < 0) { printf ("Incorrect result in underflow_up, eps > 0, %s", mpfr_print_rnd_mode ((mpfr_rnd_t) rnd)); if (extended_emin) printf (" and extended emin"); printf ("\nfor precx = %d, precy = %d, %s\n", precx, precy, e3 ? "mpfr_exp_3" : "mpfr_exp"); mpfr_dump (y); err = 1; } MPFR_ASSERTN (inex != 0); if (rnd == MPFR_RNDD || rnd == MPFR_RNDZ) MPFR_ASSERTN (inex < 0); if (rnd == MPFR_RNDU) MPFR_ASSERTN (inex > 0); if (err) exit (1); } } mpfr_clear (y); } mpfr_clear (x); } /* Case - log(2) < eps < 0 in MPFR_RNDN, starting with small-precision x; * only check the result and the ternary value. * Previous to r5453 (trunk), on 32-bit and 64-bit machines, this fails * for precx = 65 and precy = 16, e.g.: * exp_2.c:264: assertion failed: ... * because mpfr_sub (r, x, r, MPFR_RNDU); yields a null value. This is * fixed in r5453 by going to next Ziv's iteration. */ for (precx = sizeof(mpfr_exp_t) * CHAR_BIT + 1; precx <= 81; precx += 8) { mpfr_init2 (x, precx); mpfr_log (x, minpos, MPFR_RNDD); /* |ulp| <= 1/2 */ for (precy = 16; precy <= 128; precy += 16) { mpfr_init2 (y, precy); inex = mpfr_exp (y, x, MPFR_RNDN); if (inex <= 0 || mpfr_cmp0 (y, minpos) != 0) { printf ("Error in underflow_up, - log(2) < eps < 0"); if (extended_emin) printf (" and extended emin"); printf (" for prec = %d\nExpected ", precy); mpfr_out_str (stdout, 16, 0, minpos, MPFR_RNDN); printf (" (minimum positive MPFR number) and inex > 0\nGot "); mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN); printf ("\nwith inex = %d\n", inex); exit (1); } mpfr_clear (y); } mpfr_clear (x); } /* Cases eps ~ -2^(-p) and eps ~ -2^(-p-1). More precisely, * _ for j = 0, eps > -2^(-(p+i)), * _ for j = 1, eps < - (2^(-(p+i)) + 2^(1-2(p+i))), * where i = 0 or 1. */ mpfr_inits2 (2, t, t2, (mpfr_ptr) 0); for (precy = 16; precy <= 128; precy += 16) { mpfr_set_ui_2exp (t, 1, - precy, MPFR_RNDN); /* 2^(-p) */ mpfr_set_ui_2exp (t2, 1, 1 - 2 * precy, MPFR_RNDN); /* 2^(-2p+1) */ precx = sizeof(mpfr_exp_t) * CHAR_BIT + 2 * precy + 8; mpfr_init2 (x, precx); mpfr_init2 (y, precy); for (i = 0; i <= 1; i++) { for (j = 0; j <= 1; j++) { if (j == 0) { /* Case eps > -2^(-(p+i)). */ mpfr_log (x, minpos, MPFR_RNDU); } else /* j == 1 */ { /* Case eps < - (2^(-(p+i)) + 2^(1-2(p+i))). */ mpfr_log (x, minpos, MPFR_RNDD); inex = mpfr_sub (x, x, t2, MPFR_RNDN); MPFR_ASSERTN (inex == 0); } inex = mpfr_sub (x, x, t, MPFR_RNDN); MPFR_ASSERTN (inex == 0); RND_LOOP (rnd) for (e3 = 0; e3 <= 1; e3++) { int err = 0; unsigned int flags; flags = MPFR_FLAGS_INEXACT | (((rnd == MPFR_RNDU || rnd == MPFR_RNDA) && (i == 1 || j == 0)) || (rnd == MPFR_RNDN && (i == 1 && j == 0)) ? 0 : MPFR_FLAGS_UNDERFLOW); mpfr_clear_flags (); inex = e3 ? exp_3 (y, x, (mpfr_rnd_t) rnd) : mpfr_exp (y, x, (mpfr_rnd_t) rnd); if (__gmpfr_flags != flags) { printf ("Incorrect flags in underflow_up, %s", mpfr_print_rnd_mode ((mpfr_rnd_t) rnd)); if (extended_emin) printf (" and extended emin"); printf ("\nfor precx = %d, precy = %d, ", precx, precy); if (j == 0) printf ("eps >~ -2^(-%d)", precy + i); else printf ("eps <~ - (2^(-%d) + 2^(%d))", precy + i, 1 - 2 * (precy + i)); printf (", %s\n", e3 ? "mpfr_exp_3" : "mpfr_exp"); printf ("Got %u instead of %u.\n", __gmpfr_flags, flags); err = 1; } if (rnd == MPFR_RNDU || rnd == MPFR_RNDA || rnd == MPFR_RNDN ? mpfr_cmp0 (y, minpos) != 0 : MPFR_NOTZERO (y)) { printf ("Incorrect result in underflow_up, %s", mpfr_print_rnd_mode ((mpfr_rnd_t) rnd)); if (extended_emin) printf (" and extended emin"); printf ("\nfor precx = %d, precy = %d, ", precx, precy); if (j == 0) printf ("eps >~ -2^(-%d)", precy + i); else printf ("eps <~ - (2^(-%d) + 2^(%d))", precy + i, 1 - 2 * (precy + i)); printf (", %s\n", e3 ? "mpfr_exp_3" : "mpfr_exp"); mpfr_dump (y); err = 1; } if (err) exit (1); } /* for (e3 ...) */ } /* for (j ...) */ mpfr_div_2si (t, t, 1, MPFR_RNDN); mpfr_div_2si (t2, t2, 2, MPFR_RNDN); } /* for (i ...) */ mpfr_clears (x, y, (mpfr_ptr) 0); } /* for (precy ...) */ mpfr_clears (t, t2, (mpfr_ptr) 0); /* Case exp(eps) ~= 1/2, i.e. eps ~= - log(2). * We choose x0 and x1 with high enough precision such that: * x0 = rndd(rndd(log(minpos)) - rndu(log(2))) * x1 = rndu(rndu(log(minpos)) - rndd(log(2))) * In revision 5507 (trunk) on a 64-bit Linux machine, this fails: * Error in underflow_up, eps >~ - log(2) and extended emin * for precy = 16, mpfr_exp * Expected 1.0@-1152921504606846976 (minimum positive MPFR number), * inex > 0 and flags = 9 * Got 0 * with inex = -1 and flags = 9 * due to a double-rounding problem in mpfr_mul_2si when rescaling * the result. */ mpfr_inits2 (sizeof(mpfr_exp_t) * CHAR_BIT + 64, x, t, (mpfr_ptr) 0); for (i = 0; i <= 1; i++) { mpfr_log (x, minpos, i ? MPFR_RNDU : MPFR_RNDD); mpfr_const_log2 (t, i ? MPFR_RNDD : MPFR_RNDU); mpfr_sub (x, x, t, i ? MPFR_RNDU : MPFR_RNDD); for (precy = 16; precy <= 128; precy += 16) { mpfr_init2 (y, precy); for (e3 = 0; e3 <= 1; e3++) { unsigned int flags, uflags = MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW; mpfr_clear_flags (); inex = e3 ? exp_3 (y, x, MPFR_RNDN) : mpfr_exp (y, x, MPFR_RNDN); flags = __gmpfr_flags; if (flags != uflags || (i ? (inex <= 0 || mpfr_cmp0 (y, minpos) != 0) : (inex >= 0 || MPFR_NOTZERO (y)))) { printf ("Error in underflow_up, eps %c~ - log(2)", i ? '>' : '<'); if (extended_emin) printf (" and extended emin"); printf ("\nfor precy = %d, %s\nExpected ", precy, e3 ? "mpfr_exp_3" : "mpfr_exp"); if (i) { mpfr_out_str (stdout, 16, 0, minpos, MPFR_RNDN); printf (" (minimum positive MPFR number),\ninex >"); } else { printf ("+0, inex <"); } printf (" 0 and flags = %u\nGot ", uflags); mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN); printf ("\nwith inex = %d and flags = %u\n", inex, flags); exit (1); } } mpfr_clear (y); } } mpfr_clears (x, t, (mpfr_ptr) 0); mpfr_clear (minpos); }