MPFR_COLD_FUNCTION_ATTR int mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign) { int inex; MPFR_LOG_FUNC (("x[%Pu]=%.*Rg rnd=%d sign=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode, sign), ("x[%Pu]=%.*Rg", mpfr_get_prec (x), mpfr_log_prec, x)); MPFR_ASSERT_SIGN (sign); if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0)) { MPFR_SET_ZERO(x); inex = -1; } else { mpfr_setmin (x, __gmpfr_emin); inex = 1; } MPFR_SET_SIGN(x, sign); __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW; return sign > 0 ? inex : -inex; }
static void check_emin_aux (mpfr_exp_t e) { mpfr_t x; char *s1, s2[256]; int i; mpfr_exp_t emin; mpz_t ee; MPFR_ASSERTN (e >= LONG_MIN); emin = mpfr_get_emin (); set_emin (e); mpfr_init2 (x, 16); mpz_init (ee); mpfr_setmin (x, e); mpz_set_si (ee, e); mpz_sub_ui (ee, ee, 1); i = mpfr_asprintf (&s1, "%Ra", x); MPFR_ASSERTN (i > 0); gmp_snprintf (s2, 256, "0x1p%Zd", ee); if (strcmp (s1, s2) != 0) { printf ("Error in check_emin_aux for emin = %ld\n", (long) e); printf ("Expected %s\n", s2); printf ("Got %s\n", s1); exit (1); } mpfr_free_str (s1); i = mpfr_asprintf (&s1, "%Rb", x); MPFR_ASSERTN (i > 0); gmp_snprintf (s2, 256, "1p%Zd", ee); if (strcmp (s1, s2) != 0) { printf ("Error in check_emin_aux for emin = %ld\n", (long) e); printf ("Expected %s\n", s2); printf ("Got %s\n", s1); exit (1); } mpfr_free_str (s1); mpfr_clear (x); mpz_clear (ee); set_emin (emin); }
/* TODO: A test with more inputs (but can't be compared to mpfr_add). */ static void check_extreme (void) { mpfr_t u, v, w, x, y; mpfr_ptr t[2]; int i, inex1, inex2, r; t[0] = u; t[1] = v; mpfr_inits2 (32, u, v, w, x, y, (mpfr_ptr) 0); mpfr_setmin (u, mpfr_get_emax ()); mpfr_setmax (v, mpfr_get_emin ()); mpfr_setmin (w, mpfr_get_emax () - 40); RND_LOOP (r) for (i = 0; i < 2; i++) { mpfr_set_prec (x, 64); inex1 = mpfr_add (x, u, w, MPFR_RNDN); MPFR_ASSERTN (inex1 == 0); inex1 = mpfr_prec_round (x, 32, (mpfr_rnd_t) r); inex2 = mpfr_sum (y, t, 2, (mpfr_rnd_t) r); if (!(mpfr_equal_p (x, y) && SAME_SIGN (inex1, inex2))) { printf ("Error in check_extreme (%s, i = %d)\n", mpfr_print_rnd_mode ((mpfr_rnd_t) r), i); printf ("Expected "); mpfr_dump (x); printf ("with inex = %d\n", inex1); printf ("Got "); mpfr_dump (y); printf ("with inex = %d\n", inex2); exit (1); } mpfr_neg (v, v, MPFR_RNDN); mpfr_neg (w, w, MPFR_RNDN); } mpfr_clears (u, v, w, x, y, (mpfr_ptr) 0); }
static int my_setstr (mpfr_ptr t, const char *s) { if (strcmp (s, "min") == 0) { mpfr_setmin (t, mpfr_get_emin ()); MPFR_SET_POS (t); return 0; } if (strcmp (s, "min+") == 0) { mpfr_setmin (t, mpfr_get_emin ()); MPFR_SET_POS (t); mpfr_nextabove (t); return 0; } if (strcmp (s, "max") == 0) { mpfr_setmax (t, mpfr_get_emax ()); MPFR_SET_POS (t); return 0; } return mpfr_set_str (t, s, 10, MPFR_RNDN); }
int mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign) { int inex; MPFR_ASSERT_SIGN (sign); if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0)) { MPFR_SET_ZERO(x); inex = -1; } else { mpfr_setmin (x, __gmpfr_emin); inex = 1; } MPFR_SET_SIGN(x, sign); __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW; return sign > 0 ? inex : -inex; }
int mpfr_underflow (mpfr_ptr x, mp_rnd_t rnd_mode, int sign) { int inex; MPFR_ASSERT_SIGN (sign); if (rnd_mode == GMP_RNDN || MPFR_IS_RNDUTEST_OR_RNDDNOTTEST(rnd_mode, MPFR_IS_POS_SIGN (sign))) { mpfr_setmin (x, __gmpfr_emin); inex = 1; } else { MPFR_SET_ZERO(x); inex = -1; } MPFR_SET_SIGN(x, sign); __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW; return sign > 0 ? inex : -inex; }
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 test_underflow1 (void) { mpfr_t x, y, z, r; int inex, signy, signz, rnd, err = 0; mpfr_inits2 (8, x, y, z, r, (void *) 0); MPFR_SET_POS (x); mpfr_setmin (x, mpfr_get_emin ()); /* x = 0.1@emin */ for (signy = -1; signy <= 1; signy += 2) { mpfr_set_si_2exp (y, signy, -1, GMP_RNDN); /* |y| = 1/2 */ for (signz = -3; signz <= 3; signz += 2) { RND_LOOP (rnd) { mpfr_set_si (z, signz, GMP_RNDN); if (ABS (signz) != 1) mpfr_setmax (z, mpfr_get_emax ()); /* |z| = 1 or 2^emax - ulp */ mpfr_clear_flags (); inex = mpfr_fma (r, x, y, z, rnd); #define ERRTU1 "Error in test_underflow1 (signy = %d, signz = %d, %s)\n " if (mpfr_nanflag_p ()) { printf (ERRTU1 "NaN flag is set\n", signy, signz, mpfr_print_rnd_mode (rnd)); err = 1; } if (signy < 0 && (rnd == GMP_RNDD || (rnd == GMP_RNDZ && signz > 0))) mpfr_nextbelow (z); if (signy > 0 && (rnd == GMP_RNDU || (rnd == GMP_RNDZ && signz < 0))) mpfr_nextabove (z); if ((mpfr_overflow_p () != 0) ^ (mpfr_inf_p (z) != 0)) { printf (ERRTU1 "wrong overflow flag\n", signy, signz, mpfr_print_rnd_mode (rnd)); err = 1; } if (mpfr_underflow_p ()) { printf (ERRTU1 "underflow flag is set\n", signy, signz, mpfr_print_rnd_mode (rnd)); err = 1; } if (! mpfr_equal_p (r, z)) { printf (ERRTU1 "got ", signy, signz, mpfr_print_rnd_mode (rnd)); mpfr_print_binary (r); printf (" instead of "); mpfr_print_binary (z); printf ("\n"); err = 1; } if (inex >= 0 && (rnd == GMP_RNDD || (rnd == GMP_RNDZ && signz > 0) || (rnd == GMP_RNDN && signy > 0))) { printf (ERRTU1 "ternary value = %d instead of < 0\n", signy, signz, mpfr_print_rnd_mode (rnd), inex); err = 1; } if (inex <= 0 && (rnd == GMP_RNDU || (rnd == GMP_RNDZ && signz < 0) || (rnd == GMP_RNDN && signy < 0))) { printf (ERRTU1 "ternary value = %d instead of > 0\n", signy, signz, mpfr_print_rnd_mode (rnd), inex); err = 1; } } } } if (err) exit (1); mpfr_clears (x, y, z, r, (void *) 0); }
static void test_overflow2 (void) { mpfr_t x, y, z, r; int i, inex, rnd, err = 0; mpfr_inits2 (8, x, y, z, r, (void *) 0); MPFR_SET_POS (x); mpfr_setmin (x, mpfr_get_emax ()); /* x = 0.1@emax */ mpfr_set_si (y, -2, GMP_RNDN); /* y = -2 */ /* The intermediate multiplication x * y will overflow. */ for (i = -9; i <= 9; i++) RND_LOOP (rnd) { int inf, overflow; inf = rnd == GMP_RNDN || rnd == GMP_RNDD; overflow = inf || i <= 0; inex = mpfr_set_si_2exp (z, i, mpfr_get_emin (), GMP_RNDN); MPFR_ASSERTN (inex == 0); mpfr_clear_flags (); /* One has: x * y = -1@emax exactly (but not representable). */ inex = mpfr_fma (r, x, y, z, rnd); if (overflow ^ (mpfr_overflow_p () != 0)) { printf ("Error in test_overflow2 (i = %d, %s): wrong overflow" " flag (should be %d)\n", i, mpfr_print_rnd_mode (rnd), overflow); err = 1; } if (mpfr_nanflag_p ()) { printf ("Error in test_overflow2 (i = %d, %s): NaN flag should" " not be set\n", i, mpfr_print_rnd_mode (rnd)); err = 1; } if (mpfr_nan_p (r)) { printf ("Error in test_overflow2 (i = %d, %s): got NaN\n", i, mpfr_print_rnd_mode (rnd)); err = 1; } else if (MPFR_SIGN (r) >= 0) { printf ("Error in test_overflow2 (i = %d, %s): wrong sign " "(+ instead of -)\n", i, mpfr_print_rnd_mode (rnd)); err = 1; } else if (inf && ! mpfr_inf_p (r)) { printf ("Error in test_overflow2 (i = %d, %s): expected -Inf," " got\n", i, mpfr_print_rnd_mode (rnd)); mpfr_dump (r); err = 1; } else if (!inf && (mpfr_inf_p (r) || (mpfr_nextbelow (r), ! mpfr_inf_p (r)))) { printf ("Error in test_overflow2 (i = %d, %s): expected -MAX," " got\n", i, mpfr_print_rnd_mode (rnd)); mpfr_dump (r); err = 1; } if (inf ? inex >= 0 : inex <= 0) { printf ("Error in test_overflow2 (i = %d, %s): wrong inexact" " flag (got %d)\n", i, mpfr_print_rnd_mode (rnd), inex); err = 1; } } if (err) exit (1); mpfr_clears (x, y, z, r, (void *) 0); }
static void test_extreme (void) { mpfr_t x, y, z; mpfr_exp_t emin, emax; mpfr_prec_t p[4] = { 8, 32, 64, 256 }; int xi, yi, zi, j, r; unsigned int flags, ex_flags; emin = mpfr_get_emin (); emax = mpfr_get_emax (); mpfr_set_emin (MPFR_EMIN_MIN); mpfr_set_emax (MPFR_EMAX_MAX); for (xi = 0; xi < 4; xi++) { mpfr_init2 (x, p[xi]); mpfr_setmax (x, MPFR_EMAX_MAX); MPFR_ASSERTN (mpfr_check (x)); for (yi = 0; yi < 4; yi++) { mpfr_init2 (y, p[yi]); mpfr_setmin (y, MPFR_EMIN_MIN); for (j = 0; j < 2; j++) { MPFR_ASSERTN (mpfr_check (y)); for (zi = 0; zi < 4; zi++) { mpfr_init2 (z, p[zi]); RND_LOOP (r) { mpfr_clear_flags (); mpfr_div (z, x, y, (mpfr_rnd_t) r); flags = __gmpfr_flags; MPFR_ASSERTN (mpfr_check (z)); ex_flags = MPFR_FLAGS_OVERFLOW | MPFR_FLAGS_INEXACT; if (flags != ex_flags) { printf ("Bad flags in test_extreme on z = a/b" " with %s and\n", mpfr_print_rnd_mode ((mpfr_rnd_t) r)); printf ("a = "); mpfr_dump (x); printf ("b = "); mpfr_dump (y); printf ("Expected flags:"); flags_out (ex_flags); printf ("Got flags: "); flags_out (flags); printf ("z = "); mpfr_dump (z); exit (1); } mpfr_clear_flags (); mpfr_div (z, y, x, (mpfr_rnd_t) r); flags = __gmpfr_flags; MPFR_ASSERTN (mpfr_check (z)); ex_flags = MPFR_FLAGS_UNDERFLOW | MPFR_FLAGS_INEXACT; if (flags != ex_flags) { printf ("Bad flags in test_extreme on z = a/b" " with %s and\n", mpfr_print_rnd_mode ((mpfr_rnd_t) r)); printf ("a = "); mpfr_dump (y); printf ("b = "); mpfr_dump (x); printf ("Expected flags:"); flags_out (ex_flags); printf ("Got flags: "); flags_out (flags); printf ("z = "); mpfr_dump (z); exit (1); } } mpfr_clear (z); } /* zi */ mpfr_nextabove (y); } /* j */ mpfr_clear (y); } /* yi */ mpfr_clear (x); } /* xi */ set_emin (emin); set_emax (emax); }