diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2015-06-26 13:59:12 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2015-06-26 13:59:12 +0000 |
commit | e858e319214faac72b56cbda34c3e93327064ad8 (patch) | |
tree | 579398805438ff0c4099be83e1cfe78a4e878f0f | |
parent | ac94fbf2a230cd2f758ece04fca5d9867134d786 (diff) | |
download | mpfr-e858e319214faac72b56cbda34c3e93327064ad8.tar.gz |
[src/frexp.c] Handle internal overflow.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@9600 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r-- | src/frexp.c | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/src/frexp.c b/src/frexp.c index 40991fb45..a640efac8 100644 --- a/src/frexp.c +++ b/src/frexp.c @@ -26,6 +26,13 @@ int mpfr_frexp (mpfr_exp_t *exp, mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd) { int inex; + mpfr_flags_t saved_flags = __gmpfr_flags; + MPFR_BLOCK_DECL (flags); + + MPFR_LOG_FUNC + (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd), + ("y[%Pu]=%.*Rg exp=%" MPFR_EXP_FSPEC "d inex=%d", mpfr_get_prec (y), + mpfr_log_prec, y, (mpfr_eexp_t) *exp, inex)); if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(x))) { @@ -49,7 +56,28 @@ mpfr_frexp (mpfr_exp_t *exp, mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd) } } - inex = mpfr_set (y, x, rnd); + MPFR_BLOCK (flags, inex = mpfr_set (y, x, rnd)); + __gmpfr_flags = saved_flags; + + if (MPFR_UNLIKELY (MPFR_OVERFLOW (flags))) + { + int inex2; + + /* An overflow here means that the exponent of y would be larger than + the one of x, thus x would be rounded to the next power of 2, and + the returned y should be 1/2 in absolute value, rounded (i.e. with + possible underflow or overflow). This also implies that x and y are + different objects, so that the exponent of x has not been lost. */ + MPFR_LOG_MSG (("Internal overflow\n", 0)); + MPFR_ASSERTD (x != y); + *exp = MPFR_GET_EXP (x) + 1; + inex2 = mpfr_set_si_2exp (y, MPFR_INT_SIGN (x), -1, rnd); + MPFR_LOG_MSG (("inex=%d inex2=%d\n", inex, inex2)); + if (inex2 != 0) + inex = inex2; + MPFR_RET (inex); + } + *exp = MPFR_GET_EXP (y); /* Do not use MPFR_SET_EXP because the range has not been checked yet. */ MPFR_EXP (y) = 0; |