/* worst cases communicated by Jean-Michel Muller and Vincent Lefevre */ static int check_worst_cases (void) { mpfr_t x; mpfr_t y; mpfr_init(x); mpfr_set_prec (x, 53); check_worst_case("4.44089209850062517562e-16", "1.00000000000000022204"); check_worst_case("6.39488462184069720009e-14", "1.00000000000006372680"); check_worst_case("1.84741111297455401935e-12", "1.00000000000184718907"); check_worst_case("1.76177628026265550074e-10", "1.00000000017617751702"); check3("1.76177628026265550074e-10", MPFR_RNDN, "1.00000000017617773906"); check_worst_case("7.54175277499595900852e-10", "1.00000000075417516676"); check3("7.54175277499595900852e-10", MPFR_RNDN, "1.00000000075417538881"); /* bug found by Vincent Lefe`vre on December 8, 1999 */ check3("-5.42410311287441459172e+02", MPFR_RNDN, "2.7176584868845723e-236"); /* further cases communicated by Vincent Lefe`vre on January 27, 2000 */ check3("-1.32920285897904911589e-10", MPFR_RNDN, "0.999999999867079769622"); check3("-1.44037948245738330735e-10", MPFR_RNDN, "0.9999999998559621072757"); check3("-1.66795910430705305937e-10", MPFR_RNDZ, "0.9999999998332040895832"); check3("-1.64310953745426656203e-10", MPFR_RNDN, "0.9999999998356891017792"); check3("-1.38323574826034659172e-10", MPFR_RNDZ, "0.9999999998616764251835"); check3("-1.23621668465115401498e-10", MPFR_RNDZ, "0.9999999998763783315425"); mpfr_set_prec (x, 601); mpfr_set_str (x, "0.88b6ba510e10450edc258748bc9dfdd466f21b47ed264cdf24aa8f64af1f3fad9ec2301d43c0743f534b5aa20091ff6d352df458ef1ba519811ef6f5b11853534fd8fa32764a0a6d2d0dd20@0", 16, MPFR_RNDZ); mpfr_init2 (y, 601); mpfr_exp_2 (y, x, MPFR_RNDD); mpfr_exp_3 (x, x, MPFR_RNDD); if (mpfr_cmp (x, y)) { printf ("mpfr_exp_2 and mpfr_exp_3 differ for prec=601\n"); printf ("mpfr_exp_2 gives "); mpfr_out_str (stdout, 2, 0, y, MPFR_RNDN); printf ("\nmpfr_exp_3 gives "); mpfr_out_str (stdout, 2, 0, x, MPFR_RNDN); printf ("\n"); exit (1); } mpfr_set_prec (x, 13001); mpfr_set_prec (y, 13001); mpfr_urandomb (x, RANDS); mpfr_exp_3 (y, x, MPFR_RNDN); mpfr_exp_2 (x, x, MPFR_RNDN); if (mpfr_cmp (x, y)) { printf ("mpfr_exp_2 and mpfr_exp_3 differ for prec=13001\n"); exit (1); } mpfr_clear (x); mpfr_clear (y); return 0; }
static void compare_exp2_exp3 (int n) { mpfr_t x, y, z; int prec; mp_rnd_t rnd; mpfr_init (x); mpfr_init (y); mpfr_init (z); for (prec = 20; prec <= n; prec++) { mpfr_set_prec (x, prec); mpfr_set_prec (y, prec); mpfr_set_prec (z, prec); mpfr_random (x); rnd = (mp_rnd_t) RND_RAND(); mpfr_exp_2 (y, x, rnd); mpfr_exp_3 (z, x, rnd); if (mpfr_cmp (y,z)) { printf ("mpfr_exp_2 and mpfr_exp_3 disagree for rnd=%s and\nx=", mpfr_print_rnd_mode (rnd)); mpfr_print_binary (x); puts (""); printf ("mpfr_exp_2 gives "); mpfr_print_binary (y); puts (""); printf ("mpfr_exp_3 gives "); mpfr_print_binary (z); puts (""); exit (1); } } /* bug found by Patrick Pe'lissier on 7 Jun 2004 */ prec = 203780; mpfr_set_prec (x, prec); mpfr_set_prec (z, prec); mpfr_set_d (x, 3.0, GMP_RNDN); mpfr_sqrt (x, x, GMP_RNDN); mpfr_sub_ui (x, x, 1, GMP_RNDN); mpfr_exp_3 (z, x, GMP_RNDN); mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); }
static void compare_exp2_exp3 (mpfr_prec_t p0, mpfr_prec_t p1) { mpfr_t x, y, z; mpfr_prec_t prec; mpfr_rnd_t rnd; mpfr_init (x); mpfr_init (y); mpfr_init (z); for (prec = p0; prec <= p1; prec ++) { mpfr_set_prec (x, prec); mpfr_set_prec (y, prec); mpfr_set_prec (z, prec); do mpfr_urandomb (x, RANDS); while (MPFR_IS_ZERO (x)); /* 0 is handled by mpfr_exp only */ rnd = RND_RAND (); mpfr_exp_2 (y, x, rnd); mpfr_exp_3 (z, x, rnd); if (mpfr_cmp (y,z)) { printf ("mpfr_exp_2 and mpfr_exp_3 disagree for rnd=%s and\nx=", mpfr_print_rnd_mode (rnd)); mpfr_print_binary (x); puts (""); printf ("mpfr_exp_2 gives "); mpfr_print_binary (y); puts (""); printf ("mpfr_exp_3 gives "); mpfr_print_binary (z); puts (""); exit (1); } } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); }
int mpfr_exp (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { mpfr_exp_t expx; mpfr_prec_t precy; int inexact; MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", x, x, rnd_mode), ("y[%#R]=%R inexact=%d", y, y, inexact)); if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(x) )) { if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); MPFR_RET_NAN; } else if (MPFR_IS_INF(x)) { if (MPFR_IS_POS(x)) MPFR_SET_INF(y); else MPFR_SET_ZERO(y); MPFR_SET_POS(y); MPFR_RET(0); } else { MPFR_ASSERTD(MPFR_IS_ZERO(x)); return mpfr_set_ui (y, 1, rnd_mode); } } /* First, let's detect most overflow and underflow cases. */ { mpfr_t e, bound; /* We must extended the exponent range and save the flags now. */ MPFR_SAVE_EXPO_MARK (expo); mpfr_init2 (e, sizeof (mpfr_exp_t) * CHAR_BIT); mpfr_init2 (bound, 32); inexact = mpfr_set_exp_t (e, expo.saved_emax, MPFR_RNDN); MPFR_ASSERTD (inexact == 0); mpfr_const_log2 (bound, expo.saved_emax < 0 ? MPFR_RNDD : MPFR_RNDU); mpfr_mul (bound, bound, e, MPFR_RNDU); if (MPFR_UNLIKELY (mpfr_cmp (x, bound) >= 0)) { /* x > log(2^emax), thus exp(x) > 2^emax */ mpfr_clears (e, bound, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); return mpfr_overflow (y, rnd_mode, 1); } inexact = mpfr_set_exp_t (e, expo.saved_emin, MPFR_RNDN); MPFR_ASSERTD (inexact == 0); inexact = mpfr_sub_ui (e, e, 2, MPFR_RNDN); MPFR_ASSERTD (inexact == 0); mpfr_const_log2 (bound, expo.saved_emin < 0 ? MPFR_RNDU : MPFR_RNDD); mpfr_mul (bound, bound, e, MPFR_RNDD); if (MPFR_UNLIKELY (mpfr_cmp (x, bound) <= 0)) { /* x < log(2^(emin - 2)), thus exp(x) < 2^(emin - 2) */ mpfr_clears (e, bound, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); return mpfr_underflow (y, rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode, 1); } /* Other overflow/underflow cases must be detected by the generic routines. */ mpfr_clears (e, bound, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); } expx = MPFR_GET_EXP (x); precy = MPFR_PREC (y); /* if x < 2^(-precy), then exp(x) i.e. gives 1 +/- 1 ulp(1) */ if (MPFR_UNLIKELY (expx < 0 && (mpfr_uexp_t) (-expx) > precy)) { mpfr_exp_t emin = __gmpfr_emin; mpfr_exp_t emax = __gmpfr_emax; int signx = MPFR_SIGN (x); MPFR_SET_POS (y); if (MPFR_IS_NEG_SIGN (signx) && (rnd_mode == MPFR_RNDD || rnd_mode == MPFR_RNDZ)) { __gmpfr_emin = 0; __gmpfr_emax = 0; mpfr_setmax (y, 0); /* y = 1 - epsilon */ inexact = -1; } else { __gmpfr_emin = 1; __gmpfr_emax = 1; mpfr_setmin (y, 1); /* y = 1 */ if (MPFR_IS_POS_SIGN (signx) && (rnd_mode == MPFR_RNDU || rnd_mode == MPFR_RNDA)) { mp_size_t yn; int sh; yn = 1 + (MPFR_PREC(y) - 1) / GMP_NUMB_BITS; sh = (mpfr_prec_t) yn * GMP_NUMB_BITS - MPFR_PREC(y); MPFR_MANT(y)[0] += MPFR_LIMB_ONE << sh; inexact = 1; } else inexact = -MPFR_FROM_SIGN_TO_INT(signx); } __gmpfr_emin = emin; __gmpfr_emax = emax; } else /* General case */ { if (MPFR_UNLIKELY (precy >= MPFR_EXP_THRESHOLD)) /* mpfr_exp_3 saves the exponent range and flags itself, otherwise the flag changes in mpfr_exp_3 are lost */ inexact = mpfr_exp_3 (y, x, rnd_mode); /* O(M(n) log(n)^2) */ else { MPFR_SAVE_EXPO_MARK (expo); inexact = mpfr_exp_2 (y, x, rnd_mode); /* O(n^(1/3) M(n)) */ MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags); MPFR_SAVE_EXPO_FREE (expo); } } return mpfr_check_range (y, inexact, rnd_mode); }