summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4>2005-05-18 08:22:55 +0000
committerpelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4>2005-05-18 08:22:55 +0000
commit6ce84039a34830e8841936c370539b5e01386e79 (patch)
tree73ef169251ea14a30662f3ed220be13116dacf45
parenta2ac43cf79fb45c4dada0fc9880a184ac32b3878 (diff)
downloadmpfr-6ce84039a34830e8841936c370539b5e01386e79.tar.gz
Fix bug of overflow.
Fix bug of ternary value in case of overflow. git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@3585 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r--cosh.c28
-rw-r--r--tests/tcosh.c32
2 files changed, 48 insertions, 12 deletions
diff --git a/cosh.c b/cosh.c
index fe90e2907..3f107057c 100644
--- a/cosh.c
+++ b/cosh.c
@@ -57,15 +57,12 @@ mpfr_cosh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode)
MPFR_SAVE_EXPO_MARK (expo);
MPFR_TMP_INIT_ABS(x, xt);
-
/* General case */
{
/* Declaration of the intermediary variable */
mpfr_t t, te;
-
/* Declaration of the size variable */
mp_prec_t Ny = MPFR_PREC(y); /* Precision of output variable */
-
mp_prec_t Nt; /* Precision of the intermediary variable */
long int err; /* Precision of error */
MPFR_ZIV_DECL (loop);
@@ -73,7 +70,7 @@ mpfr_cosh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode)
/* compute the precision of intermediary variable */
/* The optimal number of bits : see algorithms.tex */
Nt = Ny + 3 + MPFR_INT_CEIL_LOG2 (Ny);
-
+
/* initialise of intermediary variables */
mpfr_init2 (t, Nt);
mpfr_init2 (te, Nt);
@@ -83,18 +80,28 @@ mpfr_cosh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode)
for (;;)
{
/* Compute cosh */
+ mpfr_clear_flags ();
mpfr_exp (te, x, GMP_RNDD); /* exp(x) */
+ /* exp can overflow (but not underflow since x>0) */
+ /* BUG/TODO/FIXME: exp can overflow but cosh may be representable! */
+ if (MPFR_UNLIKELY (mpfr_overflow_p ()))
+ {
+ inexact = mpfr_overflow (y, rnd_mode, MPFR_SIGN_POS);
+ MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_OVERFLOW);
+ break;
+ }
mpfr_ui_div (t, 1, te, GMP_RNDU); /* 1/exp(x) */
mpfr_add (t, te, t, GMP_RNDU); /* exp(x) + 1/exp(x)*/
mpfr_div_2ui (t, t, 1, GMP_RNDN); /* 1/2(exp(x) + 1/exp(x))*/
-
- /* Estimation of the error */
+
+ /* Estimation of the error */
err = Nt - 3;
-
/* Check if we can round */
- if (MPFR_UNLIKELY (MPFR_IS_INF (t))
- || MPFR_LIKELY (MPFR_CAN_ROUND (t, err, Ny, rnd_mode)))
- break;
+ if (MPFR_LIKELY (MPFR_CAN_ROUND (t, err, Ny, rnd_mode)))
+ {
+ inexact = mpfr_set (y, t, rnd_mode);
+ break;
+ }
/* Actualisation of the precision */
MPFR_ZIV_NEXT (loop, Nt);
@@ -102,7 +109,6 @@ mpfr_cosh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode)
mpfr_set_prec (te, Nt);
}
MPFR_ZIV_FREE (loop);
- inexact = mpfr_set (y, t, rnd_mode);
mpfr_clear (te);
mpfr_clear (t);
diff --git a/tests/tcosh.c b/tests/tcosh.c
index 74b138a7b..8f953adb3 100644
--- a/tests/tcosh.c
+++ b/tests/tcosh.c
@@ -32,6 +32,7 @@ static void
special (void)
{
mpfr_t x, y;
+ int i;
mpfr_init (x);
mpfr_init (y);
@@ -95,7 +96,36 @@ special (void)
{
printf ("Error: mpfr_cosh for prec=32 (2)\n");
exit (1);
- }
+ }
+
+ mpfr_set_prec (x, 2);
+ mpfr_clear_flags ();
+ mpfr_set_str_binary (x, "1E1000000000");
+ i = mpfr_cosh (x, x, GMP_RNDN);
+ MPFR_ASSERTN (MPFR_IS_INF (x) && MPFR_SIGN (x) > 0);
+ MPFR_ASSERTN (mpfr_overflow_p ());
+ MPFR_ASSERTN (i == 1);
+
+ mpfr_clear_flags ();
+ mpfr_set_str_binary (x, "-1E1000000000");
+ i = mpfr_cosh (x, x, GMP_RNDN);
+ MPFR_ASSERTN (MPFR_IS_INF (x) && MPFR_SIGN (x) > 0);
+ MPFR_ASSERTN (mpfr_overflow_p () && !mpfr_underflow_p ());
+ MPFR_ASSERTN (i == 1);
+
+ mpfr_clear_flags ();
+ mpfr_set_str_binary (x, "-1E1000000000");
+ i = mpfr_cosh (x, x, GMP_RNDD);
+ MPFR_ASSERTN (!MPFR_IS_INF (x) && MPFR_SIGN (x) > 0);
+ MPFR_ASSERTN (mpfr_overflow_p () && !mpfr_underflow_p ());
+ MPFR_ASSERTN (i == -1);
+
+ mpfr_clear_flags ();
+ mpfr_set_str_binary (x, "-1E1000000000");
+ i = mpfr_cosh (x, x, GMP_RNDU);
+ MPFR_ASSERTN (MPFR_IS_INF (x) && MPFR_SIGN (x) > 0);
+ MPFR_ASSERTN (mpfr_overflow_p () && !mpfr_underflow_p ());
+ MPFR_ASSERTN (i == 1);
mpfr_clear (x);
mpfr_clear (y);