int main (int argc, char *argv[]) { mp_size_t s; mpz_t z; mpfr_prec_t p; mpfr_t x, y, t, u, v; int r; int inexact, sign_t; tests_start_mpfr (); mpfr_init (x); mpfr_init (y); mpz_init (z); mpfr_init (t); mpfr_init (u); mpfr_init (v); mpz_set_ui (z, 1); for (s = 2; s < 100; s++) { /* z has exactly s bits */ mpz_mul_2exp (z, z, 1); if (randlimb () % 2) mpz_add_ui (z, z, 1); mpfr_set_prec (x, s); mpfr_set_prec (t, s); mpfr_set_prec (u, s); if (mpfr_set_z (x, z, MPFR_RNDN)) { printf ("Error: mpfr_set_z should be exact (s = %u)\n", (unsigned int) s); exit (1); } if (randlimb () % 2) mpfr_neg (x, x, MPFR_RNDN); if (randlimb () % 2) mpfr_div_2ui (x, x, randlimb () % s, MPFR_RNDN); for (p = 2; p < 100; p++) { int trint; mpfr_set_prec (y, p); mpfr_set_prec (v, p); for (r = 0; r < MPFR_RND_MAX ; r++) for (trint = 0; trint < 3; trint++) { if (trint == 2) inexact = mpfr_rint (y, x, (mpfr_rnd_t) r); else if (r == MPFR_RNDN) inexact = mpfr_round (y, x); else if (r == MPFR_RNDZ) inexact = (trint ? mpfr_trunc (y, x) : mpfr_rint_trunc (y, x, MPFR_RNDZ)); else if (r == MPFR_RNDU) inexact = (trint ? mpfr_ceil (y, x) : mpfr_rint_ceil (y, x, MPFR_RNDU)); else /* r = MPFR_RNDD */ inexact = (trint ? mpfr_floor (y, x) : mpfr_rint_floor (y, x, MPFR_RNDD)); if (mpfr_sub (t, y, x, MPFR_RNDN)) err ("subtraction 1 should be exact", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); sign_t = mpfr_cmp_ui (t, 0); if (trint != 0 && (((inexact == 0) && (sign_t != 0)) || ((inexact < 0) && (sign_t >= 0)) || ((inexact > 0) && (sign_t <= 0)))) err ("wrong inexact flag", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); if (inexact == 0) continue; /* end of the test for exact results */ if (((r == MPFR_RNDD || (r == MPFR_RNDZ && MPFR_SIGN (x) > 0)) && inexact > 0) || ((r == MPFR_RNDU || (r == MPFR_RNDZ && MPFR_SIGN (x) < 0)) && inexact < 0)) err ("wrong rounding direction", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); if (inexact < 0) { mpfr_add_ui (v, y, 1, MPFR_RNDU); if (mpfr_cmp (v, x) <= 0) err ("representable integer between x and its " "rounded value", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); } else { mpfr_sub_ui (v, y, 1, MPFR_RNDD); if (mpfr_cmp (v, x) >= 0) err ("representable integer between x and its " "rounded value", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); } if (r == MPFR_RNDN) { int cmp; if (mpfr_sub (u, v, x, MPFR_RNDN)) err ("subtraction 2 should be exact", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); cmp = mpfr_cmp_abs (t, u); if (cmp > 0) err ("faithful rounding, but not the nearest integer", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); if (cmp < 0) continue; /* |t| = |u|: x is the middle of two consecutive representable integers. */ if (trint == 2) { /* halfway case for mpfr_rint in MPFR_RNDN rounding mode: round to an even integer or significand. */ mpfr_div_2ui (y, y, 1, MPFR_RNDZ); if (!mpfr_integer_p (y)) err ("halfway case for mpfr_rint, result isn't an" " even integer", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); /* If floor(x) and ceil(x) aren't both representable integers, the significand must be even. */ mpfr_sub (v, v, y, MPFR_RNDN); mpfr_abs (v, v, MPFR_RNDN); if (mpfr_cmp_ui (v, 1) != 0) { mpfr_div_2si (y, y, MPFR_EXP (y) - MPFR_PREC (y) + 1, MPFR_RNDN); if (!mpfr_integer_p (y)) err ("halfway case for mpfr_rint, significand isn't" " even", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); } } else { /* halfway case for mpfr_round: x must have been rounded away from zero. */ if ((MPFR_SIGN (x) > 0 && inexact < 0) || (MPFR_SIGN (x) < 0 && inexact > 0)) err ("halfway case for mpfr_round, bad rounding" " direction", s, x, y, p, (mpfr_rnd_t) r, trint, inexact); } } } } } mpfr_clear (x); mpfr_clear (y); mpz_clear (z); mpfr_clear (t); mpfr_clear (u); mpfr_clear (v); special (); coverage_03032011 (); #if __MPFR_STDC (199901L) if (argc > 1 && strcmp (argv[1], "-s") == 0) test_against_libc (); #endif tests_end_mpfr (); return 0; }
void check_inexact (void) { mpfr_t x, y, z, u; mp_prec_t px, py, pu, pz; int inexact, cmp; mp_rnd_t rnd; mpfr_init (x); mpfr_init (y); mpfr_init (z); mpfr_init (u); mpfr_set_prec (x, 2); mpfr_set_str_raw (x, "0.1E-4"); mpfr_set_prec (u, 33); mpfr_set_str_raw (u, "0.101110100101101100000000111100000E-1"); mpfr_set_prec (y, 31); if ((inexact = mpfr_add (y, x, u, GMP_RNDN))) { fprintf (stderr, "Wrong inexact flag (2): expected 0, got %d\n", inexact); exit (1); } mpfr_set_prec (x, 2); mpfr_set_str_raw (x, "0.1E-4"); mpfr_set_prec (u, 33); mpfr_set_str_raw (u, "0.101110100101101100000000111100000E-1"); mpfr_set_prec (y, 28); if ((inexact = mpfr_add (y, x, u, GMP_RNDN))) { fprintf (stderr, "Wrong inexact flag (1): expected 0, got %d\n", inexact); exit (1); } for (px=2; px<MAX_PREC; px++) { mpfr_set_prec (x, px); mpfr_random (x); for (pu=2; pu<MAX_PREC; pu++) { mpfr_set_prec (u, pu); mpfr_random (u); for (py=2; py<MAX_PREC; py++) { mpfr_set_prec (y, py); pz = (mpfr_cmp_abs (x, u) >= 0) ? MPFR_EXP(x)-MPFR_EXP(u) : MPFR_EXP(u)-MPFR_EXP(x); /* x + u is exactly representable with precision abs(EXP(x)-EXP(u)) + max(prec(x), prec(u)) + 1 */ pz = pz + MAX(MPFR_PREC(x), MPFR_PREC(u)) + 1; mpfr_set_prec (z, pz); rnd = LONG_RAND () % 4; if (mpfr_add (z, x, u, rnd)) { fprintf (stderr, "z <- x + u should be exact\n"); printf ("x="); mpfr_print_binary (x); putchar ('\n'); printf ("u="); mpfr_print_binary (u); putchar ('\n'); printf ("z="); mpfr_print_binary (z); putchar ('\n'); exit (1); } for (rnd=0; rnd<4; rnd++) { inexact = mpfr_add (y, x, u, rnd); cmp = mpfr_cmp (y, z); if (((inexact == 0) && (cmp != 0)) || ((inexact > 0) && (cmp <= 0)) || ((inexact < 0) && (cmp >= 0))) { fprintf (stderr, "Wrong inexact flag for rnd=%s\n", mpfr_print_rnd_mode(rnd)); printf ("expected %d, got %d\n", cmp, inexact); printf ("x="); mpfr_print_binary (x); putchar ('\n'); printf ("u="); mpfr_print_binary (u); putchar ('\n'); printf ("y= "); mpfr_print_binary (y); putchar ('\n'); printf ("x+u="); mpfr_print_binary (z); putchar ('\n'); exit (1); } } } } } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); mpfr_clear (u); }
/* The computation of z = pow(x,y) is done by z = exp(y * log(x)) = x^y */ int mpfr_pow (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) { int inexact = 0; if (MPFR_IS_NAN(x) || MPFR_IS_NAN(y)) { MPFR_SET_NAN(z); MPFR_RET_NAN; } if (MPFR_IS_INF(y)) { mpfr_t one; int cmp; if (MPFR_SIGN(y) > 0) { if (MPFR_IS_INF(x)) { MPFR_CLEAR_FLAGS(z); if (MPFR_SIGN(x) > 0) MPFR_SET_INF(z); else MPFR_SET_ZERO(z); MPFR_SET_POS(z); MPFR_RET(0); } MPFR_CLEAR_FLAGS(z); if (MPFR_IS_ZERO(x)) { MPFR_SET_ZERO(z); MPFR_SET_POS(z); MPFR_RET(0); } mpfr_init2(one, BITS_PER_MP_LIMB); mpfr_set_ui(one, 1, GMP_RNDN); cmp = mpfr_cmp_abs(x, one); mpfr_clear(one); if (cmp > 0) { MPFR_SET_INF(z); MPFR_SET_POS(z); MPFR_RET(0); } else if (cmp < 0) { MPFR_SET_ZERO(z); MPFR_SET_POS(z); MPFR_RET(0); } else { MPFR_SET_NAN(z); MPFR_RET_NAN; } } else { if (MPFR_IS_INF(x)) { MPFR_CLEAR_FLAGS(z); if (MPFR_SIGN(x) > 0) MPFR_SET_ZERO(z); else MPFR_SET_INF(z); MPFR_SET_POS(z); MPFR_RET(0); } if (MPFR_IS_ZERO(x)) { MPFR_SET_INF(z); MPFR_SET_POS(z); MPFR_RET(0); } mpfr_init2(one, BITS_PER_MP_LIMB); mpfr_set_ui(one, 1, GMP_RNDN); cmp = mpfr_cmp_abs(x, one); mpfr_clear(one); MPFR_CLEAR_FLAGS(z); if (cmp > 0) { MPFR_SET_ZERO(z); MPFR_SET_POS(z); MPFR_RET(0); } else if (cmp < 0) { MPFR_SET_INF(z); MPFR_SET_POS(z); MPFR_RET(0); } else { MPFR_SET_NAN(z); MPFR_RET_NAN; } } } if (MPFR_IS_ZERO(y)) { return mpfr_set_ui (z, 1, GMP_RNDN); } if (mpfr_isinteger (y)) { mpz_t zi; long int zii; int exptol; mpz_init(zi); exptol = mpfr_get_z_exp (zi, y); if (exptol>0) mpz_mul_2exp(zi, zi, exptol); else mpz_tdiv_q_2exp(zi, zi, (unsigned long int) (-exptol)); zii=mpz_get_ui(zi); mpz_clear(zi); return mpfr_pow_si (z, x, zii, rnd_mode); } if (MPFR_IS_INF(x)) { if (MPFR_SIGN(x) > 0) { MPFR_CLEAR_FLAGS(z); if (MPFR_SIGN(y) > 0) MPFR_SET_INF(z); else MPFR_SET_ZERO(z); MPFR_SET_POS(z); MPFR_RET(0); } else { MPFR_SET_NAN(z); MPFR_RET_NAN; } } if (MPFR_IS_ZERO(x)) { MPFR_CLEAR_FLAGS(z); MPFR_SET_ZERO(z); MPFR_SET_SAME_SIGN(z, x); MPFR_RET(0); } if (MPFR_SIGN(x) < 0) { MPFR_SET_NAN(z); MPFR_RET_NAN; } MPFR_CLEAR_FLAGS(z); /* General case */ { /* Declaration of the intermediary variable */ mpfr_t t, te, ti; int loop = 0, ok; /* Declaration of the size variable */ mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ mp_prec_t Nt; /* Precision of the intermediary variable */ long int err; /* Precision of error */ /* compute the precision of intermediary variable */ Nt=MAX(Nx,Ny); /* the optimal number of bits : see algorithms.ps */ Nt=Nt+5+_mpfr_ceil_log2(Nt); /* initialise of intermediary variable */ mpfr_init(t); mpfr_init(ti); mpfr_init(te); do { loop ++; /* reactualisation of the precision */ mpfr_set_prec (t, Nt); mpfr_set_prec (ti, Nt); mpfr_set_prec (te, Nt); /* compute exp(y*ln(x)) */ mpfr_log (ti, x, GMP_RNDU); /* ln(n) */ mpfr_mul (te, y, ti, GMP_RNDU); /* y*ln(n) */ mpfr_exp (t, te, GMP_RNDN); /* exp(x*ln(n))*/ /* estimation of the error -- see pow function in algorithms.ps*/ err = Nt - (MPFR_EXP(te) + 3); /* actualisation of the precision */ Nt += 10; ok = mpfr_can_round (t, err, GMP_RNDN, rnd_mode, Ny); /* check exact power */ if (ok == 0 && loop == 1) ok = mpfr_pow_is_exact (x, y); } while (err < 0 || ok == 0); inexact = mpfr_set (z, t, rnd_mode); mpfr_clear (t); mpfr_clear (ti); mpfr_clear (te); } return inexact; }