Hook mount_hpfs into the build. It builds and even works.
[dragonfly.git] / contrib / mpfr / cos.c
blobe2601a8a82366f6d6473716fa52474389c6a9f58
1 /* mpfr_cos -- cosine of a floating-point number
3 Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4 Contributed by the Arenaire and Cacao projects, INRIA.
6 This file is part of the GNU MPFR Library.
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or (at your
11 option) any later version.
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 MA 02110-1301, USA. */
23 #define MPFR_NEED_LONGLONG_H
24 #include "mpfr-impl.h"
26 /* f <- 1 - r/2! + r^2/4! + ... + (-1)^l r^l/(2l)! + ...
27 Assumes |r| < 1/2, and f, r have the same precision.
28 Returns e such that the error on f is bounded by 2^e ulps.
30 static int
31 mpfr_cos2_aux (mpfr_ptr f, mpfr_srcptr r)
33 mpz_t x, t, s;
34 mp_exp_t ex, l, m;
35 mp_prec_t p, q;
36 unsigned long i, maxi, imax;
38 MPFR_ASSERTD(mpfr_get_exp (r) <= -1);
40 /* compute minimal i such that i*(i+1) does not fit in an unsigned long,
41 assuming that there are no padding bits. */
42 maxi = 1UL << (CHAR_BIT * sizeof(unsigned long) / 2);
43 if (maxi * (maxi / 2) == 0) /* test checked at compile time */
45 /* can occur only when there are padding bits. */
46 /* maxi * (maxi-1) is representable iff maxi * (maxi / 2) != 0 */
48 maxi /= 2;
49 while (maxi * (maxi / 2) == 0);
52 mpz_init (x);
53 mpz_init (s);
54 mpz_init (t);
55 ex = mpfr_get_z_exp (x, r); /* r = x*2^ex */
57 /* remove trailing zeroes */
58 l = mpz_scan1 (x, 0);
59 ex += l;
60 mpz_div_2exp (x, x, l);
62 /* since |r| < 1, r = x*2^ex, and x is an integer, necessarily ex < 0 */
64 p = mpfr_get_prec (f); /* same than r */
65 /* bound for number of iterations */
66 imax = p / (-mpfr_get_exp (r));
67 imax += (imax == 0);
68 q = 2 * MPFR_INT_CEIL_LOG2(imax) + 4; /* bound for (3l)^2 */
70 mpz_set_ui (s, 1); /* initialize sum with 1 */
71 mpz_mul_2exp (s, s, p + q); /* scale all values by 2^(p+q) */
72 mpz_set (t, s); /* invariant: t is previous term */
73 for (i = 1; (m = mpz_sizeinbase (t, 2)) >= q; i += 2)
75 /* adjust precision of x to that of t */
76 l = mpz_sizeinbase (x, 2);
77 if (l > m)
79 l -= m;
80 mpz_div_2exp (x, x, l);
81 ex += l;
83 /* multiply t by r */
84 mpz_mul (t, t, x);
85 mpz_div_2exp (t, t, -ex);
86 /* divide t by i*(i+1) */
87 if (i < maxi)
88 mpz_div_ui (t, t, i * (i + 1));
89 else
91 mpz_div_ui (t, t, i);
92 mpz_div_ui (t, t, i + 1);
94 /* if m is the (current) number of bits of t, we can consider that
95 all operations on t so far had precision >= m, so we can prove
96 by induction that the relative error on t is of the form
97 (1+u)^(3l)-1, where |u| <= 2^(-m), and l=(i+1)/2 is the # of loops.
98 Since |(1+x^2)^(1/x) - 1| <= 4x/3 for |x| <= 1/2,
99 for |u| <= 1/(3l)^2, the absolute error is bounded by
100 4/3*(3l)*2^(-m)*t <= 4*l since |t| < 2^m.
101 Therefore the error on s is bounded by 2*l*(l+1). */
102 /* add or subtract to s */
103 if (i % 4 == 1)
104 mpz_sub (s, s, t);
105 else
106 mpz_add (s, s, t);
109 mpfr_set_z (f, s, GMP_RNDN);
110 mpfr_div_2ui (f, f, p + q, GMP_RNDN);
112 mpz_clear (x);
113 mpz_clear (s);
114 mpz_clear (t);
116 l = (i - 1) / 2; /* number of iterations */
117 return 2 * MPFR_INT_CEIL_LOG2 (l + 1) + 1; /* bound is 2l(l+1) */
121 mpfr_cos (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode)
123 mp_prec_t K0, K, precy, m, k, l;
124 int inexact, reduce = 0;
125 mpfr_t r, s, xr, c;
126 mp_exp_t exps, cancel = 0, expx;
127 MPFR_ZIV_DECL (loop);
128 MPFR_SAVE_EXPO_DECL (expo);
129 MPFR_GROUP_DECL (group);
131 MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", x, x, rnd_mode),
132 ("y[%#R]=%R inexact=%d", y, y, inexact));
134 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
136 if (MPFR_IS_NAN (x) || MPFR_IS_INF (x))
138 MPFR_SET_NAN (y);
139 MPFR_RET_NAN;
141 else
143 MPFR_ASSERTD (MPFR_IS_ZERO (x));
144 return mpfr_set_ui (y, 1, rnd_mode);
148 MPFR_SAVE_EXPO_MARK (expo);
150 /* cos(x) = 1-x^2/2 + ..., so error < 2^(2*EXP(x)-1) */
151 expx = MPFR_GET_EXP (x);
152 MPFR_SMALL_INPUT_AFTER_SAVE_EXPO (y, __gmpfr_one, -2 * expx,
153 1, 0, rnd_mode, expo, {});
155 /* Compute initial precision */
156 precy = MPFR_PREC (y);
157 K0 = __gmpfr_isqrt (precy / 3);
158 m = precy + 2 * MPFR_INT_CEIL_LOG2 (precy) + 2 * K0;
160 if (expx >= 3)
162 reduce = 1;
163 mpfr_init2 (xr, m);
164 mpfr_init2 (c, expx + m - 1);
167 MPFR_GROUP_INIT_2 (group, m, r, s);
168 MPFR_ZIV_INIT (loop, m);
169 for (;;)
171 /* If |x| >= 4, first reduce x cmod (2*Pi) into xr, using mpfr_remainder:
172 let e = EXP(x) >= 3, and m the target precision:
173 (1) c <- 2*Pi [precision e+m-1, nearest]
174 (2) xr <- remainder (x, c) [precision m, nearest]
175 We have |c - 2*Pi| <= 1/2ulp(c) = 2^(3-e-m)
176 |xr - x - k c| <= 1/2ulp(xr) <= 2^(1-m)
177 |k| <= |x|/(2*Pi) <= 2^(e-2)
178 Thus |xr - x - 2kPi| <= |k| |c - 2Pi| + 2^(1-m) <= 2^(2-m).
179 It follows |cos(xr) - cos(x)| <= 2^(2-m). */
180 if (reduce)
182 mpfr_const_pi (c, GMP_RNDN);
183 mpfr_mul_2ui (c, c, 1, GMP_RNDN); /* 2Pi */
184 mpfr_remainder (xr, x, c, GMP_RNDN);
185 /* now |xr| <= 4, thus r <= 16 below */
186 mpfr_mul (r, xr, xr, GMP_RNDU); /* err <= 1 ulp */
188 else
189 mpfr_mul (r, x, x, GMP_RNDU); /* err <= 1 ulp */
191 /* now |x| < 4 (or xr if reduce = 1), thus |r| <= 16 */
193 /* we need |r| < 1/2 for mpfr_cos2_aux, i.e., EXP(r) - 2K <= -1 */
194 K = K0 + 1 + MAX(0, MPFR_EXP(r)) / 2;
195 /* since K0 >= 0, if EXP(r) < 0, then K >= 1, thus EXP(r) - 2K <= -3;
196 otherwise if EXP(r) >= 0, then K >= 1/2 + EXP(r)/2, thus
197 EXP(r) - 2K <= -1 */
199 MPFR_SET_EXP (r, MPFR_GET_EXP (r) - 2 * K); /* Can't overflow! */
201 /* s <- 1 - r/2! + ... + (-1)^l r^l/(2l)! */
202 l = mpfr_cos2_aux (s, r);
203 /* l is the error bound in ulps on s */
204 MPFR_SET_ONE (r);
205 for (k = 0; k < K; k++)
207 mpfr_sqr (s, s, GMP_RNDU); /* err <= 2*olderr */
208 MPFR_SET_EXP (s, MPFR_GET_EXP (s) + 1); /* Can't overflow */
209 mpfr_sub (s, s, r, GMP_RNDN); /* err <= 4*olderr */
210 if (MPFR_IS_ZERO(s))
211 goto ziv_next;
212 MPFR_ASSERTD (MPFR_GET_EXP (s) <= 1);
215 /* The absolute error on s is bounded by (2l+1/3)*2^(2K-m)
216 2l+1/3 <= 2l+1.
217 If |x| >= 4, we need to add 2^(2-m) for the argument reduction
218 by 2Pi: if K = 0, this amounts to add 4 to 2l+1/3, i.e., to add
219 2 to l; if K >= 1, this amounts to add 1 to 2*l+1/3. */
220 l = 2 * l + 1;
221 if (reduce)
222 l += (K == 0) ? 4 : 1;
223 k = MPFR_INT_CEIL_LOG2 (l) + 2*K;
224 /* now the error is bounded by 2^(k-m) = 2^(EXP(s)-err) */
226 exps = MPFR_GET_EXP (s);
227 if (MPFR_LIKELY (MPFR_CAN_ROUND (s, exps + m - k, precy, rnd_mode)))
228 break;
230 if (MPFR_UNLIKELY (exps == 1))
231 /* s = 1 or -1, and except x=0 which was already checked above,
232 cos(x) cannot be 1 or -1, so we can round if the error is less
233 than 2^(-precy) for directed rounding, or 2^(-precy-1) for rounding
234 to nearest. */
236 if (m > k && (m - k >= precy + (rnd_mode == GMP_RNDN)))
238 /* If round to nearest or away, result is s = 1 or -1,
239 otherwise it is round(nexttoward (s, 0)). However in order to
240 have the inexact flag correctly set below, we set |s| to
241 1 - 2^(-m) in all cases. */
242 mpfr_nexttozero (s);
243 break;
247 if (exps < cancel)
249 m += cancel - exps;
250 cancel = exps;
253 ziv_next:
254 MPFR_ZIV_NEXT (loop, m);
255 MPFR_GROUP_REPREC_2 (group, m, r, s);
256 if (reduce)
258 mpfr_set_prec (xr, m);
259 mpfr_set_prec (c, expx + m - 1);
262 MPFR_ZIV_FREE (loop);
263 inexact = mpfr_set (y, s, rnd_mode);
264 MPFR_GROUP_CLEAR (group);
265 if (reduce)
267 mpfr_clear (xr);
268 mpfr_clear (c);
271 MPFR_SAVE_EXPO_FREE (expo);
272 return mpfr_check_range (y, inexact, rnd_mode);