summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4>2004-04-07 14:19:44 +0000
committerzimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4>2004-04-07 14:19:44 +0000
commitc44bde008cebc99a76205f1329ac86fef8cf65c3 (patch)
tree86ed9bfe64d93338368f8b9e9f7c735cfec520c9
parenta7ed08d70837deee7ccb01c30e43efbba292f9f3 (diff)
downloadmpfr-c44bde008cebc99a76205f1329ac86fef8cf65c3.tar.gz
fixed problem when overflow in destination exponent happens
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@2862 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r--mpn_exp.c17
-rw-r--r--set_str.c8
-rw-r--r--tests/tset_str.c15
3 files changed, 35 insertions, 5 deletions
diff --git a/mpn_exp.c b/mpn_exp.c
index c11692744..b0bb88cb3 100644
--- a/mpn_exp.c
+++ b/mpn_exp.c
@@ -30,7 +30,10 @@ MA 02111-1307, USA. */
that is:
a*2^exp_r <= b^e <= 2^exp_r (a + 2^f),
where a represents {a, n}, i.e. the integer
- a[0] + a[1]*B + ... + a[n-1]*B^(n-1) where B=2^BITS_PER_MP_LIMB */
+ a[0] + a[1]*B + ... + a[n-1]*B^(n-1) where B=2^BITS_PER_MP_LIMB
+
+ Return -2 if an overflow occurred in the computation of exp_r.
+*/
long
mpfr_mpn_exp (mp_limb_t *a, mp_exp_t *exp_r, int b, mp_exp_t e, size_t n)
@@ -91,7 +94,17 @@ mpfr_mpn_exp (mp_limb_t *a, mp_exp_t *exp_r, int b, mp_exp_t e, size_t n)
/* set {c+n, 2n1-n} to 0 : {c, n} = {a, n}^2*K^n */
- f = 2 * f + n * BITS_PER_MP_LIMB;
+ /* check overflow on f */
+ {
+ mp_exp_t oldf = f;
+ f = 2 * f;
+ if (f / 2 != oldf)
+ {
+ TMP_FREE(marker);
+ return -2;
+ }
+ }
+ f += n * BITS_PER_MP_LIMB;
if ((c[2*n - 1] & MPFR_LIMB_HIGHBIT) == 0)
{
/* shift A by one bit to the left */
diff --git a/set_str.c b/set_str.c
index d99733791..0c574770e 100644
--- a/set_str.c
+++ b/set_str.c
@@ -269,6 +269,11 @@ mpfr_set_str (mpfr_t x, const char *str, int base, mp_rnd_t rnd)
/* z is allocated at y - n */
z = y - n;
err = mpfr_mpn_exp (z, &exp_z, base, exp_s - (mp_exp_t) pr, n);
+ if (err == -2) /* overflow in exp_z, return Inf */
+ {
+ exp_y = __mpfr_emax;
+ goto free;
+ }
exact = (exact && (err == -1));
/* multiply(y = 0.mant_s[0]...mant_s[pr-1])_base by base^(exp_s-g) */
@@ -363,6 +368,7 @@ mpfr_set_str (mpfr_t x, const char *str, int base, mp_rnd_t rnd)
exp_y ++;
}
+ free:
TMP_FREE(marker);
/* Set sign of x before exp since check_range needs a valid sign */
@@ -372,7 +378,7 @@ mpfr_set_str (mpfr_t x, const char *str, int base, mp_rnd_t rnd)
MPFR_SET_POS(x);
/* DO NOT USE MPFR_SET_EXP. The exp may be out of range! */
MPFR_EXP (x) = exp_y + n * BITS_PER_MP_LIMB;
- res = mpfr_check_range (x, res, rnd );
+ res = mpfr_check_range (x, res, rnd);
end:
(*__gmp_free_func) (str1, size_str1 * sizeof (char));
diff --git a/tests/tset_str.c b/tests/tset_str.c
index f90db1f34..5e486d022 100644
--- a/tests/tset_str.c
+++ b/tests/tset_str.c
@@ -33,12 +33,12 @@ static void
check_underflow (void)
{
mpfr_t a;
- mp_exp_t emin;
+ mp_exp_t emin, emax;
int res;
mpfr_init (a);
- /* Check undeflow */
+ /* Check underflow */
emin = mpfr_get_emin ();
mpfr_set_emin (-20);
res = mpfr_set_str (a, "0.00000000001", 10, GMP_RNDZ);
@@ -52,6 +52,17 @@ check_underflow (void)
}
mpfr_set_emin (emin);
+ /* check overflow */
+ emax = mpfr_get_emax ();
+ mpfr_set_emax (1073741823); /* 2^30-1 */
+ mpfr_set_str (a, "2E1000000000", 10, GMP_RNDN);
+ if (!mpfr_inf_p (a) || mpfr_sgn (a) < 0)
+ {
+ printf("ERROR for mpfr_set_str (a, \"2E1000000000\", 10, GMP_RNDN);\n");
+ exit (1);
+ }
+ mpfr_set_emax (emax);
+
mpfr_clear (a);
}