summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/set_si_2exp.c9
-rw-r--r--src/set_ui_2exp.c9
-rw-r--r--src/set_uj.c20
3 files changed, 32 insertions, 6 deletions
diff --git a/src/set_si_2exp.c b/src/set_si_2exp.c
index e15c9b60f..6b8fa9cd1 100644
--- a/src/set_si_2exp.c
+++ b/src/set_si_2exp.c
@@ -40,6 +40,15 @@ mpfr_set_si_2exp (mpfr_ptr x, long i, mpfr_exp_t e, mpfr_rnd_t rnd_mode)
mp_limb_t ai, *xp;
int inex = 0;
+ /* Early underflow/overflow checking is necessary to avoid
+ integer overflow or errors due to special exponent values. */
+ if (MPFR_UNLIKELY (e < __gmpfr_emin - (mpfr_exp_t)
+ (sizeof (unsigned long) * CHAR_BIT + 1)))
+ return mpfr_underflow (x, rnd_mode == MPFR_RNDN ?
+ MPFR_RNDZ : rnd_mode, i < 0 ? -1 : 1);
+ if (MPFR_UNLIKELY (e >= __gmpfr_emax))
+ return mpfr_overflow (x, rnd_mode, i < 0 ? -1 : 1);
+
/* FIXME: support int limbs (e.g. 16-bit limbs on 16-bit proc) */
ai = SAFE_ABS (unsigned long, i);
MPFR_ASSERTN (SAFE_ABS (unsigned long, i) == ai);
diff --git a/src/set_ui_2exp.c b/src/set_ui_2exp.c
index 172372708..89fc50383 100644
--- a/src/set_ui_2exp.c
+++ b/src/set_ui_2exp.c
@@ -41,6 +41,15 @@ mpfr_set_ui_2exp (mpfr_ptr x, unsigned long i, mpfr_exp_t e, mpfr_rnd_t rnd_mode
mp_limb_t *xp;
int inex = 0;
+ /* Early underflow/overflow checking is necessary to avoid
+ integer overflow or errors due to special exponent values. */
+ if (MPFR_UNLIKELY (e < __gmpfr_emin - (mpfr_exp_t)
+ (sizeof (unsigned long) * CHAR_BIT + 1)))
+ return mpfr_underflow (x, rnd_mode == MPFR_RNDN ?
+ MPFR_RNDZ : rnd_mode, i < 0 ? -1 : 1);
+ if (MPFR_UNLIKELY (e >= __gmpfr_emax))
+ return mpfr_overflow (x, rnd_mode, i < 0 ? -1 : 1);
+
/* FIXME: support int limbs (e.g. 16-bit limbs on 16-bit proc) */
MPFR_ASSERTD (i == (mp_limb_t) i);
diff --git a/src/set_uj.c b/src/set_uj.c
index 7b94a2a09..5a79ee772 100644
--- a/src/set_uj.c
+++ b/src/set_uj.c
@@ -41,7 +41,7 @@ mpfr_set_uj (mpfr_t x, uintmax_t j, mpfr_rnd_t rnd)
int
mpfr_set_uj_2exp (mpfr_t x, uintmax_t j, intmax_t e, mpfr_rnd_t rnd)
{
- int cnt;
+ int cnt, inex;
mp_size_t i, k;
mp_limb_t limb;
mp_limb_t yp[uintmaxpml];
@@ -57,6 +57,10 @@ mpfr_set_uj_2exp (mpfr_t x, uintmax_t j, intmax_t e, mpfr_rnd_t rnd)
MPFR_RET(0);
}
+ /* early overflow detection to avoid a possible integer overflow below */
+ if (MPFR_UNLIKELY(e >= __gmpfr_emax))
+ return mpfr_overflow (x, rnd, MPFR_SIGN_POS);
+
MPFR_ASSERTN (sizeof(uintmax_t) % sizeof(mp_limb_t) == 0);
/* Create an auxiliary var */
@@ -107,7 +111,9 @@ mpfr_set_uj_2exp (mpfr_t x, uintmax_t j, intmax_t e, mpfr_rnd_t rnd)
e += k * GMP_NUMB_BITS - cnt; /* Update Expo */
MPFR_ASSERTD (MPFR_LIMB_MSB(yp[numberof (yp) - 1]) != 0);
- /* Check expo underflow / overflow (can't use mpfr_check_range) */
+ MPFR_RNDRAW (inex, x, yp, uintmax_bit_size, rnd, MPFR_SIGN_POS, e++);
+
+ /* Check expo underflow / overflow */
if (MPFR_UNLIKELY(e < __gmpfr_emin))
{
/* The following test is necessary because in the rounding to the
@@ -116,16 +122,18 @@ mpfr_set_uj_2exp (mpfr_t x, uintmax_t j, intmax_t e, mpfr_rnd_t rnd)
* _ |x| < 2^(emin-2), or
* _ |x| = 2^(emin-2) and the absolute value of the exact
* result is <= 2^(emin-2). */
- if (rnd == MPFR_RNDN && (e+1 < __gmpfr_emin || mpfr_powerof2_raw(y)))
+ if (rnd == MPFR_RNDN &&
+ (e + 1 < __gmpfr_emin ||
+ (mpfr_powerof2_raw (x) && inex >= 0)))
rnd = MPFR_RNDZ;
return mpfr_underflow (x, rnd, MPFR_SIGN_POS);
}
if (MPFR_UNLIKELY(e > __gmpfr_emax))
return mpfr_overflow (x, rnd, MPFR_SIGN_POS);
- MPFR_SET_EXP (y, e);
- /* Final: set x to y (rounding if necessary) */
- return mpfr_set (x, y, rnd);
+ MPFR_SET_SIGN (x, MPFR_SIGN_POS);
+ MPFR_SET_EXP (x, e);
+ MPFR_RET (inex);
}
#endif