1 /* mpfr_jn_asympt, mpfr_yn_asympt -- shared code for mpfr_jn and mpfr_yn
2
3 Copyright 2007-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5
6 This file is part of the GNU MPFR Library.
7
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 3 of the License, or (at your
11 option) any later version.
12
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.
17
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.LESSER. If not, see
20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23 #ifdef MPFR_JN
24 # define FUNCTION mpfr_jn_asympt
25 #else
26 # ifdef MPFR_YN
27 # define FUNCTION mpfr_yn_asympt
28 # else
29 # error "neither MPFR_JN nor MPFR_YN is defined"
30 # endif
31 #endif
32
33 /* Implements asymptotic expansion for jn or yn (formulae 9.2.5 and 9.2.6
34 from Abramowitz & Stegun).
35 Assumes |z| > p log(2)/2, where p is the target precision
36 (z can be negative only for jn).
37 Return 0 if the expansion does not converge enough (the value 0 as inexact
38 flag should not happen for normal input).
39 Note: for MPFR_RNDF, it returns 0 if the expansion failed, and a non-zero
40 value otherwise (with no other meaning).
41 */
42 static int
FUNCTION(mpfr_ptr res,long n,mpfr_srcptr z,mpfr_rnd_t r)43 FUNCTION (mpfr_ptr res, long n, mpfr_srcptr z, mpfr_rnd_t r)
44 {
45 mpfr_t s, c, P, Q, t, iz, err_t, err_s, err_u;
46 mpfr_prec_t w;
47 long k;
48 int inex, stop, diverge = 0;
49 mpfr_exp_t err2, err;
50 MPFR_ZIV_DECL (loop);
51
52 mpfr_init2 (c, 64);
53
54 /* The terms of the asymptotic expansion grow like mu^(2k)/(8z)^(2k), where
55 mu = 4n^2, thus we need mu < 8|z| so that it converges,
56 i.e., n^2/2 < |z| */
57 MPFR_ASSERTD (n >= 0);
58 mpfr_set_ui (c, n, MPFR_RNDU);
59 mpfr_mul_ui (c, c, n, MPFR_RNDU);
60 mpfr_div_2ui (c, c, 1, MPFR_RNDU);
61 if (mpfr_cmpabs (c, z) >= 0)
62 {
63 mpfr_clear (c);
64 return 0; /* asymptotic expansion failed */
65 }
66
67 w = MPFR_PREC(res) + MPFR_INT_CEIL_LOG2(MPFR_PREC(res)) + 4;
68
69 MPFR_ZIV_INIT (loop, w);
70 for (;;)
71 {
72 int ok = 0;
73
74 mpfr_set_prec (c, w);
75 mpfr_init2 (s, w);
76 mpfr_init2 (P, w);
77 mpfr_init2 (Q, w);
78 mpfr_init2 (t, w);
79 mpfr_init2 (iz, w);
80 mpfr_init2 (err_t, 31);
81 mpfr_init2 (err_s, 31);
82 mpfr_init2 (err_u, 31);
83
84 /* Approximate sin(z) and cos(z). In the following, err <= k means that
85 the approximate value y and the true value x are related by
86 y = x * (1 + u)^k with |u| <= 2^(-w), following Higham's method. */
87 mpfr_sin_cos (s, c, z, MPFR_RNDN);
88 if (MPFR_IS_NEG(z))
89 mpfr_neg (s, s, MPFR_RNDN); /* compute jn/yn(|z|), fix sign later */
90 /* The absolute error on s/c is bounded by 1/2 ulp(1/2) <= 2^(-w-1). */
91 mpfr_add (t, s, c, MPFR_RNDN);
92 mpfr_sub (c, s, c, MPFR_RNDN);
93 mpfr_swap (s, t);
94 /* now s approximates sin(z)+cos(z), and c approximates sin(z)-cos(z),
95 with total absolute error bounded by 2^(1-w). */
96
97 /* if s or c is zero, MPFR_GET_EXP will fail below */
98 if (MPFR_IS_ZERO(s) || MPFR_IS_ZERO(c))
99 goto clear; /* with ok=0 */
100
101 /* precompute 1/(8|z|) */
102 mpfr_si_div (iz, MPFR_IS_POS(z) ? 1 : -1, z, MPFR_RNDN); /* err <= 1 */
103 mpfr_div_2ui (iz, iz, 3, MPFR_RNDN);
104
105 /* compute P and Q */
106 mpfr_set_ui (P, 1, MPFR_RNDN);
107 mpfr_set_ui (Q, 0, MPFR_RNDN);
108 mpfr_set_ui (t, 1, MPFR_RNDN); /* current term */
109 mpfr_set_ui (err_t, 0, MPFR_RNDN); /* error on t */
110 mpfr_set_ui (err_s, 0, MPFR_RNDN); /* error on P and Q (sum of errors) */
111 for (k = 1, stop = 0; stop < 4; k++)
112 {
113 /* compute next term: t(k)/t(k-1) = (2n+2k-1)(2n-2k+1)/(8kz) */
114 MPFR_LOG_MSG (("loop (k,stop) = (%ld,%d)\n", k, stop));
115 mpfr_mul_si (t, t, 2 * (n + k) - 1, MPFR_RNDN); /* err <= err_k + 1 */
116 mpfr_mul_si (t, t, 2 * (n - k) + 1, MPFR_RNDN); /* err <= err_k + 2 */
117 mpfr_div_ui (t, t, k, MPFR_RNDN); /* err <= err_k + 3 */
118 mpfr_mul (t, t, iz, MPFR_RNDN); /* err <= err_k + 5 */
119 /* the relative error on t is bounded by (1+u)^(5k)-1, which is
120 bounded by 6ku for 6ku <= 0.02: first |5 log(1+u)| <= |5.5u|
121 for |u| <= 0.15, then |exp(5.5u)-1| <= 6u for |u| <= 0.02. */
122 mpfr_mul_ui (err_t, t, 6 * k, MPFR_IS_POS(t) ? MPFR_RNDU : MPFR_RNDD);
123 mpfr_abs (err_t, err_t, MPFR_RNDN); /* exact */
124 /* the absolute error on t is bounded by err_t * 2^(-w) */
125 mpfr_abs (err_u, t, MPFR_RNDU);
126 mpfr_mul_2ui (err_u, err_u, w, MPFR_RNDU); /* t * 2^w */
127 mpfr_add (err_u, err_u, err_t, MPFR_RNDU); /* max|t| * 2^w */
128 if (stop >= 2)
129 {
130 /* take into account the neglected terms: t * 2^w */
131 mpfr_div_2ui (err_s, err_s, w, MPFR_RNDU);
132 if (MPFR_IS_POS(t))
133 mpfr_add (err_s, err_s, t, MPFR_RNDU);
134 else
135 mpfr_sub (err_s, err_s, t, MPFR_RNDU);
136 mpfr_mul_2ui (err_s, err_s, w, MPFR_RNDU);
137 stop ++;
138 }
139 /* if k is odd, add to Q, otherwise to P */
140 else if (k & 1)
141 {
142 /* if k = 1 mod 4, add, otherwise subtract */
143 if ((k & 2) == 0)
144 mpfr_add (Q, Q, t, MPFR_RNDN);
145 else
146 mpfr_sub (Q, Q, t, MPFR_RNDN);
147 /* check if the next term is smaller than ulp(Q): if EXP(err_u)
148 <= EXP(Q), since the current term is bounded by
149 err_u * 2^(-w), it is bounded by ulp(Q) */
150 if (MPFR_GET_EXP (err_u) <= MPFR_GET_EXP (Q))
151 stop ++;
152 else
153 stop = 0;
154 }
155 else
156 {
157 /* if k = 0 mod 4, add, otherwise subtract */
158 if ((k & 2) == 0)
159 mpfr_add (P, P, t, MPFR_RNDN);
160 else
161 mpfr_sub (P, P, t, MPFR_RNDN);
162 /* check if the next term is smaller than ulp(P) */
163 if (MPFR_GET_EXP (err_u) <= MPFR_GET_EXP (P))
164 stop ++;
165 else
166 stop = 0;
167 }
168 mpfr_add (err_s, err_s, err_t, MPFR_RNDU);
169 /* the sum of the rounding errors on P and Q is bounded by
170 err_s * 2^(-w) */
171
172 /* stop when start to diverge */
173 if (stop < 2 &&
174 ((MPFR_IS_POS(z) && mpfr_cmp_ui (z, (k + 1) / 2) < 0) ||
175 (MPFR_IS_NEG(z) && mpfr_cmp_si (z, - ((k + 1) / 2)) > 0)))
176 {
177 /* if we have to stop the series because it diverges, then
178 increasing the precision will most probably fail, since
179 we will stop to the same point, and thus compute a very
180 similar approximation */
181 diverge = 1;
182 stop = 2; /* force stop */
183 }
184 }
185 /* the sum of the total errors on P and Q is bounded by err_s * 2^(-w) */
186
187 /* Now combine: the sum of the rounding errors on P and Q is bounded by
188 err_s * 2^(-w), and the absolute error on s/c is bounded by 2^(1-w) */
189 if ((n & 1) == 0) /* n even: P * (sin + cos) + Q (cos - sin) for jn
190 Q * (sin + cos) + P (sin - cos) for yn */
191 {
192 #ifdef MPFR_JN
193 mpfr_mul (c, c, Q, MPFR_RNDN); /* Q * (sin - cos) */
194 mpfr_mul (s, s, P, MPFR_RNDN); /* P * (sin + cos) */
195 #else
196 mpfr_mul (c, c, P, MPFR_RNDN); /* P * (sin - cos) */
197 mpfr_mul (s, s, Q, MPFR_RNDN); /* Q * (sin + cos) */
198 #endif
199 err = MPFR_GET_EXP (c);
200 if (MPFR_GET_EXP (s) > err)
201 err = MPFR_EXP (s);
202 #ifdef MPFR_JN
203 mpfr_sub (s, s, c, MPFR_RNDN);
204 #else
205 mpfr_add (s, s, c, MPFR_RNDN);
206 #endif
207 }
208 else /* n odd: P * (sin - cos) + Q (cos + sin) for jn,
209 Q * (sin - cos) - P (cos + sin) for yn */
210 {
211 #ifdef MPFR_JN
212 mpfr_mul (c, c, P, MPFR_RNDN); /* P * (sin - cos) */
213 mpfr_mul (s, s, Q, MPFR_RNDN); /* Q * (sin + cos) */
214 #else
215 mpfr_mul (c, c, Q, MPFR_RNDN); /* Q * (sin - cos) */
216 mpfr_mul (s, s, P, MPFR_RNDN); /* P * (sin + cos) */
217 #endif
218 err = MPFR_GET_EXP (c);
219 if (MPFR_GET_EXP (s) > err)
220 err = MPFR_EXP (s);
221 #ifdef MPFR_JN
222 mpfr_add (s, s, c, MPFR_RNDN);
223 #else
224 mpfr_sub (s, c, s, MPFR_RNDN);
225 #endif
226 }
227 if (MPFR_IS_ZERO(s))
228 goto clear; /* with ok=0 */
229 ok = 1;
230 if ((n & 2) != 0)
231 mpfr_neg (s, s, MPFR_RNDN);
232 if (MPFR_GET_EXP (s) > err)
233 err = MPFR_EXP (s);
234 /* the absolute error on s is bounded by P*err(s/c) + Q*err(s/c)
235 + err(P)*(s/c) + err(Q)*(s/c) + 3 * 2^(err - w - 1)
236 <= (|P|+|Q|) * 2^(1-w) + err_s * 2^(1-w) + 2^err * 2^(1-w),
237 since |c|, |old_s| <= 2. */
238 err2 = (MPFR_GET_EXP (P) >= MPFR_GET_EXP (Q))
239 ? MPFR_EXP (P) + 2 : MPFR_EXP (Q) + 2;
240 /* (|P| + |Q|) * 2^(1 - w) <= 2^(err2 - w) */
241 err = MPFR_GET_EXP (err_s) >= err ? MPFR_EXP (err_s) + 2 : err + 2;
242 /* err_s * 2^(1-w) + 2^old_err * 2^(1-w) <= 2^err * 2^(-w) */
243 err2 = (err >= err2) ? err + 1 : err2 + 1;
244 /* now the absolute error on s is bounded by 2^(err2 - w) */
245
246 /* multiply by sqrt(1/(Pi*z)) */
247 mpfr_const_pi (c, MPFR_RNDN); /* Pi, err <= 1 */
248 mpfr_mul (c, c, z, MPFR_RNDN); /* err <= 2 */
249 mpfr_si_div (c, MPFR_IS_POS(z) ? 1 : -1, c, MPFR_RNDN); /* err <= 3 */
250 mpfr_sqrt (c, c, MPFR_RNDN); /* err<=5/2, thus the absolute error is
251 bounded by 3*u*|c| for |u| <= 0.25 */
252 mpfr_mul (err_t, c, s, MPFR_SIGN(c)==MPFR_SIGN(s) ? MPFR_RNDU : MPFR_RNDD);
253 mpfr_abs (err_t, err_t, MPFR_RNDU);
254 mpfr_mul_ui (err_t, err_t, 3, MPFR_RNDU);
255 /* 3*2^(-w)*|old_c|*|s| [see below] is bounded by err_t * 2^(-w) */
256 err2 += MPFR_GET_EXP (c);
257 /* |old_c| * 2^(err2 - w) [see below] is bounded by 2^(err2-w) */
258 mpfr_mul (c, c, s, MPFR_RNDN); /* the absolute error on c is bounded by
259 1/2 ulp(c) + 3*2^(-w)*|old_c|*|s|
260 + |old_c| * 2^(err2 - w) */
261 /* compute err_t * 2^(-w) + 1/2 ulp(c) = (err_t + 2^EXP(c)) * 2^(-w) */
262 err = (MPFR_GET_EXP (err_t) > MPFR_GET_EXP (c)) ?
263 MPFR_EXP (err_t) + 1 : MPFR_EXP (c) + 1;
264 /* err_t * 2^(-w) + 1/2 ulp(c) <= 2^(err - w) */
265 /* now err_t * 2^(-w) bounds 1/2 ulp(c) + 3*2^(-w)*|old_c|*|s| */
266 err = (err >= err2) ? err + 1 : err2 + 1;
267 /* the absolute error on c is bounded by 2^(err - w) */
268
269 err -= MPFR_GET_EXP (c);
270
271 clear:
272 mpfr_clear (s);
273 mpfr_clear (P);
274 mpfr_clear (Q);
275 mpfr_clear (t);
276 mpfr_clear (iz);
277 mpfr_clear (err_t);
278 mpfr_clear (err_s);
279 mpfr_clear (err_u);
280
281 if (ok && MPFR_LIKELY (MPFR_CAN_ROUND (c, w - err, MPFR_PREC(res), r)))
282 break;
283 if (diverge != 0)
284 {
285 MPFR_ZIV_FREE (loop);
286 mpfr_clear (c);
287 return 0; /* means that the asymptotic expansion failed */
288 }
289 MPFR_ZIV_NEXT (loop, w);
290 }
291 MPFR_ZIV_FREE (loop);
292
293 inex = mpfr_set4 (res, c, r, MPFR_IS_POS (z) || (n & 1) == 0 ?
294 MPFR_SIGN (c) : - MPFR_SIGN (c));
295 mpfr_clear (c);
296
297 /* for RNDF, mpfr_set or mpfr_neg may return 0, but if we return 0, it
298 would mean the asymptotic expansion failed, thus we return 1 instead */
299 return (r != MPFR_RNDF) ? inex : 1;
300 }
301