summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2015-07-17 00:33:35 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2015-07-17 00:33:35 +0000
commitd927d77384e65f7d5d1cea344ba7c9b63b068432 (patch)
tree3c7c71dce0c9bd03a647ff8ea7b51f94413d0e50 /src
parent210e6b5e4aa5bd17a6bf7555a7427a61a34c5c0b (diff)
downloadmpfr-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.c35
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);
}