1
/* mpfr_sin -- sine of a floating-point number
3
Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
5
This file is part of the MPFR Library.
7
The MPFR Library is free software; you can redistribute it and/or modify
8
it under the terms of the GNU Lesser General Public License as published by
9
the Free Software Foundation; either version 2.1 of the License, or (at your
10
option) any later version.
12
The MPFR Library is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15
License for more details.
17
You should have received a copy of the GNU Lesser General Public License
18
along with the MPFR Library; see the file COPYING.LIB. If not, write to
19
the Free Software Foundation, Inc., 51 Franklin Place, Fifth Floor, Boston,
20
MA 02110-1301, USA. */
22
#define MPFR_NEED_LONGLONG_H
23
#include "mpfr-impl.h"
25
/* determine the sign of sin(x) using argument reduction.
26
Assumes x is not an exact multiple of Pi (this excludes x=0). */
28
mpfr_sin_sign (mpfr_srcptr x)
38
if (K < 0) /* Trivial case if ABS(x) < 1 */
41
m = K + BITS_PER_MP_LIMB;
45
MPFR_ZIV_INIT (loop, m);
48
/* first determine round(x/Pi): does not have to be exact since
49
the result is an integer */
50
mpfr_const_pi (c, GMP_RNDN); /* err <= 1/2*ulp(c) = 2^(1-m) */
51
/* we need that k is not-to-badly rounded to an integer,
52
i.e. ulp(k) <= 1, so m >= EXP(k). */
53
mpfr_div (k, x, c, GMP_RNDN);
58
if (!MPFR_IS_ZERO (k)) /* subtract k*approx(Pi) */
60
/* determine parity of k for sign */
61
if (MPFR_GET_EXP (k) <= 0 || (mpfr_uexp_t) MPFR_GET_EXP (k) <= m)
63
mp_size_t j = BITS_PER_MP_LIMB * MPFR_LIMB_SIZE(k)
65
mp_size_t l = j / BITS_PER_MP_LIMB;
66
/* parity bit is j-th bit starting from least significant bits */
67
if ((MPFR_MANT(k)[l] >> (j % BITS_PER_MP_LIMB)) & 1)
68
sign = -1; /* k is odd */
70
K = MPFR_GET_EXP (k); /* k is an integer, thus K >= 1, k < 2^K */
71
mpfr_mul (k, k, c, GMP_RNDN); /* err <= oldk*err(c) + 1/2*ulp(k)
73
mpfr_sub (k, x, k, GMP_RNDN);
74
/* assuming |k| <= Pi, err <= 2^(1-m)+2^(K+2-m) < 2^(K+3-m) */
75
MPFR_ASSERTN (MPFR_IS_ZERO (k) || MPFR_GET_EXP (k) <= 2);
83
/* sign of sign(y) is uncertain if |y| <= err < 2^(K+3-m),
84
thus EXP(y) < K+4-m */
85
if (MPFR_LIKELY (!MPFR_IS_ZERO (y)
86
&& MPFR_GET_EXP (y) >= K + 4 - (mp_exp_t) m))
88
MPFR_ZIV_NEXT (loop, m);
103
mpfr_sin (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode)
109
MPFR_ZIV_DECL (loop);
111
MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", x, x, rnd_mode),
112
("y[%#R]=%R inexact=%d", y, y, inexact));
114
if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
116
if (MPFR_IS_NAN (x) || MPFR_IS_INF (x))
124
MPFR_ASSERTD (MPFR_IS_ZERO (x));
126
MPFR_SET_SAME_SIGN (y, x);
131
/* sin(x) = x - x^3/6 + ... so the error is < 2^(3*EXP(x)-2) */
132
MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, -2*MPFR_GET_EXP (x)+2,0,rnd_mode,{});
134
/* Compute initial precision */
135
precy = MPFR_PREC (y);
136
m = precy + MPFR_INT_CEIL_LOG2 (precy) + 13;
137
e = MPFR_GET_EXP (x);
138
m += (e < 0) ? -2*e : e;
140
sign = mpfr_sin_sign (x);
143
MPFR_ZIV_INIT (loop, m);
146
mpfr_cos (c, x, GMP_RNDZ); /* can't be exact */
147
mpfr_nexttoinf (c); /* now c = cos(x) rounded away */
148
mpfr_mul (c, c, c, GMP_RNDU); /* away */
149
mpfr_ui_sub (c, 1, c, GMP_RNDZ);
150
mpfr_sqrt (c, c, GMP_RNDZ);
151
if (MPFR_IS_NEG_SIGN(sign))
154
/* Warning c may be 0 ! */
155
if (MPFR_UNLIKELY (MPFR_IS_ZERO (c)))
157
/* Huge cancellation: increase prec a lot! */
158
m = MAX (m, MPFR_PREC (x));
163
/* the absolute error on c is at most 2^(3-m-EXP(c)) */
164
e = 2 * MPFR_GET_EXP (c) + m - 3;
165
if (mpfr_can_round (c, e, GMP_RNDN, GMP_RNDZ,
166
precy + (rnd_mode == GMP_RNDN)))
167
/* WARNING: even if we know c <= sin(x), don't give GMP_RNDZ
168
as 3rd argument to mpfr_can_round, since if c is exactly
169
representable to the target precision (inexact = 0 below),
170
we would have to add one ulp when rounding away from 0. */
173
/* check for huge cancellation (Near 0) */
174
if (e < (mp_exp_t) MPFR_PREC (y))
175
m += MPFR_PREC (y) - e;
176
/* Check if near 1 */
177
if (MPFR_GET_EXP (c) == 1)
181
/* Else generic increase */
182
MPFR_ZIV_NEXT (loop, m);
183
mpfr_set_prec (c, m);
185
MPFR_ZIV_FREE (loop);
187
inexact = mpfr_set (y, c, rnd_mode);
188
/* inexact cannot be 0, since this would mean that c was representable
189
within the target precision, but in that case mpfr_can_round will fail */
193
return inexact; /* inexact */