summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorenge <enge@211d60ee-9f03-0410-a15a-8952a2c7a4e4>2010-07-30 15:31:30 +0000
committerenge <enge@211d60ee-9f03-0410-a15a-8952a2c7a4e4>2010-07-30 15:31:30 +0000
commitf5e44f7b814899e0c8a01cf4803e99c37de9fecb (patch)
tree0c7e502aa06d2b5e7edda453b797e5d84673d9fc
parent669f79ebbfb19e5548a8798a575e4cf2406161b1 (diff)
downloadmpc-f5e44f7b814899e0c8a01cf4803e99c37de9fecb.tar.gz
exp: closed bug http://lists.gforge.inria.fr/pipermail/mpc-discuss/2010-July/000757.html
high precision is needed for argument close to 0 git-svn-id: svn://scm.gforge.inria.fr/svn/mpc/trunk@813 211d60ee-9f03-0410-a15a-8952a2c7a4e4
-rw-r--r--NEWS1
-rw-r--r--src/exp.c16
-rw-r--r--tests/exp.dat3
3 files changed, 13 insertions, 7 deletions
diff --git a/NEWS b/NEWS
index 801d358..afaa3f5 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ Changes in version 0.8.3:
mpc_pow_z when the exponent fits in a long
- Bug fixes:
- trigonometric functions: infinite loop due to overflow for large arguments
+ - exp: close to infinite loop for argument close to 0
Changes in version 0.8.2:
- Speed-up of mpc_pow_ui through binary exponentiation
diff --git a/src/exp.c b/src/exp.c
index 21d4154..d304c62 100644
--- a/src/exp.c
+++ b/src/exp.c
@@ -148,8 +148,13 @@ mpc_exp (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
/* from now on, both parts of op are regular numbers */
- prec = MPC_MAX_PREC(rop);
-
+ prec = MPC_MAX_PREC(rop)
+ + MPC_MAX (MPC_MAX (-mpfr_get_exp (MPC_RE (op)), 0),
+ -mpfr_get_exp (MPC_IM (op)));
+ /* When op is close to 0, then exp is close to 1+Re(op), while
+ cos is close to 1-Im(op); to decide on the ternary value of exp*cos,
+ we need a high enough precision so that none of exp or cos is
+ computed as 1. */
mpfr_init2 (x, 2);
mpfr_init2 (y, 2);
mpfr_init2 (z, 2);
@@ -166,10 +171,9 @@ mpc_exp (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
could be represented in the precision of rop. */
mpfr_clear_overflow ();
mpfr_clear_underflow ();
- mpfr_exp (x, MPC_RE(op), GMP_RNDN);
- mpfr_sin_cos (z, y, MPC_IM(op), GMP_RNDN);
- mpfr_mul (y, y, x, GMP_RNDN);
-
+ mpfr_exp (x, MPC_RE(op), GMP_RNDN); /* error <= 0.5ulp */
+ mpfr_sin_cos (z, y, MPC_IM(op), GMP_RNDN); /* errors <= 0.5ulp */
+ mpfr_mul (y, y, x, GMP_RNDN); /* error <= 2ulp */
ok = mpfr_overflow_p () || mpfr_zero_p (x)
|| mpfr_can_round (y, prec - 2, GMP_RNDN, GMP_RNDZ,
MPFR_PREC(MPC_RE(rop)) + (MPC_RND_RE(rnd) == GMP_RNDN));
diff --git a/tests/exp.dat b/tests/exp.dat
index f9c5fa3..5c9c978 100644
--- a/tests/exp.dat
+++ b/tests/exp.dat
@@ -1,6 +1,6 @@
# Data file for mpc_exp.
#
-# Copyright (C) 2008, 2010 Philippe Th\'eveny, Andreas Enge
+# Copyright (C) 2008, 2010 Philippe Th\'eveny, Andreas Enge, Paul Zimmermann
#
# This file is part of the MPC Library.
#
@@ -116,4 +116,5 @@
# overflow
- - 2 -inf 2 -inf 53 0x3312ae437f94441ec@-9 53 0xe45f7bab0595dd700@-10 N N
+# input close to 0
? ? 53 1 53 0x5D7A2148071Fp-7213522 53 0x1E02AE0D0F6Fp-7213521 53 0x5D7A2148071Fp-7213522 N N