diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2020-03-30 00:00:47 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2020-03-30 00:00:47 +0000 |
commit | 100d483e5d63a1d79d9e8c277be70e90bcfb5dbb (patch) | |
tree | bbdebea67f01a0345ec0b5abec49b0c52e899ee9 /src/sub1.c | |
parent | ff1e2ee315ffab91a62a3c7b04098e17035215ab (diff) | |
download | mpfr-100d483e5d63a1d79d9e8c277be70e90bcfb5dbb.tar.gz |
UBF support fixed in mpfr_sub1 (src/sub1.c):
* underflow detection (which could affect mpfr_{fma,fms,fmma,fmms});
* MPFR_RNDF (mpfr_set4, which doesn't support UBF, could be called).
In the tests directory:
* tfma.c: disabled some tests on MPFR_RNDF (since the results are
not fully specified, the tests are heuristics only and depend on
a particular implementation, which has changed for the bug fix).
* tfmma.c: added a testcase showing how the above bug could affect
mpfr_fmms.
* tsub.c: added tests on UBF (thus using internals).
(merged changesets r13703,13796-13807,13810-13815,13818,13821 from the
trunk)
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/branches/4.0@13837 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'src/sub1.c')
-rw-r--r-- | src/sub1.c | 32 |
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, |