summaryrefslogtreecommitdiff
path: root/src/sin_cos.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sin_cos.c')
-rw-r--r--src/sin_cos.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/src/sin_cos.c b/src/sin_cos.c
index 0bb00cf..7051708 100644
--- a/src/sin_cos.c
+++ b/src/sin_cos.c
@@ -299,11 +299,28 @@ mpc_sin_cos (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
mpfr_t s, c, sh, ch, sch, csh;
mpfr_prec_t prec;
int ok;
- int inex_re, inex_im, inex_sin, inex_cos;
+ int inex_re, inex_im, inex_sin, inex_cos, loop = 0;
prec = 2;
if (rop_sin != NULL)
- prec = MPC_MAX (prec, MPC_MAX_PREC (rop_sin));
+ {
+ mp_prec_t er, ei;
+ prec = MPC_MAX (prec, MPC_MAX_PREC (rop_sin));
+ /* since the Taylor expansion of sin(x) at x=0 is x - x^3/6 + O(x^5),
+ if x <= 2^(-p), then the second term/x is about 2^(-2p)/6, thus we
+ need at least 2p+3 bits of precision. This is true only when x is
+ exactly representable in the target precision. */
+ if (MPC_MAX_PREC (op) <= prec)
+ {
+ er = mpfr_get_exp (mpc_realref (op));
+ ei = mpfr_get_exp (mpc_imagref (op));
+ /* consider the maximal exponent only */
+ er = (er < ei) ? ei : er;
+ if (er < 0)
+ if (prec < 2 * (mp_prec_t) (-er) + 3)
+ prec = 2 * (mp_prec_t) (-er) + 3;
+ }
+ }
if (rop_cos != NULL)
prec = MPC_MAX (prec, MPC_MAX_PREC (rop_cos));
@@ -315,8 +332,9 @@ mpc_sin_cos (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
mpfr_init2 (csh, 2);
do {
+ loop ++;
ok = 1;
- prec += mpc_ceil_log2 (prec) + 5;
+ prec += (loop <= 2) ? mpc_ceil_log2 (prec) + 5 : prec / 2;
mpfr_set_prec (s, prec);
mpfr_set_prec (c, prec);