summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2007-12-18 12:54:25 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2007-12-18 12:54:25 +0000
commit38d6b3c6caea92c4aecd48d9b8c254ad0b782ad2 (patch)
treef67867135f9b93fc8f2c561ff5ba3a10bcda1d53
parentf5117029cfeb842429871a6554fc6786eeac49f0 (diff)
downloadmpfr-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.c20
-rw-r--r--tests/tpow_z.c40
2 files changed, 49 insertions, 11 deletions
diff --git a/pow_z.c b/pow_z.c
index ab1efa6b6..23170b20e 100644
--- a/pow_z.c
+++ b/pow_z.c
@@ -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;