diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2007-12-18 12:54:25 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2007-12-18 12:54:25 +0000 |
commit | 38d6b3c6caea92c4aecd48d9b8c254ad0b782ad2 (patch) | |
tree | f67867135f9b93fc8f2c561ff5ba3a10bcda1d53 | |
parent | f5117029cfeb842429871a6554fc6786eeac49f0 (diff) | |
download | mpfr-38d6b3c6caea92c4aecd48d9b8c254ad0b782ad2.tar.gz |
Fixed bug in mpfr_pow_z: if x = y (same mpfr_t argument), the input
argument is negative and not a power of two, z is positive and odd,
an overflow or underflow occurs, and the temporary result res is
positive, then the result gets a wrong sign (positive instead of
negative). Testcase.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@5110 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r-- | pow_z.c | 20 | ||||
-rw-r--r-- | tests/tpow_z.c | 40 |
2 files changed, 49 insertions, 11 deletions
@@ -81,21 +81,19 @@ mpfr_pow_pos_z (mpfr_ptr y, mpfr_srcptr x, mpz_srcptr z, mp_rnd_t rnd) } MPFR_ZIV_FREE (loop); - inexact = mpfr_set (y, res, rnd); - mpfr_clear (res); - /* Check Overflow */ if (MPFR_UNLIKELY (mpfr_overflow_p ())) - return mpfr_overflow (y, rnd, - mpz_odd_p (absz) ? MPFR_SIGN (x) : MPFR_SIGN_POS); + inexact = mpfr_overflow (y, rnd, mpz_odd_p (absz) ? + MPFR_SIGN (x) : MPFR_SIGN_POS); /* Check Underflow */ else if (MPFR_UNLIKELY (mpfr_underflow_p ())) - { - if (rnd == GMP_RNDN) - rnd = GMP_RNDZ; - return mpfr_underflow (y, rnd, - mpz_odd_p (absz) ? MPFR_SIGN (x) : MPFR_SIGN_POS); - } + inexact = mpfr_underflow (y, rnd == GMP_RNDN ? GMP_RNDZ : rnd, + mpz_odd_p (absz) ? MPFR_SIGN (x) : + MPFR_SIGN_POS); + else + inexact = mpfr_set (y, res, rnd); + + mpfr_clear (res); return inexact; } diff --git a/tests/tpow_z.c b/tests/tpow_z.c index 0fb71ba19..d4da4ecbe 100644 --- a/tests/tpow_z.c +++ b/tests/tpow_z.c @@ -257,6 +257,45 @@ bug20071104 (void) mpz_clear (z); } +static void +check_overflow (void) +{ + mpfr_t a; + mpz_t z; + unsigned long n; + int res; + + mpfr_init2 (a, 53); + + mpfr_set_str_binary (a, "1E10"); + mpz_init_set_ui (z, ULONG_MAX); + res = mpfr_pow_z (a, a, z, GMP_RNDN); + if (!MPFR_IS_INF (a) || MPFR_SIGN (a) < 0) + { + printf ("Error for (1e10)^ULONG_MAX\n"); + exit (1); + } + + /* Bug in pow_z.c up to r5109: if x = y (same mpfr_t argument), the + input argument is negative and not a power of two, z is positive + and odd, an overflow or underflow occurs, and the temporary result + res is positive, then the result gets a wrong sign (positive + instead of negative). */ + mpfr_set_str_binary (a, "-1.1E10"); + n = (ULONG_MAX ^ (ULONG_MAX >> 1)) + 1; + mpz_set_ui (z, n); + res = mpfr_pow_z (a, a, z, GMP_RNDN); + if (!MPFR_IS_INF (a) || MPFR_SIGN (a) > 0) + { + printf ("Error for (-1e10)^%lu, expected -Inf,\ngot ", n); + mpfr_dump (a); + exit (1); + } + + mpfr_clear (a); + mpz_clear (z); +} + int main (void) { @@ -266,6 +305,7 @@ main (void) check_integer (2, 163, 100); check_regression (); bug20071104 (); + check_overflow (); tests_end_mpfr (); return 0; |