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); }
static void check_special (void) { mpfr_t x, y, z; mpfr_exp_t emin, emax; emin = mpfr_get_emin (); emax = mpfr_get_emax (); mpfr_init (x); mpfr_init (y); mpfr_init (z); /* check exp(NaN) = NaN */ mpfr_set_nan (x); test_exp (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error for exp(NaN)\n"); exit (1); } /* check exp(+inf) = +inf */ mpfr_set_inf (x, 1); test_exp (y, x, MPFR_RNDN); if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0) { printf ("Error for exp(+inf)\n"); exit (1); } /* check exp(-inf) = +0 */ mpfr_set_inf (x, -1); test_exp (y, x, MPFR_RNDN); if (mpfr_cmp_ui (y, 0) || mpfr_sgn (y) < 0) { printf ("Error for exp(-inf)\n"); exit (1); } /* Check overflow. Corner case of mpfr_exp_2 */ mpfr_set_prec (x, 64); mpfr_set_emax (MPFR_EMAX_DEFAULT); mpfr_set_emin (MPFR_EMIN_DEFAULT); mpfr_set_str (x, "0.1011000101110010000101111111010100001100000001110001100111001101E30", 2, MPFR_RNDN); mpfr_exp (x, x, MPFR_RNDD); if (mpfr_cmp_str (x, ".1111111111111111111111111111111111111111111111111111111111111111E1073741823", 2, MPFR_RNDN) != 0) { printf ("Wrong overflow detection in mpfr_exp\n"); mpfr_dump (x); exit (1); } /* Check underflow. Corner case of mpfr_exp_2 */ mpfr_set_str (x, "-0.1011000101110010000101111111011111010001110011110111100110101100E30", 2, MPFR_RNDN); mpfr_exp (x, x, MPFR_RNDN); if (mpfr_cmp_str (x, "0.1E-1073741823", 2, MPFR_RNDN) != 0) { printf ("Wrong underflow (1) detection in mpfr_exp\n"); mpfr_dump (x); exit (1); } mpfr_set_str (x, "-0.1011001101110010000101111111011111010001110011110111100110111101E30", 2, MPFR_RNDN); mpfr_exp (x, x, MPFR_RNDN); if (mpfr_cmp_ui (x, 0) != 0) { printf ("Wrong underflow (2) detection in mpfr_exp\n"); mpfr_dump (x); exit (1); } /* Check overflow. Corner case of mpfr_exp_3 */ if (MPFR_PREC_MAX >= MPFR_EXP_THRESHOLD + 10 && MPFR_PREC_MAX >= 64) { /* this ensures that for small MPFR_EXP_THRESHOLD, the following mpfr_set_str conversion is exact */ mpfr_set_prec (x, (MPFR_EXP_THRESHOLD + 10 > 64) ? MPFR_EXP_THRESHOLD + 10 : 64); mpfr_set_str (x, "0.1011000101110010000101111111010100001100000001110001100111001101E30", 2, MPFR_RNDN); mpfr_clear_overflow (); mpfr_exp (x, x, MPFR_RNDD); if (!mpfr_overflow_p ()) { printf ("Wrong overflow detection in mpfr_exp_3\n"); mpfr_dump (x); exit (1); } /* Check underflow. Corner case of mpfr_exp_3 */ mpfr_set_str (x, "-0.1011000101110010000101111111011111010001110011110111100110101100E30", 2, MPFR_RNDN); mpfr_clear_underflow (); mpfr_exp (x, x, MPFR_RNDN); if (!mpfr_underflow_p ()) { printf ("Wrong underflow detection in mpfr_exp_3\n"); mpfr_dump (x); exit (1); } mpfr_set_prec (x, 53); } /* check overflow */ set_emax (10); mpfr_set_ui (x, 7, MPFR_RNDN); test_exp (y, x, MPFR_RNDN); if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0) { printf ("Error for exp(7) for emax=10\n"); exit (1); } set_emax (emax); /* check underflow */ set_emin (-10); mpfr_set_si (x, -9, MPFR_RNDN); test_exp (y, x, MPFR_RNDN); if (mpfr_cmp_ui (y, 0) || mpfr_sgn (y) < 0) { printf ("Error for exp(-9) for emin=-10\n"); printf ("Expected +0\n"); printf ("Got "); mpfr_print_binary (y); puts (""); exit (1); } set_emin (emin); /* check case EXP(x) < -precy */ mpfr_set_prec (y, 2); mpfr_set_str_binary (x, "-0.1E-3"); test_exp (y, x, MPFR_RNDD); if (mpfr_cmp_ui_2exp (y, 3, -2)) { printf ("Error for exp(-1/16), prec=2, RNDD\n"); printf ("expected 0.11, got "); mpfr_dump (y); exit (1); } test_exp (y, x, MPFR_RNDZ); if (mpfr_cmp_ui_2exp (y, 3, -2)) { printf ("Error for exp(-1/16), prec=2, RNDZ\n"); printf ("expected 0.11, got "); mpfr_dump (y); exit (1); } mpfr_set_str_binary (x, "0.1E-3"); test_exp (y, x, MPFR_RNDN); if (mpfr_cmp_ui (y, 1)) { printf ("Error for exp(1/16), prec=2, RNDN\n"); exit (1); } test_exp (y, x, MPFR_RNDU); if (mpfr_cmp_ui_2exp (y, 3, -1)) { printf ("Error for exp(1/16), prec=2, RNDU\n"); exit (1); } /* bug reported by Franky Backeljauw, 28 Mar 2003 */ mpfr_set_prec (x, 53); mpfr_set_prec (y, 53); mpfr_set_str_binary (x, "1.1101011000111101011110000111010010101001101001110111e28"); test_exp (y, x, MPFR_RNDN); mpfr_set_prec (x, 153); mpfr_set_prec (z, 153); mpfr_set_str_binary (x, "1.1101011000111101011110000111010010101001101001110111e28"); test_exp (z, x, MPFR_RNDN); mpfr_prec_round (z, 53, MPFR_RNDN); if (mpfr_cmp (y, z)) { printf ("Error in mpfr_exp for large argument\n"); exit (1); } /* corner cases in mpfr_exp_3 */ mpfr_set_prec (x, 2); mpfr_set_ui (x, 1, MPFR_RNDN); mpfr_set_prec (y, 2); mpfr_exp_3 (y, x, MPFR_RNDN); /* Check some little things about overflow detection */ set_emin (-125); set_emax (128); mpfr_set_prec (x, 107); mpfr_set_prec (y, 107); mpfr_set_str_binary (x, "0.11110000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000" "00000000E4"); test_exp (y, x, MPFR_RNDN); if (mpfr_cmp_str (y, "0.11000111100001100110010101111101011010010101010000" "1101110111100010111001011111111000110111001011001101010" "01E22", 2, MPFR_RNDN)) { printf ("Special overflow error (1)\n"); mpfr_dump (y); exit (1); } set_emin (emin); set_emax (emax); /* Check for overflow producing a segfault with HUGE exponent */ mpfr_set_ui (x, 3, MPFR_RNDN); mpfr_mul_2ui (x, x, 32, MPFR_RNDN); test_exp (y, x, MPFR_RNDN); /* Can't test return value: May overflow or not*/ /* Bug due to wrong approximation of (x)/log2 */ mpfr_set_prec (x, 163); mpfr_set_str (x, "-4.28ac8fceeadcda06bb56359017b1c81b85b392e7", 16, MPFR_RNDN); mpfr_exp (x, x, MPFR_RNDN); if (mpfr_cmp_str (x, "3.fffffffffffffffffffffffffffffffffffffffe8@-2", 16, MPFR_RNDN)) { printf ("Error for x= -4.28ac8fceeadcda06bb56359017b1c81b85b392e7"); printf ("expected 3.fffffffffffffffffffffffffffffffffffffffe8@-2"); printf ("Got "); mpfr_out_str (stdout, 16, 0, x, MPFR_RNDN); putchar ('\n'); } /* bug found by Guillaume Melquiond, 13 Sep 2005 */ mpfr_set_prec (x, 53); mpfr_set_str_binary (x, "-1E-400"); mpfr_exp (x, x, MPFR_RNDZ); if (mpfr_cmp_ui (x, 1) == 0) { printf ("Error for exp(-2^(-400))\n"); exit (1); } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); }
static void check_special () { mpfr_t x, y, z; mp_exp_t emin, emax; mpfr_init (x); mpfr_init (y); mpfr_init (z); /* check exp(NaN) = NaN */ mpfr_set_nan (x); mpfr_exp (y, x, GMP_RNDN); if (!mpfr_nan_p (y)) { printf ("Error for exp(NaN)\n"); exit (1); } /* check exp(+inf) = +inf */ mpfr_set_inf (x, 1); mpfr_exp (y, x, GMP_RNDN); if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0) { printf ("Error for exp(+inf)\n"); exit (1); } /* check exp(-inf) = +0 */ mpfr_set_inf (x, -1); mpfr_exp (y, x, GMP_RNDN); if (mpfr_cmp_ui (y, 0) || mpfr_sgn (y) < 0) { printf ("Error for exp(-inf)\n"); exit (1); } /* check overflow */ emax = mpfr_get_emax (); set_emax (10); mpfr_set_ui (x, 7, GMP_RNDN); mpfr_exp (y, x, GMP_RNDN); if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0) { printf ("Error for exp(7) for emax=10\n"); exit (1); } set_emax (emax); /* check underflow */ emin = mpfr_get_emin (); set_emin (-10); mpfr_set_si (x, -9, GMP_RNDN); mpfr_exp (y, x, GMP_RNDN); if (mpfr_cmp_ui (y, 0) || mpfr_sgn (y) < 0) { printf ("Error for exp(-9) for emin=-10\n"); printf ("Expected +0\n"); printf ("Got "); mpfr_print_binary (y); puts (""); exit (1); } set_emin (emin); /* check case EXP(x) < -precy */ mpfr_set_prec (y, 2); mpfr_set_str_binary (x, "-0.1E-3"); mpfr_exp (y, x, GMP_RNDD); if (mpfr_cmp_ui_2exp (y, 3, -2)) { printf ("Error for exp(-1/16), prec=2, RNDD\n"); exit (1); } mpfr_exp (y, x, GMP_RNDZ); if (mpfr_cmp_ui (y, 1)) { printf ("Error for exp(-1/16), prec=2, RNDZ\n"); exit (1); } mpfr_set_str_binary (x, "0.1E-3"); mpfr_exp (y, x, GMP_RNDN); if (mpfr_cmp_ui (y, 1)) { printf ("Error for exp(1/16), prec=2, RNDN\n"); exit (1); } mpfr_exp (y, x, GMP_RNDU); if (mpfr_cmp_ui_2exp (y, 3, -1)) { printf ("Error for exp(1/16), prec=2, RNDU\n"); exit (1); } /* bug reported by Franky Backeljauw, 28 Mar 2003 */ mpfr_set_prec (x, 53); mpfr_set_prec (y, 53); mpfr_set_str_binary (x, "1.1101011000111101011110000111010010101001101001110111e28"); mpfr_exp (y, x, GMP_RNDN); mpfr_set_prec (x, 153); mpfr_set_prec (z, 153); mpfr_set_str_binary (x, "1.1101011000111101011110000111010010101001101001110111e28"); mpfr_exp (z, x, GMP_RNDN); mpfr_prec_round (z, 53, GMP_RNDN); if (mpfr_cmp (y, z)) { printf ("Error in mpfr_exp for large argument\n"); exit (1); } /* corner cases in mpfr_exp_3 */ mpfr_set_prec (x, 2); mpfr_set_ui (x, 1, GMP_RNDN); mpfr_set_prec (y, 2); mpfr_exp_3 (y, x, GMP_RNDN); /* Check some little things about overflow detection */ set_emin (-125); set_emax (128); mpfr_set_prec (x, 107); mpfr_set_prec (y, 107); mpfr_set_str_binary (x, "0.11110000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000" "00000000E4"); mpfr_exp (y, x, GMP_RNDN); if (mpfr_cmp_str (y, "0.11000111100001100110010101111101011010010101010000" "1101110111100010111001011111111000110111001011001101010" "01E22", 2, GMP_RNDN)) { printf ("Special overflow error (1)\n"); mpfr_dump (y); exit (1); } set_emin (MPFR_EMIN_MIN); set_emax (MPFR_EMAX_MAX); /* Check for overflow producing a segfault with HUGE exponent */ mpfr_set_ui (x, 3, GMP_RNDN); mpfr_mul_2ui (x, x, 32, GMP_RNDN); mpfr_exp (y, x, GMP_RNDN); /* Can't test return value: May overflow or not*/ mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); }
/* 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_set_prec (x, 118); mpfr_set_str_binary (x, "0.1110010100011101010000111110011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E-86"); mpfr_set_prec (y, 118); mpfr_exp_2 (y, x, MPFR_RNDU); mpfr_exp_3 (x, x, MPFR_RNDU); if (mpfr_cmp (x, y)) { printf ("mpfr_exp_2 and mpfr_exp_3 differ for prec=118\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_clear (x); mpfr_clear (y); return 0; }