diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2017-10-09 11:39:32 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2017-10-09 11:39:32 +0000 |
commit | d3d5d5363383b3df052201ab53c711519000ab5d (patch) | |
tree | b34e4977b3e8013aafb7c4fc37519d50856dc712 | |
parent | 31259a4fabccd443cb09128969c1cbeda26f54d4 (diff) | |
download | mpfr-d3d5d5363383b3df052201ab53c711519000ab5d.tar.gz |
[src/get_z.c] Fixed failure in mpfr_get_z when called with a very
reduced exponent range.
[tests/tget_z.c] Added tests in the various rounding modes (triggering
a failure before the above fix). Also call check_one() on an integer
congruent to 1 mod 4 (useful to check even rounding). Fixed 2 issues
in the error message (for inex and the flags).
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@11777 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r-- | src/get_z.c | 10 | ||||
-rw-r--r-- | tests/tget_z.c | 155 |
2 files changed, 114 insertions, 51 deletions
diff --git a/src/get_z.c b/src/get_z.c index 32d3b684d..7eae0dc5b 100644 --- a/src/get_z.c +++ b/src/get_z.c @@ -29,6 +29,7 @@ mpfr_get_z (mpz_ptr z, mpfr_srcptr f, mpfr_rnd_t rnd) int inex; mpfr_t r; mpfr_exp_t exp; + MPFR_SAVE_EXPO_DECL (expo); if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (f))) { @@ -41,6 +42,8 @@ mpfr_get_z (mpz_ptr z, mpfr_srcptr f, mpfr_rnd_t rnd) return 0; } + MPFR_SAVE_EXPO_MARK (expo); + exp = MPFR_GET_EXP (f); /* if exp <= 0, then |f|<1, thus |o(f)|<=1 */ MPFR_ASSERTN (exp < 0 || exp <= MPFR_PREC_MAX); @@ -50,6 +53,11 @@ mpfr_get_z (mpz_ptr z, mpfr_srcptr f, mpfr_rnd_t rnd) MPFR_ASSERTN (inex != 1 && inex != -1); /* integral part of f is representable in r */ MPFR_ASSERTN (MPFR_IS_FP (r)); + + /* The flags from mpfr_rint are the wanted ones. In particular, + it sets the inexact flag when necessary. */ + MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags); + exp = mpfr_get_z_2exp (z, r); if (exp >= 0) mpz_mul_2exp (z, z, exp); @@ -57,5 +65,7 @@ mpfr_get_z (mpz_ptr z, mpfr_srcptr f, mpfr_rnd_t rnd) mpz_fdiv_q_2exp (z, z, -exp); mpfr_clear (r); + MPFR_SAVE_EXPO_FREE (expo); + return inex; } diff --git a/tests/tget_z.c b/tests/tget_z.c index 756e2674e..b5b368a5f 100644 --- a/tests/tget_z.c +++ b/tests/tget_z.c @@ -73,10 +73,10 @@ static void check_one (mpz_ptr z) { mpfr_exp_t emin, emax; - int inex, ex_inex, same; + int inex; int sh, neg; mpfr_t f; - mpz_t got, ex; + mpz_t got, ex, t; emin = mpfr_get_emin (); emax = mpfr_get_emax (); @@ -84,72 +84,121 @@ check_one (mpz_ptr z) mpfr_init2 (f, MAX (mpz_sizeinbase (z, 2), MPFR_PREC_MIN)); mpz_init (got); mpz_init (ex); + mpz_init (t); for (sh = -2*GMP_NUMB_BITS ; sh < 2*GMP_NUMB_BITS ; sh++) { inex = mpfr_set_z (f, z, MPFR_RNDN); /* exact */ MPFR_ASSERTN (inex == 0); - if (sh < 0) - { - mpz_tdiv_q_2exp (ex, z, -sh); - inex = mpfr_div_2exp (f, f, -sh, MPFR_RNDN); - } - else - { - mpz_mul_2exp (ex, z, sh); - inex = mpfr_mul_2exp (f, f, sh, MPFR_RNDN); - } + inex = sh < 0 ? + mpfr_div_2exp (f, f, -sh, MPFR_RNDN) : + mpfr_mul_2exp (f, f, sh, MPFR_RNDN); MPFR_ASSERTN (inex == 0); for (neg = 0; neg <= 1; neg++) { - /* Test (-1)^neg * z * 2^sh */ - int fi, e; - mpfr_flags_t flags[3] = { 0, MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE, - MPFR_FLAGS_ALL }, ex_flags, gt_flags; + int rnd; - ex_inex = - mpfr_cmp_z (f, ex); + /* Test (-1)^neg * z * 2^sh */ - for (fi = 0; fi < numberof (flags); fi++) - for (e = 0; e < 2; e++) - { - if (e) + RND_LOOP_NO_RNDF (rnd) + { + int ex_inex, same; + int d, fi, e; + mpfr_flags_t flags[3] = { 0, MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE, + MPFR_FLAGS_ALL }, ex_flags, gt_flags; + + if (neg) + mpz_neg (ex, z); + else + mpz_set (ex, z); + + if (sh < 0) + switch (rnd) { - mpfr_exp_t ef; - - if (MPFR_IS_ZERO (f)) - break; - ef = MPFR_GET_EXP (f); - set_emin (ef); - set_emax (ef); + case MPFR_RNDN: + mpz_set_si (t, neg ? -1 : 1); + mpz_mul_2exp (t, t, -sh - 1); + mpz_add (ex, ex, t); + d = mpz_divisible_2exp_p (ex, -sh); + mpz_tdiv_q_2exp (ex, ex, -sh); + if (d && mpz_tstbit (ex, 0) != 0) /* even rounding */ + { + if (neg) + mpz_add_ui (ex, ex, 1); + else + mpz_sub_ui (ex, ex, 1); + } + break; + case MPFR_RNDZ: + mpz_tdiv_q_2exp (ex, ex, -sh); + break; + case MPFR_RNDU: + mpz_cdiv_q_2exp (ex, ex, -sh); + break; + case MPFR_RNDD: + mpz_fdiv_q_2exp (ex, ex, -sh); + break; + case MPFR_RNDA: + if (neg) + mpz_fdiv_q_2exp (ex, ex, -sh); + else + mpz_cdiv_q_2exp (ex, ex, -sh); + break; + default: + MPFR_ASSERTN (0); } - ex_flags = __gmpfr_flags = flags[fi]; - if (ex_inex != 0) - ex_flags |= MPFR_FLAGS_INEXACT; - inex = mpfr_get_z (got, f, MPFR_RNDZ); - gt_flags = __gmpfr_flags; - set_emin (emin); - set_emax (emax); - same = SAME_SIGN (inex, ex_inex); - - if (mpz_cmp (got, ex) != 0 || !same || gt_flags != ex_flags) + else + mpz_mul_2exp (ex, ex, sh); + + ex_inex = - mpfr_cmp_z (f, ex); + ex_inex = VSIGN (ex_inex); + + for (fi = 0; fi < numberof (flags); fi++) + for (e = 0; e < 2; e++) { - printf ("Error in check_one for sh=%d, fi=%d\n", sh, fi); - printf (" f = "); mpfr_dump (f); - printf ("expected "); mpz_dump (ex); - printf (" got "); mpz_dump (got); - printf ("Expected inex ~ %d, got %d (%s)\n", - inex, ex_inex, same ? "OK" : "wrong"); - printf ("Flags:\n"); - printf (" in"); flags_out (gt_flags); - printf ("expected"); flags_out (ex_flags); - printf (" got"); flags_out (gt_flags); - exit (1); + if (e) + { + mpfr_exp_t ef; + + if (MPFR_IS_ZERO (f)) + break; + ef = MPFR_GET_EXP (f); + set_emin (ef); + set_emax (ef); + } + ex_flags = __gmpfr_flags = flags[fi]; + if (ex_inex != 0) + ex_flags |= MPFR_FLAGS_INEXACT; + inex = mpfr_get_z (got, f, (mpfr_rnd_t) rnd); + inex = VSIGN (inex); + gt_flags = __gmpfr_flags; + set_emin (emin); + set_emax (emax); + same = SAME_SIGN (inex, ex_inex); + + if (mpz_cmp (got, ex) != 0 || + !same || gt_flags != ex_flags) + { + printf ("Error in check_one for sh=%d, fi=%d, %s%s\n", + sh, fi, + mpfr_print_rnd_mode ((mpfr_rnd_t) rnd), + e ? ", reduced exponent range" : ""); + printf (" f = "); mpfr_dump (f); + printf ("expected "); mpz_dump (ex); + printf (" got "); mpz_dump (got); + printf ("Expected inex ~ %d, got %d (%s)\n", + ex_inex, inex, same ? "OK" : "wrong"); + printf ("Flags:\n"); + printf (" in"); flags_out (flags[fi]); + printf ("expected"); flags_out (ex_flags); + printf (" got"); flags_out (gt_flags); + exit (1); + } } - } + } - mpz_neg (ex, ex); mpfr_neg (f, f, MPFR_RNDN); } } @@ -157,6 +206,7 @@ check_one (mpz_ptr z) mpfr_clear (f); mpz_clear (got); mpz_clear (ex); + mpz_clear (t); } static void @@ -169,6 +219,9 @@ check (void) mpz_set_ui (z, 0L); check_one (z); + mpz_set_si (z, 17L); + check_one (z); + mpz_set_si (z, 123L); check_one (z); |