summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4>2005-12-29 17:48:46 +0000
committerzimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4>2005-12-29 17:48:46 +0000
commit09432671eeb1f53b95405c68911695f738c76fc3 (patch)
treeb67703611f831b6352c72a9b48a5817d18018dd9
parent4c5022cca9ca5752b0c94301041e87f2de541d17 (diff)
downloadmpfr-09432671eeb1f53b95405c68911695f738c76fc3.tar.gz
fixed bug in mpfr_set_f for huge argument
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@3979 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r--set_f.c16
-rw-r--r--tests/tset_f.c28
2 files changed, 42 insertions, 2 deletions
diff --git a/set_f.c b/set_f.c
index eeb7baf7b..57707a067 100644
--- a/set_f.c
+++ b/set_f.c
@@ -80,7 +80,19 @@ mpfr_set_f (mpfr_ptr y, mpf_srcptr x, mp_rnd_t rnd_mode)
inexact = 0;
}
- MPFR_SET_EXP(y, EXP(x) * BITS_PER_MP_LIMB - cnt + carry);
+ /* warning: EXP(x) * BITS_PER_MP_LIMB may exceed the maximal exponent */
+ if (EXP(x) > 1 + (__mpfr_emax - 1) / BITS_PER_MP_LIMB)
+ {
+ /* EXP(x) >= 2 + floor((__mpfr_emax-1)/BITS_PER_MP_LIMB)
+ EXP(x) >= 2 + (__mpfr_emax - BITS_PER_MP_LIMB) / BITS_PER_MP_LIMB
+ >= 1 + __mpfr_emax / BITS_PER_MP_LIMB
+ EXP(x) * BITS_PER_MP_LIMB >= __mpfr_emax + BITS_PER_MP_LIMB
+ Since 0 <= cnt <= BITS_PER_MP_LIMB-1, and 0 <= carry <= 1,
+ we have then EXP(x) * BITS_PER_MP_LIMB - cnt + carry > __mpfr_emax */
+ MPFR_SET_EXP(y, __mpfr_emax + 1);
+ }
+ else
+ MPFR_SET_EXP(y, EXP(x) * BITS_PER_MP_LIMB - (mp_exp_t) cnt + carry);
- return inexact;
+ return mpfr_check_range (y, inexact, rnd_mode);
}
diff --git a/tests/tset_f.c b/tests/tset_f.c
index b96f4abbc..716e1814f 100644
--- a/tests/tset_f.c
+++ b/tests/tset_f.c
@@ -22,6 +22,7 @@ MA 02110-1301, USA. */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
+#include <limits.h> /* for ULONG_MAX */
#include "mpfr-test.h"
@@ -131,6 +132,33 @@ main (void)
mpf_mul_2exp (y, y, 1);
}
+ mpf_set_ui (y, 1);
+ mpf_mul_2exp (y, y, ULONG_MAX);
+ mpfr_set_f (x, y, GMP_RNDN);
+ if (mpfr_inf_p (x) == 0 || mpfr_cmp_ui (x, 0) < 0)
+ {
+ printf ("Error: mpfr_set_f (x, y, GMP_RNDN) for y=2^ULONG_MAX\n");
+ exit (1);
+ }
+
+ mpf_set_ui (y, 1);
+ mpf_mul_2exp (y, y, __mpfr_emax);
+ mpfr_set_f (x, y, GMP_RNDN);
+ if (mpfr_inf_p (x) == 0 || mpfr_cmp_ui (x, 0) < 0)
+ {
+ printf ("Error: mpfr_set_f (x, y, GMP_RNDN) for y=2^__mpfr_emax\n");
+ exit (1);
+ }
+
+ mpf_set_ui (y, 1);
+ mpf_mul_2exp (y, y, __mpfr_emax - 1);
+ mpfr_set_f (x, y, GMP_RNDN);
+ if (mpfr_cmp_ui_2exp (x, 1, __mpfr_emax - 1) != 0)
+ {
+ printf ("Error: mpfr_set_f (x, y, GMP_RNDN) for y=2^(__mpfr_emax-1)\n");
+ exit (1);
+ }
+
mpfr_clear (x);
mpf_clear (y);
mpf_clear (z);