summaryrefslogtreecommitdiff
path: root/src/sub1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sub1.c')
-rw-r--r--src/sub1.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/src/sub1.c b/src/sub1.c
index 5b475d9d3..6ee6ad544 100644
--- a/src/sub1.c
+++ b/src/sub1.c
@@ -91,9 +91,20 @@ mpfr_sub1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode)
if (MPFR_UNLIKELY (MPFR_IS_UBF (b) || MPFR_IS_UBF (c)))
{
- exp_b = MPFR_IS_UBF (b) ?
- mpfr_ubf_zexp2exp (MPFR_ZEXP (b)) : MPFR_GET_EXP (b);
+ exp_b = MPFR_UBF_GET_EXP (b);
+ /* Early underflow detection. Rare, but a test is needed anyway
+ since in the "MAX (aq, bq) + 2 <= diff_exp" branch, the exponent
+ may decrease and MPFR_EXP_MIN would yield an integer overflow. */
+ if (MPFR_UNLIKELY (exp_b < __gmpfr_emin - 1))
+ {
+ if (rnd_mode == MPFR_RNDN)
+ rnd_mode = MPFR_RNDZ;
+ return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a));
+ }
diff_exp = mpfr_ubf_diff_exp (b, c);
+ /* mpfr_set4 below used with MPFR_RNDF does not support UBF. */
+ if (rnd_mode == MPFR_RNDF)
+ rnd_mode = MPFR_RNDN;
}
else
{
@@ -185,7 +196,13 @@ mpfr_sub1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode)
if (MPFR_UNLIKELY (exp_a > __gmpfr_emax))
return mpfr_overflow (a, rnd_mode, MPFR_SIGN (a));
if (MPFR_UNLIKELY (exp_a < __gmpfr_emin))
- goto underflow;
+ {
+ if (rnd_mode == MPFR_RNDN &&
+ (exp_a < __gmpfr_emin - 1 ||
+ (inexact * MPFR_INT_SIGN (a) >= 0 && mpfr_powerof2_raw (a))))
+ rnd_mode = MPFR_RNDZ;
+ return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a));
+ }
MPFR_SET_EXP (a, exp_a);
MPFR_RET (inexact);
}
@@ -660,6 +677,15 @@ mpfr_sub1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode)
if (MPFR_LIKELY(cancel))
{
cancel -= add_exp; /* OK: add_exp is an int equal to 0 or 1 */
+ MPFR_ASSERTD (cancel >= 0);
+ /* Detect an underflow case to avoid a possible integer overflow
+ with UBF in the computation of exp_a. */
+ if (MPFR_UNLIKELY (exp_b < __gmpfr_emin - 1))
+ {
+ if (rnd_mode == MPFR_RNDN)
+ rnd_mode = MPFR_RNDZ;
+ return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a));
+ }
exp_a = exp_b - cancel;
/* The following assertion corresponds to a limitation of the MPFR
implementation. It may fail with a 32-bit ABI and huge precisions,