diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2015-07-17 00:33:35 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2015-07-17 00:33:35 +0000 |
commit | d927d77384e65f7d5d1cea344ba7c9b63b068432 (patch) | |
tree | 3c7c71dce0c9bd03a647ff8ea7b51f94413d0e50 /src | |
parent | 210e6b5e4aa5bd17a6bf7555a7427a61a34c5c0b (diff) | |
download | mpfr-d927d77384e65f7d5d1cea344ba7c9b63b068432.tar.gz |
[src/frexp.c] Fixed a bug occurring when the current exponent range
does not contain 0. Handle internal overflow.
[tests/tfrexp.c] Added corresponding testcases.
(merged changesets r9592,9594,9599-9600,9613,9617,9619 from the trunk)
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/branches/3.1@9621 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'src')
-rw-r--r-- | src/frexp.c | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/src/frexp.c b/src/frexp.c index 0f8de7ed5..69553fa51 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; + unsigned int 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,8 +56,32 @@ 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; + + /* Possible overflow due to the rounding, no possible underflow. */ + + 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); - MPFR_SET_EXP (y, 0); + /* Do not use MPFR_SET_EXP because the range has not been checked yet. */ + MPFR_EXP (y) = 0; return mpfr_check_range (y, inex, rnd); } |