xref: /netbsd-src/external/lgpl3/mpfr/dist/src/yn.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1d59437c0Smrg /* mpfr_y0, mpfr_y1, mpfr_yn -- Bessel functions of 2nd kind, integer order.
2ba125506Smrg    https://pubs.opengroup.org/onlinepubs/9699919799/functions/y0.html
3d59437c0Smrg 
4ba125506Smrg Copyright 2007-2023 Free Software Foundation, Inc.
5efdec83bSmrg Contributed by the AriC and Caramba projects, INRIA.
6d59437c0Smrg 
7d59437c0Smrg This file is part of the GNU MPFR Library.
8d59437c0Smrg 
9d59437c0Smrg The GNU MPFR Library is free software; you can redistribute it and/or modify
10d59437c0Smrg it under the terms of the GNU Lesser General Public License as published by
11d59437c0Smrg the Free Software Foundation; either version 3 of the License, or (at your
12d59437c0Smrg option) any later version.
13d59437c0Smrg 
14d59437c0Smrg The GNU MPFR Library is distributed in the hope that it will be useful, but
15d59437c0Smrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16d59437c0Smrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17d59437c0Smrg License for more details.
18d59437c0Smrg 
19d59437c0Smrg You should have received a copy of the GNU Lesser General Public License
20d59437c0Smrg along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
212ba2404bSmrg https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22d59437c0Smrg 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23d59437c0Smrg 
24d59437c0Smrg #define MPFR_NEED_LONGLONG_H
25d59437c0Smrg #include "mpfr-impl.h"
26d59437c0Smrg 
27d59437c0Smrg static int mpfr_yn_asympt (mpfr_ptr, long, mpfr_srcptr, mpfr_rnd_t);
28d59437c0Smrg 
29d59437c0Smrg int
mpfr_y0(mpfr_ptr res,mpfr_srcptr z,mpfr_rnd_t r)30d59437c0Smrg mpfr_y0 (mpfr_ptr res, mpfr_srcptr z, mpfr_rnd_t r)
31d59437c0Smrg {
32d59437c0Smrg   return mpfr_yn (res, 0, z, r);
33d59437c0Smrg }
34d59437c0Smrg 
35d59437c0Smrg int
mpfr_y1(mpfr_ptr res,mpfr_srcptr z,mpfr_rnd_t r)36d59437c0Smrg mpfr_y1 (mpfr_ptr res, mpfr_srcptr z, mpfr_rnd_t r)
37d59437c0Smrg {
38d59437c0Smrg   return mpfr_yn (res, 1, z, r);
39d59437c0Smrg }
40d59437c0Smrg 
41d59437c0Smrg /* compute in s an approximation of S1 = sum((n-k)!/k!*y^k,k=0..n)
42d59437c0Smrg    return e >= 0 the exponent difference between the maximal value of |s|
43d59437c0Smrg    during the for loop and the final value of |s|.
44d59437c0Smrg */
45d59437c0Smrg static mpfr_exp_t
mpfr_yn_s1(mpfr_ptr s,mpfr_srcptr y,unsigned long n)46d59437c0Smrg mpfr_yn_s1 (mpfr_ptr s, mpfr_srcptr y, unsigned long n)
47d59437c0Smrg {
48d59437c0Smrg   unsigned long k;
49d59437c0Smrg   mpz_t f;
50d59437c0Smrg   mpfr_exp_t e, emax;
51d59437c0Smrg 
52d59437c0Smrg   mpz_init_set_ui (f, 1);
53d59437c0Smrg   /* we compute n!*S1 = sum(a[k]*y^k,k=0..n) where a[k] = n!*(n-k)!/k!,
54d59437c0Smrg      a[0] = (n!)^2, a[1] = n!*(n-1)!, ..., a[n-1] = n, a[n] = 1 */
55d59437c0Smrg   mpfr_set_ui (s, 1, MPFR_RNDN); /* a[n] */
56d59437c0Smrg   emax = MPFR_EXP(s);
57d59437c0Smrg   for (k = n; k-- > 0;)
58d59437c0Smrg     {
59d59437c0Smrg       /* a[k]/a[k+1] = (n-k)!/k!/(n-(k+1))!*(k+1)! = (k+1)*(n-k) */
60d59437c0Smrg       mpfr_mul (s, s, y, MPFR_RNDN);
61d59437c0Smrg       mpz_mul_ui (f, f, n - k);
62d59437c0Smrg       mpz_mul_ui (f, f, k + 1);
63d59437c0Smrg       /* invariant: f = a[k] */
64d59437c0Smrg       mpfr_add_z (s, s, f, MPFR_RNDN);
65d59437c0Smrg       e = MPFR_EXP(s);
66d59437c0Smrg       if (e > emax)
67d59437c0Smrg         emax = e;
68d59437c0Smrg     }
69d59437c0Smrg   /* now we have f = (n!)^2 */
70d59437c0Smrg   mpz_sqrt (f, f);
71d59437c0Smrg   mpfr_div_z (s, s, f, MPFR_RNDN);
72d59437c0Smrg   mpz_clear (f);
73d59437c0Smrg   return emax - MPFR_EXP(s);
74d59437c0Smrg }
75d59437c0Smrg 
76d59437c0Smrg /* compute in s an approximation of
77d59437c0Smrg    S3 = c*sum((h(k)+h(n+k))*y^k/k!/(n+k)!,k=0..infinity)
78d59437c0Smrg    where h(k) = 1 + 1/2 + ... + 1/k
79d59437c0Smrg    k=0: h(n)
80d59437c0Smrg    k=1: 1+h(n+1)
81d59437c0Smrg    k=2: 3/2+h(n+2)
82d59437c0Smrg    Returns e such that the error is bounded by 2^e ulp(s).
83d59437c0Smrg */
84d59437c0Smrg static mpfr_exp_t
mpfr_yn_s3(mpfr_ptr s,mpfr_srcptr y,mpfr_srcptr c,unsigned long n)85d59437c0Smrg mpfr_yn_s3 (mpfr_ptr s, mpfr_srcptr y, mpfr_srcptr c, unsigned long n)
86d59437c0Smrg {
87d59437c0Smrg   unsigned long k, zz;
88d59437c0Smrg   mpfr_t t, u;
89d59437c0Smrg   mpz_t p, q; /* p/q will store h(k)+h(n+k) */
90d59437c0Smrg   mpfr_exp_t exps, expU;
91d59437c0Smrg 
92d59437c0Smrg   zz = mpfr_get_ui (y, MPFR_RNDU); /* y = z^2/4 */
93d59437c0Smrg   MPFR_ASSERTN (zz < ULONG_MAX - 2);
94d59437c0Smrg   zz += 2; /* z^2 <= 2^zz */
95d59437c0Smrg   mpz_init_set_ui (p, 0);
96d59437c0Smrg   mpz_init_set_ui (q, 1);
97d59437c0Smrg   /* initialize p/q to h(n) */
98d59437c0Smrg   for (k = 1; k <= n; k++)
99d59437c0Smrg     {
100d59437c0Smrg       /* p/q + 1/k = (k*p+q)/(q*k) */
101d59437c0Smrg       mpz_mul_ui (p, p, k);
102d59437c0Smrg       mpz_add (p, p, q);
103d59437c0Smrg       mpz_mul_ui (q, q, k);
104d59437c0Smrg     }
105d59437c0Smrg   mpfr_init2 (t, MPFR_PREC(s));
106d59437c0Smrg   mpfr_init2 (u, MPFR_PREC(s));
107d59437c0Smrg   mpfr_fac_ui (t, n, MPFR_RNDN);
108d59437c0Smrg   mpfr_div (t, c, t, MPFR_RNDN);    /* c/n! */
109d59437c0Smrg   mpfr_mul_z (u, t, p, MPFR_RNDN);
110d59437c0Smrg   mpfr_div_z (s, u, q, MPFR_RNDN);
111d59437c0Smrg   exps = MPFR_EXP (s);
112d59437c0Smrg   expU = exps;
113d59437c0Smrg   for (k = 1; ;k ++)
114d59437c0Smrg     {
115d59437c0Smrg       /* update t */
116d59437c0Smrg       mpfr_mul (t, t, y, MPFR_RNDN);
117d59437c0Smrg       mpfr_div_ui (t, t, k, MPFR_RNDN);
118d59437c0Smrg       mpfr_div_ui (t, t, n + k, MPFR_RNDN);
119d59437c0Smrg       /* update p/q:
120d59437c0Smrg          p/q + 1/k + 1/(n+k) = [p*k*(n+k) + q*(n+k) + q*k]/(q*k*(n+k)) */
121d59437c0Smrg       mpz_mul_ui (p, p, k);
122d59437c0Smrg       mpz_mul_ui (p, p, n + k);
123d59437c0Smrg       mpz_addmul_ui (p, q, n + 2 * k);
124d59437c0Smrg       mpz_mul_ui (q, q, k);
125d59437c0Smrg       mpz_mul_ui (q, q, n + k);
126d59437c0Smrg       mpfr_mul_z (u, t, p, MPFR_RNDN);
127d59437c0Smrg       mpfr_div_z (u, u, q, MPFR_RNDN);
128d59437c0Smrg       exps = MPFR_EXP (u);
129d59437c0Smrg       if (exps > expU)
130d59437c0Smrg         expU = exps;
131d59437c0Smrg       mpfr_add (s, s, u, MPFR_RNDN);
132d59437c0Smrg       exps = MPFR_EXP (s);
133d59437c0Smrg       if (exps > expU)
134d59437c0Smrg         expU = exps;
135d59437c0Smrg       if (MPFR_EXP (u) + (mpfr_exp_t) MPFR_PREC (u) < MPFR_EXP (s) &&
136d59437c0Smrg           zz / (2 * k) < k + n)
137d59437c0Smrg         break;
138d59437c0Smrg     }
139d59437c0Smrg   mpfr_clear (t);
140d59437c0Smrg   mpfr_clear (u);
141d59437c0Smrg   mpz_clear (p);
142d59437c0Smrg   mpz_clear (q);
143d59437c0Smrg   exps = expU - MPFR_EXP (s);
144d59437c0Smrg   /* the error is bounded by (6k^2+33/2k+11) 2^exps ulps
145d59437c0Smrg      <= 8*(k+2)^2 2^exps ulps */
146d59437c0Smrg   return 3 + 2 * MPFR_INT_CEIL_LOG2(k + 2) + exps;
147d59437c0Smrg }
148d59437c0Smrg 
149d59437c0Smrg int
mpfr_yn(mpfr_ptr res,long n,mpfr_srcptr z,mpfr_rnd_t r)150d59437c0Smrg mpfr_yn (mpfr_ptr res, long n, mpfr_srcptr z, mpfr_rnd_t r)
151d59437c0Smrg {
152d59437c0Smrg   int inex;
153d59437c0Smrg   unsigned long absn;
154d59437c0Smrg   MPFR_SAVE_EXPO_DECL (expo);
155d59437c0Smrg 
156d59437c0Smrg   MPFR_LOG_FUNC
157*ec6772edSmrg     (("n=%ld x[%Pd]=%.*Rg rnd=%d", n, mpfr_get_prec (z), mpfr_log_prec, z, r),
158*ec6772edSmrg      ("y[%Pd]=%.*Rg inexact=%d", mpfr_get_prec (res), mpfr_log_prec, res, inex));
159d59437c0Smrg 
160d59437c0Smrg   absn = SAFE_ABS (unsigned long, n);
161d59437c0Smrg 
162d59437c0Smrg   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (z)))
163d59437c0Smrg     {
164d59437c0Smrg       if (MPFR_IS_NAN (z))
165d59437c0Smrg         {
166d59437c0Smrg           MPFR_SET_NAN (res); /* y(n,NaN) = NaN */
167d59437c0Smrg           MPFR_RET_NAN;
168d59437c0Smrg         }
169d59437c0Smrg       /* y(n,z) tends to zero when z goes to +Inf, oscillating around
170d59437c0Smrg          0. We choose to return +0 in that case. */
171d59437c0Smrg       else if (MPFR_IS_INF (z))
172d59437c0Smrg         {
173299c6f0cSmrg           if (MPFR_IS_POS (z))
174d59437c0Smrg             return mpfr_set_ui (res, 0, r);
175d59437c0Smrg           else /* y(n,-Inf) = NaN */
176d59437c0Smrg             {
177d59437c0Smrg               MPFR_SET_NAN (res);
178d59437c0Smrg               MPFR_RET_NAN;
179d59437c0Smrg             }
180d59437c0Smrg         }
181d59437c0Smrg       else /* y(n,z) tends to -Inf for n >= 0 or n even, to +Inf otherwise,
182d59437c0Smrg               when z goes to zero */
183d59437c0Smrg         {
184d59437c0Smrg           MPFR_SET_INF(res);
185d59437c0Smrg           if (n >= 0 || ((unsigned long) n & 1) == 0)
186d59437c0Smrg             MPFR_SET_NEG(res);
187d59437c0Smrg           else
188d59437c0Smrg             MPFR_SET_POS(res);
189299c6f0cSmrg           MPFR_SET_DIVBY0 ();
190d59437c0Smrg           MPFR_RET(0);
191d59437c0Smrg         }
192d59437c0Smrg     }
193d59437c0Smrg 
194d59437c0Smrg   /* for z < 0, y(n,z) is imaginary except when j(n,|z|) = 0, which we
195d59437c0Smrg      assume does not happen for a rational z. */
196299c6f0cSmrg   if (MPFR_IS_NEG (z))
197d59437c0Smrg     {
198d59437c0Smrg       MPFR_SET_NAN (res);
199d59437c0Smrg       MPFR_RET_NAN;
200d59437c0Smrg     }
201d59437c0Smrg 
202d59437c0Smrg   /* now z is not singular, and z > 0 */
203d59437c0Smrg 
204d59437c0Smrg   MPFR_SAVE_EXPO_MARK (expo);
205d59437c0Smrg 
206d59437c0Smrg   /* Deal with tiny arguments. We have:
207d59437c0Smrg      y0(z) = 2 log(z)/Pi + 2 (euler - log(2))/Pi + O(log(z)*z^2), more
208d59437c0Smrg      precisely for 0 <= z <= 1/2, with g(z) = 2/Pi + 2(euler-log(2))/Pi/log(z),
209d59437c0Smrg                 g(z) - 0.41*z^2 < y0(z)/log(z) < g(z)
210d59437c0Smrg      thus since log(z) is negative:
211d59437c0Smrg              g(z)*log(z) < y0(z) < (g(z) - z^2/2)*log(z)
212d59437c0Smrg      and since |g(z)| >= 0.63 for 0 <= z <= 1/2, the relative error on
213d59437c0Smrg      y0(z)/log(z) is bounded by 0.41*z^2/0.63 <= 0.66*z^2.
214d59437c0Smrg      Note: we use both the main term in log(z) and the constant term, because
215d59437c0Smrg      otherwise the relative error would be only in 1/log(|log(z)|).
216d59437c0Smrg   */
217d59437c0Smrg   if (n == 0 && MPFR_EXP(z) < - (mpfr_exp_t) (MPFR_PREC(res) / 2))
218d59437c0Smrg     {
219d59437c0Smrg       mpfr_t l, h, t, logz;
220d59437c0Smrg       mpfr_prec_t prec;
221d59437c0Smrg       int ok, inex2;
222d59437c0Smrg 
223d59437c0Smrg       prec = MPFR_PREC(res) + 10;
224d59437c0Smrg       mpfr_init2 (l, prec);
225d59437c0Smrg       mpfr_init2 (h, prec);
226d59437c0Smrg       mpfr_init2 (t, prec);
227d59437c0Smrg       mpfr_init2 (logz, prec);
228d59437c0Smrg       /* first enclose log(z) + euler - log(2) = log(z/2) + euler */
229d59437c0Smrg       mpfr_log (logz, z, MPFR_RNDD);    /* lower bound of log(z) */
230d59437c0Smrg       mpfr_set (h, logz, MPFR_RNDU);    /* exact */
231d59437c0Smrg       mpfr_nextabove (h);               /* upper bound of log(z) */
232d59437c0Smrg       mpfr_const_euler (t, MPFR_RNDD);  /* lower bound of euler */
233d59437c0Smrg       mpfr_add (l, logz, t, MPFR_RNDD); /* lower bound of log(z) + euler */
234d59437c0Smrg       mpfr_nextabove (t);               /* upper bound of euler */
235d59437c0Smrg       mpfr_add (h, h, t, MPFR_RNDU);    /* upper bound of log(z) + euler */
236d59437c0Smrg       mpfr_const_log2 (t, MPFR_RNDU);   /* upper bound of log(2) */
237d59437c0Smrg       mpfr_sub (l, l, t, MPFR_RNDD);    /* lower bound of log(z/2) + euler */
238d59437c0Smrg       mpfr_nextbelow (t);               /* lower bound of log(2) */
239d59437c0Smrg       mpfr_sub (h, h, t, MPFR_RNDU);    /* upper bound of log(z/2) + euler */
240d59437c0Smrg       mpfr_const_pi (t, MPFR_RNDU);     /* upper bound of Pi */
241d59437c0Smrg       mpfr_div (l, l, t, MPFR_RNDD);    /* lower bound of (log(z/2)+euler)/Pi */
242d59437c0Smrg       mpfr_nextbelow (t);               /* lower bound of Pi */
243d59437c0Smrg       mpfr_div (h, h, t, MPFR_RNDD);    /* upper bound of (log(z/2)+euler)/Pi */
244d59437c0Smrg       mpfr_mul_2ui (l, l, 1, MPFR_RNDD); /* lower bound on g(z)*log(z) */
245d59437c0Smrg       mpfr_mul_2ui (h, h, 1, MPFR_RNDU); /* upper bound on g(z)*log(z) */
246d59437c0Smrg       /* we now have l <= g(z)*log(z) <= h, and we need to add -z^2/2*log(z)
247d59437c0Smrg          to h */
2482ba2404bSmrg       mpfr_sqr (t, z, MPFR_RNDU);        /* upper bound on z^2 */
249d59437c0Smrg       /* since logz is negative, a lower bound corresponds to an upper bound
250d59437c0Smrg          for its absolute value */
251d59437c0Smrg       mpfr_neg (t, t, MPFR_RNDD);
252d59437c0Smrg       mpfr_div_2ui (t, t, 1, MPFR_RNDD);
253d59437c0Smrg       mpfr_mul (t, t, logz, MPFR_RNDU);  /* upper bound on z^2/2*log(z) */
254d59437c0Smrg       mpfr_add (h, h, t, MPFR_RNDU);
255d59437c0Smrg       inex = mpfr_prec_round (l, MPFR_PREC(res), r);
256d59437c0Smrg       inex2 = mpfr_prec_round (h, MPFR_PREC(res), r);
257d59437c0Smrg       /* we need h=l and inex=inex2 */
258d59437c0Smrg       ok = (inex == inex2) && mpfr_equal_p (l, h);
259d59437c0Smrg       if (ok)
260d59437c0Smrg         mpfr_set (res, h, r); /* exact */
261d59437c0Smrg       mpfr_clear (l);
262d59437c0Smrg       mpfr_clear (h);
263d59437c0Smrg       mpfr_clear (t);
264d59437c0Smrg       mpfr_clear (logz);
265d59437c0Smrg       if (ok)
266d59437c0Smrg         goto end;
267d59437c0Smrg     }
268d59437c0Smrg 
269d59437c0Smrg   /* small argument check for y1(z) = -2/Pi/z + O(log(z)):
270d59437c0Smrg      for 0 <= z <= 1, |y1(z) + 2/Pi/z| <= 0.25 */
271d59437c0Smrg   if (n == 1 && MPFR_EXP(z) + 1 < - (mpfr_exp_t) MPFR_PREC(res))
272d59437c0Smrg     {
273d59437c0Smrg       mpfr_t y;
274d59437c0Smrg       mpfr_prec_t prec;
275d59437c0Smrg       mpfr_exp_t err1;
276d59437c0Smrg       int ok;
277d59437c0Smrg       MPFR_BLOCK_DECL (flags);
278d59437c0Smrg 
279d59437c0Smrg       /* since 2/Pi > 0.5, and |y1(z)| >= |2/Pi/z|, if z <= 2^(-emax-1),
280d59437c0Smrg          then |y1(z)| > 2^emax */
281d59437c0Smrg       prec = MPFR_PREC(res) + 10;
282d59437c0Smrg       mpfr_init2 (y, prec);
283d59437c0Smrg       mpfr_const_pi (y, MPFR_RNDU); /* Pi*(1+u)^2, where here and below u
284d59437c0Smrg                                       represents a quantity <= 1/2^prec */
285d59437c0Smrg       mpfr_mul (y, y, z, MPFR_RNDU); /* Pi*z * (1+u)^4, upper bound */
286d59437c0Smrg       MPFR_BLOCK (flags, mpfr_ui_div (y, 2, y, MPFR_RNDZ));
287d59437c0Smrg       /* 2/Pi/z * (1+u)^6, lower bound, with possible overflow */
288d59437c0Smrg       if (MPFR_OVERFLOW (flags))
289d59437c0Smrg         {
290d59437c0Smrg           mpfr_clear (y);
291d59437c0Smrg           MPFR_SAVE_EXPO_FREE (expo);
292d59437c0Smrg           return mpfr_overflow (res, r, -1);
293d59437c0Smrg         }
294d59437c0Smrg       mpfr_neg (y, y, MPFR_RNDN);
295d59437c0Smrg       /* (1+u)^6 can be written 1+7u [for another value of u], thus the
296d59437c0Smrg          error on 2/Pi/z is less than 7ulp(y). The truncation error is less
297d59437c0Smrg          than 1/4, thus if ulp(y)>=1/4, the total error is less than 8ulp(y),
298d59437c0Smrg          otherwise it is less than 1/4+7/8 <= 2. */
299d59437c0Smrg       if (MPFR_EXP(y) + 2 >= MPFR_PREC(y)) /* ulp(y) >= 1/4 */
300d59437c0Smrg         err1 = 3;
301d59437c0Smrg       else /* ulp(y) <= 1/8 */
302d59437c0Smrg         err1 = (mpfr_exp_t) MPFR_PREC(y) - MPFR_EXP(y) + 1;
303d59437c0Smrg       ok = MPFR_CAN_ROUND (y, prec - err1, MPFR_PREC(res), r);
304d59437c0Smrg       if (ok)
305d59437c0Smrg         inex = mpfr_set (res, y, r);
306d59437c0Smrg       mpfr_clear (y);
307d59437c0Smrg       if (ok)
308d59437c0Smrg         goto end;
309d59437c0Smrg     }
310d59437c0Smrg 
311d59437c0Smrg   /* we can use the asymptotic expansion as soon as z > p log(2)/2,
312d59437c0Smrg      but to get some margin we use it for z > p/2 */
313d59437c0Smrg   if (mpfr_cmp_ui (z, MPFR_PREC(res) / 2 + 3) > 0)
314d59437c0Smrg     {
315d59437c0Smrg       inex = mpfr_yn_asympt (res, n, z, r);
316d59437c0Smrg       if (inex != 0)
317d59437c0Smrg         goto end;
318d59437c0Smrg     }
319d59437c0Smrg 
320d59437c0Smrg   /* General case */
321d59437c0Smrg   {
322d59437c0Smrg     mpfr_prec_t prec;
323d59437c0Smrg     mpfr_exp_t err1, err2, err3;
324d59437c0Smrg     mpfr_t y, s1, s2, s3;
325d59437c0Smrg     MPFR_ZIV_DECL (loop);
326d59437c0Smrg 
327d59437c0Smrg     prec = MPFR_PREC(res) + 2 * MPFR_INT_CEIL_LOG2 (MPFR_PREC (res)) + 13;
328ba125506Smrg 
329ba125506Smrg     mpfr_init2 (y, prec);
330ba125506Smrg     mpfr_init2 (s1, prec);
331ba125506Smrg     mpfr_init2 (s2, prec);
332ba125506Smrg     mpfr_init2 (s3, prec);
333ba125506Smrg 
334d59437c0Smrg     MPFR_ZIV_INIT (loop, prec);
335d59437c0Smrg     for (;;)
336d59437c0Smrg       {
337d59437c0Smrg         mpfr_set_prec (y, prec);
338d59437c0Smrg         mpfr_set_prec (s1, prec);
339d59437c0Smrg         mpfr_set_prec (s2, prec);
340d59437c0Smrg         mpfr_set_prec (s3, prec);
341d59437c0Smrg 
3422ba2404bSmrg         mpfr_sqr (y, z, MPFR_RNDN);
343d59437c0Smrg         mpfr_div_2ui (y, y, 2, MPFR_RNDN); /* z^2/4 */
344d59437c0Smrg 
345d59437c0Smrg         /* store (z/2)^n temporarily in s2 */
346d59437c0Smrg         mpfr_pow_ui (s2, z, absn, MPFR_RNDN);
347d59437c0Smrg         mpfr_div_2si (s2, s2, absn, MPFR_RNDN);
348d59437c0Smrg 
349d59437c0Smrg         /* compute S1 * (z/2)^(-n) */
350d59437c0Smrg         if (n == 0)
351d59437c0Smrg           {
352d59437c0Smrg             mpfr_set_ui (s1, 0, MPFR_RNDN);
353d59437c0Smrg             err1 = 0;
354d59437c0Smrg           }
355d59437c0Smrg         else
356d59437c0Smrg           err1 = mpfr_yn_s1 (s1, y, absn - 1);
357d59437c0Smrg         mpfr_div (s1, s1, s2, MPFR_RNDN); /* (z/2)^(-n) * S1 */
358d59437c0Smrg         /* See algorithms.tex: the relative error on s1 is bounded by
359d59437c0Smrg            (3n+3)*2^(e+1-prec). */
360d59437c0Smrg         err1 = MPFR_INT_CEIL_LOG2 (3 * absn + 3) + err1 + 1;
361d59437c0Smrg         /* rel_err(s1) <= 2^(err1-prec), thus err(s1) <= 2^err1 ulps */
362d59437c0Smrg 
363d59437c0Smrg         /* compute (z/2)^n * S3 */
364d59437c0Smrg         mpfr_neg (y, y, MPFR_RNDN); /* -z^2/4 */
365d59437c0Smrg         err3 = mpfr_yn_s3 (s3, y, s2, absn); /* (z/2)^n * S3 */
366d59437c0Smrg         /* the error on s3 is bounded by 2^err3 ulps */
367d59437c0Smrg 
368d59437c0Smrg         /* add s1+s3 */
369d59437c0Smrg         err1 += MPFR_EXP(s1);
370d59437c0Smrg         mpfr_add (s1, s1, s3, MPFR_RNDN);
371d59437c0Smrg         /* the error is bounded by 1/2 + 2^err1*2^(- EXP(s1))
372d59437c0Smrg            + 2^err3*2^(EXP(s3) - EXP(s1)) */
373d59437c0Smrg         err3 += MPFR_EXP(s3);
374d59437c0Smrg         err1 = (err3 > err1) ? err3 + 1 : err1 + 1;
375d59437c0Smrg         err1 -= MPFR_EXP(s1);
376d59437c0Smrg         err1 = (err1 >= 0) ? err1 + 1 : 1;
377d59437c0Smrg         /* now the error on s1 is bounded by 2^err1*ulp(s1) */
378d59437c0Smrg 
379d59437c0Smrg         /* compute S2 */
380d59437c0Smrg         mpfr_div_2ui (s2, z, 1, MPFR_RNDN); /* z/2 */
381d59437c0Smrg         mpfr_log (s2, s2, MPFR_RNDN); /* log(z/2) */
382d59437c0Smrg         mpfr_const_euler (s3, MPFR_RNDN);
383d59437c0Smrg         err2 = MPFR_EXP(s2) > MPFR_EXP(s3) ? MPFR_EXP(s2) : MPFR_EXP(s3);
384d59437c0Smrg         mpfr_add (s2, s2, s3, MPFR_RNDN); /* log(z/2) + gamma */
385d59437c0Smrg         err2 -= MPFR_EXP(s2);
386d59437c0Smrg         mpfr_mul_2ui (s2, s2, 1, MPFR_RNDN); /* 2*(log(z/2) + gamma) */
387d59437c0Smrg         mpfr_jn (s3, absn, z, MPFR_RNDN); /* Jn(z) */
388d59437c0Smrg         mpfr_mul (s2, s2, s3, MPFR_RNDN); /* 2*(log(z/2) + gamma)*Jn(z) */
389d59437c0Smrg         err2 += 4; /* the error on s2 is bounded by 2^err2 ulps, see
390d59437c0Smrg                       algorithms.tex */
391d59437c0Smrg 
392d59437c0Smrg         /* add all three sums */
393d59437c0Smrg         err1 += MPFR_EXP(s1); /* the error on s1 is bounded by 2^err1 */
394d59437c0Smrg         err2 += MPFR_EXP(s2); /* the error on s2 is bounded by 2^err2 */
395d59437c0Smrg         mpfr_sub (s2, s2, s1, MPFR_RNDN); /* s2 - (s1+s3) */
396d59437c0Smrg         err2 = (err1 > err2) ? err1 + 1 : err2 + 1;
397d59437c0Smrg         err2 -= MPFR_EXP(s2);
398d59437c0Smrg         err2 = (err2 >= 0) ? err2 + 1 : 1;
399d59437c0Smrg         /* now the error on s2 is bounded by 2^err2*ulp(s2) */
400d59437c0Smrg         mpfr_const_pi (y, MPFR_RNDN); /* error bounded by 1 ulp */
401d59437c0Smrg         mpfr_div (s2, s2, y, MPFR_RNDN); /* error bounded by
402d59437c0Smrg                                            2^(err2+1)*ulp(s2) */
403d59437c0Smrg         err2 ++;
404d59437c0Smrg 
405d59437c0Smrg         if (MPFR_LIKELY (MPFR_CAN_ROUND (s2, prec - err2, MPFR_PREC(res), r)))
406d59437c0Smrg           break;
407d59437c0Smrg         MPFR_ZIV_NEXT (loop, prec);
408d59437c0Smrg       }
409d59437c0Smrg     MPFR_ZIV_FREE (loop);
410d59437c0Smrg 
411d59437c0Smrg     /* Assume two's complement for the test n & 1 */
412d59437c0Smrg     inex = mpfr_set4 (res, s2, r, n >= 0 || (n & 1) == 0 ?
413d59437c0Smrg                       MPFR_SIGN (s2) : - MPFR_SIGN (s2));
414d59437c0Smrg 
415d59437c0Smrg     mpfr_clear (y);
416d59437c0Smrg     mpfr_clear (s1);
417d59437c0Smrg     mpfr_clear (s2);
418d59437c0Smrg     mpfr_clear (s3);
419d59437c0Smrg   }
420d59437c0Smrg 
421d59437c0Smrg  end:
422d59437c0Smrg   MPFR_SAVE_EXPO_FREE (expo);
423d59437c0Smrg   return mpfr_check_range (res, inex, r);
424d59437c0Smrg }
425d59437c0Smrg 
426d59437c0Smrg #define MPFR_YN
427d59437c0Smrg #include "jyn_asympt.c"
428