1 /* mpfr_y0, mpfr_y1, mpfr_yn -- Bessel functions of 2nd kind, integer order.
2 http://www.opengroup.org/onlinepubs/009695399/functions/y0.html
4 Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
5 Contributed by the Arenaire and Cacao projects, INRIA.
7 This file is part of the GNU MPFR Library.
9 The GNU MPFR Library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or (at your
12 option) any later version.
14 The GNU MPFR Library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with the GNU MPFR Library; see the file COPYING.LIB. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
22 MA 02110-1301, USA. */
24 #define MPFR_NEED_LONGLONG_H
25 #include "mpfr-impl.h"
27 static int mpfr_yn_asympt (mpfr_ptr
, long, mpfr_srcptr
, mp_rnd_t
);
30 mpfr_y0 (mpfr_ptr res
, mpfr_srcptr z
, mp_rnd_t r
)
32 return mpfr_yn (res
, 0, z
, r
);
36 mpfr_y1 (mpfr_ptr res
, mpfr_srcptr z
, mp_rnd_t r
)
38 return mpfr_yn (res
, 1, z
, r
);
41 /* compute in s an approximation of S1 = sum((n-k)!/k!*y^k,k=0..n)
42 return e >= 0 the exponent difference between the maximal value of |s|
43 during the for loop and the final value of |s|.
46 mpfr_yn_s1 (mpfr_ptr s
, mpfr_srcptr y
, unsigned long n
)
52 mpz_init_set_ui (f
, 1);
53 /* we compute n!*S1 = sum(a[k]*y^k,k=0..n) where a[k] = n!*(n-k)!/k!,
54 a[0] = (n!)^2, a[1] = n!*(n-1)!, ..., a[n-1] = n, a[n] = 1 */
55 mpfr_set_ui (s
, 1, GMP_RNDN
); /* a[n] */
59 /* a[k]/a[k+1] = (n-k)!/k!/(n-(k+1))!*(k+1)! = (k+1)*(n-k) */
60 mpfr_mul (s
, s
, y
, GMP_RNDN
);
61 mpz_mul_ui (f
, f
, n
- k
);
62 mpz_mul_ui (f
, f
, k
+ 1);
63 /* invariant: f = a[k] */
64 mpfr_add_z (s
, s
, f
, GMP_RNDN
);
69 /* now we have f = (n!)^2 */
71 mpfr_div_z (s
, s
, f
, GMP_RNDN
);
73 return emax
- MPFR_EXP(s
);
76 /* compute in s an approximation of
77 S3 = c*sum((h(k)+h(n+k))*y^k/k!/(n+k)!,k=0..infinity)
78 where h(k) = 1 + 1/2 + ... + 1/k
82 Returns e such that the error is bounded by 2^e ulp(s).
85 mpfr_yn_s3 (mpfr_ptr s
, mpfr_srcptr y
, mpfr_srcptr c
, unsigned long n
)
89 mpz_t p
, q
; /* p/q will store h(k)+h(n+k) */
92 zz
= mpfr_get_ui (y
, GMP_RNDU
); /* y = z^2/4 */
93 MPFR_ASSERTN (zz
< ULONG_MAX
- 2);
94 zz
+= 2; /* z^2 <= 2^zz */
95 mpz_init_set_ui (p
, 0);
96 mpz_init_set_ui (q
, 1);
97 /* initialize p/q to h(n) */
98 for (k
= 1; k
<= n
; k
++)
100 /* p/q + 1/k = (k*p+q)/(q*k) */
101 mpz_mul_ui (p
, p
, k
);
103 mpz_mul_ui (q
, q
, k
);
105 mpfr_init2 (t
, MPFR_PREC(s
));
106 mpfr_init2 (u
, MPFR_PREC(s
));
107 mpfr_fac_ui (t
, n
, GMP_RNDN
);
108 mpfr_div (t
, c
, t
, GMP_RNDN
); /* c/n! */
109 mpfr_mul_z (u
, t
, p
, GMP_RNDN
);
110 mpfr_div_z (s
, u
, q
, GMP_RNDN
);
116 mpfr_mul (t
, t
, y
, GMP_RNDN
);
117 mpfr_div_ui (t
, t
, k
, GMP_RNDN
);
118 mpfr_div_ui (t
, t
, n
+ k
, GMP_RNDN
);
120 p/q + 1/k + 1/(n+k) = [p*k*(n+k) + q*(n+k) + q*k]/(q*k*(n+k)) */
121 mpz_mul_ui (p
, p
, k
);
122 mpz_mul_ui (p
, p
, n
+ k
);
123 mpz_addmul_ui (p
, q
, n
+ 2 * k
);
124 mpz_mul_ui (q
, q
, k
);
125 mpz_mul_ui (q
, q
, n
+ k
);
126 mpfr_mul_z (u
, t
, p
, GMP_RNDN
);
127 mpfr_div_z (u
, u
, q
, GMP_RNDN
);
131 mpfr_add (s
, s
, u
, GMP_RNDN
);
135 if (MPFR_EXP (u
) + (mp_exp_t
) MPFR_PREC (u
) < MPFR_EXP (s
) &&
136 zz
/ (2 * k
) < k
+ n
)
143 exps
= expU
- MPFR_EXP (s
);
144 /* the error is bounded by (6k^2+33/2k+11) 2^exps ulps
145 <= 8*(k+2)^2 2^exps ulps */
146 return 3 + 2 * MPFR_INT_CEIL_LOG2(k
+ 2) + exps
;
150 mpfr_yn (mpfr_ptr res
, long n
, mpfr_srcptr z
, mp_rnd_t r
)
155 MPFR_LOG_FUNC (("x[%#R]=%R n=%d rnd=%d", z
, z
, n
, r
),
156 ("y[%#R]=%R", res
, res
));
158 absn
= SAFE_ABS (unsigned long, n
);
160 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (z
)))
164 MPFR_SET_NAN (res
); /* y(n,NaN) = NaN */
167 /* y(n,z) tends to zero when z goes to +Inf, oscillating around
168 0. We choose to return +0 in that case. */
169 else if (MPFR_IS_INF (z
))
171 if (MPFR_SIGN(z
) > 0)
172 return mpfr_set_ui (res
, 0, r
);
173 else /* y(n,-Inf) = NaN */
179 else /* y(n,z) tends to -Inf for n >= 0 or n even, to +Inf otherwise,
180 when z goes to zero */
183 if (n
>= 0 || (n
& 1) == 0)
191 /* for z < 0, y(n,z) is imaginary except when j(n,|z|) = 0, which we
192 assume does not happen for a rational z. */
193 if (MPFR_SIGN(z
) < 0)
199 /* now z is not singular, and z > 0 */
201 /* Deal with tiny arguments. We have:
202 y0(z) = 2 log(z)/Pi + 2 (euler - log(2))/Pi + O(log(z)*z^2), more
203 precisely for 0 <= z <= 1/2, with g(z) = 2/Pi + 2(euler-log(2))/Pi/log(z),
204 g(z) - 0.41*z^2 < y0(z)/log(z) < g(z)
205 thus since log(z) is negative:
206 g(z)*log(z) < y0(z) < (g(z) - z^2/2)*log(z)
207 and since |g(z)| >= 0.63 for 0 <= z <= 1/2, the relative error on
208 y0(z)/log(z) is bounded by 0.41*z^2/0.63 <= 0.66*z^2.
209 Note: we use both the main term in log(z) and the constant term, because
210 otherwise the relative error would be only in 1/log(|log(z)|).
212 if (n
== 0 && MPFR_EXP(z
) < - (mp_exp_t
) (MPFR_PREC(res
) / 2))
214 mpfr_t l
, h
, t
, logz
;
218 prec
= MPFR_PREC(res
) + 10;
219 mpfr_init2 (l
, prec
);
220 mpfr_init2 (h
, prec
);
221 mpfr_init2 (t
, prec
);
222 mpfr_init2 (logz
, prec
);
223 /* first enclose log(z) + euler - log(2) = log(z/2) + euler */
224 mpfr_log (logz
, z
, GMP_RNDD
); /* lower bound of log(z) */
225 mpfr_set (h
, logz
, GMP_RNDU
); /* exact */
226 mpfr_nextabove (h
); /* upper bound of log(z) */
227 mpfr_const_euler (t
, GMP_RNDD
); /* lower bound of euler */
228 mpfr_add (l
, logz
, t
, GMP_RNDD
); /* lower bound of log(z) + euler */
229 mpfr_nextabove (t
); /* upper bound of euler */
230 mpfr_add (h
, h
, t
, GMP_RNDU
); /* upper bound of log(z) + euler */
231 mpfr_const_log2 (t
, GMP_RNDU
); /* upper bound of log(2) */
232 mpfr_sub (l
, l
, t
, GMP_RNDD
); /* lower bound of log(z/2) + euler */
233 mpfr_nextbelow (t
); /* lower bound of log(2) */
234 mpfr_sub (h
, h
, t
, GMP_RNDU
); /* upper bound of log(z/2) + euler */
235 mpfr_const_pi (t
, GMP_RNDU
); /* upper bound of Pi */
236 mpfr_div (l
, l
, t
, GMP_RNDD
); /* lower bound of (log(z/2)+euler)/Pi */
237 mpfr_nextbelow (t
); /* lower bound of Pi */
238 mpfr_div (h
, h
, t
, GMP_RNDD
); /* upper bound of (log(z/2)+euler)/Pi */
239 mpfr_mul_2ui (l
, l
, 1, GMP_RNDD
); /* lower bound on g(z)*log(z) */
240 mpfr_mul_2ui (h
, h
, 1, GMP_RNDU
); /* upper bound on g(z)*log(z) */
241 /* we now have l <= g(z)*log(z) <= h, and we need to add -z^2/2*log(z)
243 mpfr_mul (t
, z
, z
, GMP_RNDU
); /* upper bound on z^2 */
244 /* since logz is negative, a lower bound corresponds to an upper bound
245 for its absolute value */
246 mpfr_neg (t
, t
, GMP_RNDD
);
247 mpfr_div_2ui (t
, t
, 1, GMP_RNDD
);
248 mpfr_mul (t
, t
, logz
, GMP_RNDU
); /* upper bound on z^2/2*log(z) */
249 /* an underflow may happen in the above instructions, clear flag */
250 mpfr_clear_underflow ();
251 mpfr_add (h
, h
, t
, GMP_RNDU
);
252 inex
= mpfr_prec_round (l
, MPFR_PREC(res
), r
);
253 inex2
= mpfr_prec_round (h
, MPFR_PREC(res
), r
);
254 /* we need h=l and inex=inex2 */
255 ok
= (inex
== inex2
) && (mpfr_cmp (l
, h
) == 0);
257 mpfr_set (res
, h
, r
); /* exact */
266 /* small argument check for y1(z) = -2/Pi/z + O(log(z)):
267 for 0 <= z <= 1, |y1(z) + 2/Pi/z| <= 0.25 */
268 if (n
== 1 && MPFR_EXP(z
) + 1 < - (mp_exp_t
) MPFR_PREC(res
))
274 MPFR_BLOCK_DECL (flags
);
276 /* since 2/Pi > 0.5, and |y1(z)| >= |2/Pi/z|, if z <= 2^(-emax-1),
277 then |y1(z)| > 2^emax */
278 prec
= MPFR_PREC(res
) + 10;
279 mpfr_init2 (y
, prec
);
280 mpfr_const_pi (y
, GMP_RNDU
); /* Pi*(1+u)^2, where here and below u
281 represents a quantity <= 1/2^prec */
282 mpfr_mul (y
, y
, z
, GMP_RNDU
); /* Pi*z * (1+u)^4, upper bound */
283 MPFR_BLOCK (flags
, mpfr_ui_div (y
, 2, y
, GMP_RNDZ
));
284 /* 2/Pi/z * (1+u)^6, lower bound, with possible overflow */
285 if (MPFR_OVERFLOW (flags
))
288 return mpfr_overflow (res
, r
, -1);
290 mpfr_neg (y
, y
, GMP_RNDN
);
291 /* (1+u)^6 can be written 1+7u [for another value of u], thus the
292 error on 2/Pi/z is less than 7ulp(y). The truncation error is less
293 than 1/4, thus if ulp(y)>=1/4, the total error is less than 8ulp(y),
294 otherwise it is less than 1/4+7/8 <= 2. */
295 if (MPFR_EXP(y
) + 2 >= MPFR_PREC(y
)) /* ulp(y) >= 1/4 */
297 else /* ulp(y) <= 1/8 */
298 err1
= (mp_exp_t
) MPFR_PREC(y
) - MPFR_EXP(y
) + 1;
299 ok
= MPFR_CAN_ROUND (y
, prec
- err1
, MPFR_PREC(res
), r
);
301 inex
= mpfr_set (res
, y
, r
);
307 /* we can use the asymptotic expansion as soon as z > p log(2)/2,
308 but to get some margin we use it for z > p/2 */
309 if (mpfr_cmp_ui (z
, MPFR_PREC(res
) / 2 + 3) > 0)
311 inex
= mpfr_yn_asympt (res
, n
, z
, r
);
319 mp_exp_t err1
, err2
, err3
;
320 mpfr_t y
, s1
, s2
, s3
;
321 MPFR_ZIV_DECL (loop
);
328 prec
= MPFR_PREC(res
) + 2 * MPFR_INT_CEIL_LOG2 (MPFR_PREC (res
)) + 13;
329 MPFR_ZIV_INIT (loop
, prec
);
332 mpfr_set_prec (y
, prec
);
333 mpfr_set_prec (s1
, prec
);
334 mpfr_set_prec (s2
, prec
);
335 mpfr_set_prec (s3
, prec
);
337 mpfr_mul (y
, z
, z
, GMP_RNDN
);
338 mpfr_div_2ui (y
, y
, 2, GMP_RNDN
); /* z^2/4 */
340 /* store (z/2)^n temporarily in s2 */
341 mpfr_pow_ui (s2
, z
, absn
, GMP_RNDN
);
342 mpfr_div_2si (s2
, s2
, absn
, GMP_RNDN
);
344 /* compute S1 * (z/2)^(-n) */
347 mpfr_set_ui (s1
, 0, GMP_RNDN
);
351 err1
= mpfr_yn_s1 (s1
, y
, absn
- 1);
352 mpfr_div (s1
, s1
, s2
, GMP_RNDN
); /* (z/2)^(-n) * S1 */
353 /* See algorithms.tex: the relative error on s1 is bounded by
354 (3n+3)*2^(e+1-prec). */
355 err1
= MPFR_INT_CEIL_LOG2 (3 * absn
+ 3) + err1
+ 1;
356 /* rel_err(s1) <= 2^(err1-prec), thus err(s1) <= 2^err1 ulps */
358 /* compute (z/2)^n * S3 */
359 mpfr_neg (y
, y
, GMP_RNDN
); /* -z^2/4 */
360 err3
= mpfr_yn_s3 (s3
, y
, s2
, absn
); /* (z/2)^n * S3 */
361 /* the error on s3 is bounded by 2^err3 ulps */
364 err1
+= MPFR_EXP(s1
);
365 mpfr_add (s1
, s1
, s3
, GMP_RNDN
);
366 /* the error is bounded by 1/2 + 2^err1*2^(- EXP(s1))
367 + 2^err3*2^(EXP(s3) - EXP(s1)) */
368 err3
+= MPFR_EXP(s3
);
369 err1
= (err3
> err1
) ? err3
+ 1 : err1
+ 1;
370 err1
-= MPFR_EXP(s1
);
371 err1
= (err1
>= 0) ? err1
+ 1 : 1;
372 /* now the error on s1 is bounded by 2^err1*ulp(s1) */
375 mpfr_div_2ui (s2
, z
, 1, GMP_RNDN
); /* z/2 */
376 mpfr_log (s2
, s2
, GMP_RNDN
); /* log(z/2) */
377 mpfr_const_euler (s3
, GMP_RNDN
);
378 err2
= MPFR_EXP(s2
) > MPFR_EXP(s3
) ? MPFR_EXP(s2
) : MPFR_EXP(s3
);
379 mpfr_add (s2
, s2
, s3
, GMP_RNDN
); /* log(z/2) + gamma */
380 err2
-= MPFR_EXP(s2
);
381 mpfr_mul_2ui (s2
, s2
, 1, GMP_RNDN
); /* 2*(log(z/2) + gamma) */
382 mpfr_jn (s3
, absn
, z
, GMP_RNDN
); /* Jn(z) */
383 mpfr_mul (s2
, s2
, s3
, GMP_RNDN
); /* 2*(log(z/2) + gamma)*Jn(z) */
384 err2
+= 4; /* the error on s2 is bounded by 2^err2 ulps, see
387 /* add all three sums */
388 err1
+= MPFR_EXP(s1
); /* the error on s1 is bounded by 2^err1 */
389 err2
+= MPFR_EXP(s2
); /* the error on s2 is bounded by 2^err2 */
390 mpfr_sub (s2
, s2
, s1
, GMP_RNDN
); /* s2 - (s1+s3) */
391 err2
= (err1
> err2
) ? err1
+ 1 : err2
+ 1;
392 err2
-= MPFR_EXP(s2
);
393 err2
= (err2
>= 0) ? err2
+ 1 : 1;
394 /* now the error on s2 is bounded by 2^err2*ulp(s2) */
395 mpfr_const_pi (y
, GMP_RNDN
); /* error bounded by 1 ulp */
396 mpfr_div (s2
, s2
, y
, GMP_RNDN
); /* error bounded by
397 2^(err2+1)*ulp(s2) */
400 if (MPFR_LIKELY (MPFR_CAN_ROUND (s2
, prec
- err2
, MPFR_PREC(res
), r
)))
402 MPFR_ZIV_NEXT (loop
, prec
);
404 MPFR_ZIV_FREE (loop
);
406 inex
= (n
>= 0 || (n
& 1) == 0)
407 ? mpfr_set (res
, s2
, r
)
408 : mpfr_neg (res
, s2
, r
);
420 #include "jyn_asympt.c"