summaryrefslogtreecommitdiff
path: root/sin.c
diff options
context:
space:
mode:
authorzimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4>2005-04-28 09:47:32 +0000
committerzimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4>2005-04-28 09:47:32 +0000
commitfd718a07e9f95898ccac4fabb15df599d58726cd (patch)
tree1a27da563d6348b9e04431256a0931c8252a4db9 /sin.c
parente9f9b21c62c450919c04b09146aab65420f53bc0 (diff)
downloadmpfr-fd718a07e9f95898ccac4fabb15df599d58726cd.tar.gz
wrong commit, put revision 1.37 back
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@3496 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'sin.c')
-rw-r--r--sin.c91
1 files changed, 2 insertions, 89 deletions
diff --git a/sin.c b/sin.c
index 9b48c7358..b3c40322c 100644
--- a/sin.c
+++ b/sin.c
@@ -128,97 +128,10 @@ mpfr_sin (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode)
}
}
- /* Special case when |x| is very small (and x is a good approximation) */
- e = MPFR_GET_EXP(x);
- precy = MPFR_PREC(y);
- if (e < 0)
- {
- long v;
-
- /*
- Assume WMLOG that x > 0 (we will compensate for negative x later); then
- x - x^3 < Sin(x) < x. Let e be the exponent of x, px be the precision
- of x and p the precision of y. Let L and U be such that L < x <= U
- with L and U "adjacent" representable values in precision p. (It
- follows that U = x rounded up to precision p.)
-
- Then a coarse estimate establishes that if Max(p,px) + 2*e - 2 <= 0
- then L < Sin(x) < U. If not rounding to nearest then this is sufficient,
- otherwise we need to know where it stands with respect to (L+U)/2. A
- simple approach is to implicitly use one extra bit so that one of L or U
- is implicitly replaced by (L+U)/2. In this case, we require that
- Max(p+1,px) + 2*e - 2 <= 0.
- */
- v = (long)MPFR_PREC(y);
- if (rnd_mode == GMP_RNDN)
- v++;
- if (v < (long)MPFR_PREC(x))
- v = (long)MPFR_PREC(x);
- v -= 2;
- v += (long)e; /* don't use v += 2*e due to overflow paranoia */
- if (v > 0)
- v += (long)e;
-
- if (v <= 0) /* small case */
- {
- /*
- If rounding to nearest there is a potential problem if x lies exactly
- halfway between two representable values: the correct end result is
- obtained by rounding towards zero in this case. Since this cannot
- currently be specified to the setting/rounding routines, an explicit
- check and change of rounding mode is done in this case.
- */
- if (rnd_mode == GMP_RNDN && MPFR_PREC(x) > precy)
- {
- mp_limb_t *xp, ok, mask;
- mp_prec_t sh;
- int k;
-
- MPFR_UNSIGNED_MINUS_MODULO(sh, precy);
- k = MPFR_LIMB_SIZE(x) - MPFR_LIMB_SIZE(y);
- xp = MPFR_MANT(x) + k;
- if (MPFR_LIKELY(sh != 0))
- {
- mask = MPFR_LIMB_ONE << (sh - 1);
- }
- else
- {
- mask = MPFR_LIMB_HIGHBIT;
- xp--;
- k--;
- }
- ok = (xp[0] & mask) ^ mask;
- if (ok == 0)
- {
- ok = xp[0] & (mask-1);
- if (MPFR_UNLIKELY(ok == 0))
- {
- while (--k >= 0 && ok == 0)
- ok = *--xp;
- }
- }
-
- if (MPFR_UNLIKELY(ok == 0)) /* problem case */
- rnd_mode = GMP_RNDZ;
- }
-
- sign = MPFR_INT_SIGN(x);
- inexact = mpfr_set(y, x, rnd_mode);
- if (inexact == 0)
- {
- inexact = sign;
- if (MPFR_IS_LIKE_RNDZ(rnd_mode, MPFR_IS_NEG_SIGN(sign)))
- {
- inexact = -inexact;
- mpfr_nexttozero(y);
- }
- }
- MPFR_RET(inexact);
- }
- }
-
/* Compute initial precision */
+ precy = MPFR_PREC (y);
m = precy + MPFR_INT_CEIL_LOG2 (precy) + 13;
+ e = MPFR_GET_EXP (x);
m += (e < 0) ? -2*e : e;
sign = mpfr_sin_sign (x);