14a238c70SJohn Marino /* mpfr_y0, mpfr_y1, mpfr_yn -- Bessel functions of 2nd kind, integer order.
24a238c70SJohn Marino http://www.opengroup.org/onlinepubs/009695399/functions/y0.html
34a238c70SJohn Marino
4*ab6d115fSJohn Marino Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
5*ab6d115fSJohn Marino Contributed by the AriC and Caramel projects, INRIA.
64a238c70SJohn Marino
74a238c70SJohn Marino This file is part of the GNU MPFR Library.
84a238c70SJohn Marino
94a238c70SJohn Marino The GNU MPFR Library is free software; you can redistribute it and/or modify
104a238c70SJohn Marino it under the terms of the GNU Lesser General Public License as published by
114a238c70SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
124a238c70SJohn Marino option) any later version.
134a238c70SJohn Marino
144a238c70SJohn Marino The GNU MPFR Library is distributed in the hope that it will be useful, but
154a238c70SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
164a238c70SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
174a238c70SJohn Marino License for more details.
184a238c70SJohn Marino
194a238c70SJohn Marino You should have received a copy of the GNU Lesser General Public License
204a238c70SJohn Marino along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
214a238c70SJohn Marino http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
224a238c70SJohn Marino 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
234a238c70SJohn Marino
244a238c70SJohn Marino #define MPFR_NEED_LONGLONG_H
254a238c70SJohn Marino #include "mpfr-impl.h"
264a238c70SJohn Marino
274a238c70SJohn Marino static int mpfr_yn_asympt (mpfr_ptr, long, mpfr_srcptr, mpfr_rnd_t);
284a238c70SJohn Marino
294a238c70SJohn Marino int
mpfr_y0(mpfr_ptr res,mpfr_srcptr z,mpfr_rnd_t r)304a238c70SJohn Marino mpfr_y0 (mpfr_ptr res, mpfr_srcptr z, mpfr_rnd_t r)
314a238c70SJohn Marino {
324a238c70SJohn Marino return mpfr_yn (res, 0, z, r);
334a238c70SJohn Marino }
344a238c70SJohn Marino
354a238c70SJohn Marino int
mpfr_y1(mpfr_ptr res,mpfr_srcptr z,mpfr_rnd_t r)364a238c70SJohn Marino mpfr_y1 (mpfr_ptr res, mpfr_srcptr z, mpfr_rnd_t r)
374a238c70SJohn Marino {
384a238c70SJohn Marino return mpfr_yn (res, 1, z, r);
394a238c70SJohn Marino }
404a238c70SJohn Marino
414a238c70SJohn Marino /* compute in s an approximation of S1 = sum((n-k)!/k!*y^k,k=0..n)
424a238c70SJohn Marino return e >= 0 the exponent difference between the maximal value of |s|
434a238c70SJohn Marino during the for loop and the final value of |s|.
444a238c70SJohn Marino */
454a238c70SJohn Marino static mpfr_exp_t
mpfr_yn_s1(mpfr_ptr s,mpfr_srcptr y,unsigned long n)464a238c70SJohn Marino mpfr_yn_s1 (mpfr_ptr s, mpfr_srcptr y, unsigned long n)
474a238c70SJohn Marino {
484a238c70SJohn Marino unsigned long k;
494a238c70SJohn Marino mpz_t f;
504a238c70SJohn Marino mpfr_exp_t e, emax;
514a238c70SJohn Marino
524a238c70SJohn Marino mpz_init_set_ui (f, 1);
534a238c70SJohn Marino /* we compute n!*S1 = sum(a[k]*y^k,k=0..n) where a[k] = n!*(n-k)!/k!,
544a238c70SJohn Marino a[0] = (n!)^2, a[1] = n!*(n-1)!, ..., a[n-1] = n, a[n] = 1 */
554a238c70SJohn Marino mpfr_set_ui (s, 1, MPFR_RNDN); /* a[n] */
564a238c70SJohn Marino emax = MPFR_EXP(s);
574a238c70SJohn Marino for (k = n; k-- > 0;)
584a238c70SJohn Marino {
594a238c70SJohn Marino /* a[k]/a[k+1] = (n-k)!/k!/(n-(k+1))!*(k+1)! = (k+1)*(n-k) */
604a238c70SJohn Marino mpfr_mul (s, s, y, MPFR_RNDN);
614a238c70SJohn Marino mpz_mul_ui (f, f, n - k);
624a238c70SJohn Marino mpz_mul_ui (f, f, k + 1);
634a238c70SJohn Marino /* invariant: f = a[k] */
644a238c70SJohn Marino mpfr_add_z (s, s, f, MPFR_RNDN);
654a238c70SJohn Marino e = MPFR_EXP(s);
664a238c70SJohn Marino if (e > emax)
674a238c70SJohn Marino emax = e;
684a238c70SJohn Marino }
694a238c70SJohn Marino /* now we have f = (n!)^2 */
704a238c70SJohn Marino mpz_sqrt (f, f);
714a238c70SJohn Marino mpfr_div_z (s, s, f, MPFR_RNDN);
724a238c70SJohn Marino mpz_clear (f);
734a238c70SJohn Marino return emax - MPFR_EXP(s);
744a238c70SJohn Marino }
754a238c70SJohn Marino
764a238c70SJohn Marino /* compute in s an approximation of
774a238c70SJohn Marino S3 = c*sum((h(k)+h(n+k))*y^k/k!/(n+k)!,k=0..infinity)
784a238c70SJohn Marino where h(k) = 1 + 1/2 + ... + 1/k
794a238c70SJohn Marino k=0: h(n)
804a238c70SJohn Marino k=1: 1+h(n+1)
814a238c70SJohn Marino k=2: 3/2+h(n+2)
824a238c70SJohn Marino Returns e such that the error is bounded by 2^e ulp(s).
834a238c70SJohn Marino */
844a238c70SJohn Marino static mpfr_exp_t
mpfr_yn_s3(mpfr_ptr s,mpfr_srcptr y,mpfr_srcptr c,unsigned long n)854a238c70SJohn Marino mpfr_yn_s3 (mpfr_ptr s, mpfr_srcptr y, mpfr_srcptr c, unsigned long n)
864a238c70SJohn Marino {
874a238c70SJohn Marino unsigned long k, zz;
884a238c70SJohn Marino mpfr_t t, u;
894a238c70SJohn Marino mpz_t p, q; /* p/q will store h(k)+h(n+k) */
904a238c70SJohn Marino mpfr_exp_t exps, expU;
914a238c70SJohn Marino
924a238c70SJohn Marino zz = mpfr_get_ui (y, MPFR_RNDU); /* y = z^2/4 */
934a238c70SJohn Marino MPFR_ASSERTN (zz < ULONG_MAX - 2);
944a238c70SJohn Marino zz += 2; /* z^2 <= 2^zz */
954a238c70SJohn Marino mpz_init_set_ui (p, 0);
964a238c70SJohn Marino mpz_init_set_ui (q, 1);
974a238c70SJohn Marino /* initialize p/q to h(n) */
984a238c70SJohn Marino for (k = 1; k <= n; k++)
994a238c70SJohn Marino {
1004a238c70SJohn Marino /* p/q + 1/k = (k*p+q)/(q*k) */
1014a238c70SJohn Marino mpz_mul_ui (p, p, k);
1024a238c70SJohn Marino mpz_add (p, p, q);
1034a238c70SJohn Marino mpz_mul_ui (q, q, k);
1044a238c70SJohn Marino }
1054a238c70SJohn Marino mpfr_init2 (t, MPFR_PREC(s));
1064a238c70SJohn Marino mpfr_init2 (u, MPFR_PREC(s));
1074a238c70SJohn Marino mpfr_fac_ui (t, n, MPFR_RNDN);
1084a238c70SJohn Marino mpfr_div (t, c, t, MPFR_RNDN); /* c/n! */
1094a238c70SJohn Marino mpfr_mul_z (u, t, p, MPFR_RNDN);
1104a238c70SJohn Marino mpfr_div_z (s, u, q, MPFR_RNDN);
1114a238c70SJohn Marino exps = MPFR_EXP (s);
1124a238c70SJohn Marino expU = exps;
1134a238c70SJohn Marino for (k = 1; ;k ++)
1144a238c70SJohn Marino {
1154a238c70SJohn Marino /* update t */
1164a238c70SJohn Marino mpfr_mul (t, t, y, MPFR_RNDN);
1174a238c70SJohn Marino mpfr_div_ui (t, t, k, MPFR_RNDN);
1184a238c70SJohn Marino mpfr_div_ui (t, t, n + k, MPFR_RNDN);
1194a238c70SJohn Marino /* update p/q:
1204a238c70SJohn Marino p/q + 1/k + 1/(n+k) = [p*k*(n+k) + q*(n+k) + q*k]/(q*k*(n+k)) */
1214a238c70SJohn Marino mpz_mul_ui (p, p, k);
1224a238c70SJohn Marino mpz_mul_ui (p, p, n + k);
1234a238c70SJohn Marino mpz_addmul_ui (p, q, n + 2 * k);
1244a238c70SJohn Marino mpz_mul_ui (q, q, k);
1254a238c70SJohn Marino mpz_mul_ui (q, q, n + k);
1264a238c70SJohn Marino mpfr_mul_z (u, t, p, MPFR_RNDN);
1274a238c70SJohn Marino mpfr_div_z (u, u, q, MPFR_RNDN);
1284a238c70SJohn Marino exps = MPFR_EXP (u);
1294a238c70SJohn Marino if (exps > expU)
1304a238c70SJohn Marino expU = exps;
1314a238c70SJohn Marino mpfr_add (s, s, u, MPFR_RNDN);
1324a238c70SJohn Marino exps = MPFR_EXP (s);
1334a238c70SJohn Marino if (exps > expU)
1344a238c70SJohn Marino expU = exps;
1354a238c70SJohn Marino if (MPFR_EXP (u) + (mpfr_exp_t) MPFR_PREC (u) < MPFR_EXP (s) &&
1364a238c70SJohn Marino zz / (2 * k) < k + n)
1374a238c70SJohn Marino break;
1384a238c70SJohn Marino }
1394a238c70SJohn Marino mpfr_clear (t);
1404a238c70SJohn Marino mpfr_clear (u);
1414a238c70SJohn Marino mpz_clear (p);
1424a238c70SJohn Marino mpz_clear (q);
1434a238c70SJohn Marino exps = expU - MPFR_EXP (s);
1444a238c70SJohn Marino /* the error is bounded by (6k^2+33/2k+11) 2^exps ulps
1454a238c70SJohn Marino <= 8*(k+2)^2 2^exps ulps */
1464a238c70SJohn Marino return 3 + 2 * MPFR_INT_CEIL_LOG2(k + 2) + exps;
1474a238c70SJohn Marino }
1484a238c70SJohn Marino
1494a238c70SJohn Marino int
mpfr_yn(mpfr_ptr res,long n,mpfr_srcptr z,mpfr_rnd_t r)1504a238c70SJohn Marino mpfr_yn (mpfr_ptr res, long n, mpfr_srcptr z, mpfr_rnd_t r)
1514a238c70SJohn Marino {
1524a238c70SJohn Marino int inex;
1534a238c70SJohn Marino unsigned long absn;
1544a238c70SJohn Marino MPFR_SAVE_EXPO_DECL (expo);
1554a238c70SJohn Marino
1564a238c70SJohn Marino MPFR_LOG_FUNC
1574a238c70SJohn Marino (("n=%ld x[%Pu]=%.*Rg rnd=%d", n, mpfr_get_prec (z), mpfr_log_prec, z, r),
1584a238c70SJohn Marino ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (res), mpfr_log_prec, res, inex));
1594a238c70SJohn Marino
1604a238c70SJohn Marino absn = SAFE_ABS (unsigned long, n);
1614a238c70SJohn Marino
1624a238c70SJohn Marino if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (z)))
1634a238c70SJohn Marino {
1644a238c70SJohn Marino if (MPFR_IS_NAN (z))
1654a238c70SJohn Marino {
1664a238c70SJohn Marino MPFR_SET_NAN (res); /* y(n,NaN) = NaN */
1674a238c70SJohn Marino MPFR_RET_NAN;
1684a238c70SJohn Marino }
1694a238c70SJohn Marino /* y(n,z) tends to zero when z goes to +Inf, oscillating around
1704a238c70SJohn Marino 0. We choose to return +0 in that case. */
1714a238c70SJohn Marino else if (MPFR_IS_INF (z))
1724a238c70SJohn Marino {
1734a238c70SJohn Marino if (MPFR_SIGN(z) > 0)
1744a238c70SJohn Marino return mpfr_set_ui (res, 0, r);
1754a238c70SJohn Marino else /* y(n,-Inf) = NaN */
1764a238c70SJohn Marino {
1774a238c70SJohn Marino MPFR_SET_NAN (res);
1784a238c70SJohn Marino MPFR_RET_NAN;
1794a238c70SJohn Marino }
1804a238c70SJohn Marino }
1814a238c70SJohn Marino else /* y(n,z) tends to -Inf for n >= 0 or n even, to +Inf otherwise,
1824a238c70SJohn Marino when z goes to zero */
1834a238c70SJohn Marino {
1844a238c70SJohn Marino MPFR_SET_INF(res);
1854a238c70SJohn Marino if (n >= 0 || ((unsigned long) n & 1) == 0)
1864a238c70SJohn Marino MPFR_SET_NEG(res);
1874a238c70SJohn Marino else
1884a238c70SJohn Marino MPFR_SET_POS(res);
1894a238c70SJohn Marino mpfr_set_divby0 ();
1904a238c70SJohn Marino MPFR_RET(0);
1914a238c70SJohn Marino }
1924a238c70SJohn Marino }
1934a238c70SJohn Marino
1944a238c70SJohn Marino /* for z < 0, y(n,z) is imaginary except when j(n,|z|) = 0, which we
1954a238c70SJohn Marino assume does not happen for a rational z. */
1964a238c70SJohn Marino if (MPFR_SIGN(z) < 0)
1974a238c70SJohn Marino {
1984a238c70SJohn Marino MPFR_SET_NAN (res);
1994a238c70SJohn Marino MPFR_RET_NAN;
2004a238c70SJohn Marino }
2014a238c70SJohn Marino
2024a238c70SJohn Marino /* now z is not singular, and z > 0 */
2034a238c70SJohn Marino
2044a238c70SJohn Marino MPFR_SAVE_EXPO_MARK (expo);
2054a238c70SJohn Marino
2064a238c70SJohn Marino /* Deal with tiny arguments. We have:
2074a238c70SJohn Marino y0(z) = 2 log(z)/Pi + 2 (euler - log(2))/Pi + O(log(z)*z^2), more
2084a238c70SJohn Marino precisely for 0 <= z <= 1/2, with g(z) = 2/Pi + 2(euler-log(2))/Pi/log(z),
2094a238c70SJohn Marino g(z) - 0.41*z^2 < y0(z)/log(z) < g(z)
2104a238c70SJohn Marino thus since log(z) is negative:
2114a238c70SJohn Marino g(z)*log(z) < y0(z) < (g(z) - z^2/2)*log(z)
2124a238c70SJohn Marino and since |g(z)| >= 0.63 for 0 <= z <= 1/2, the relative error on
2134a238c70SJohn Marino y0(z)/log(z) is bounded by 0.41*z^2/0.63 <= 0.66*z^2.
2144a238c70SJohn Marino Note: we use both the main term in log(z) and the constant term, because
2154a238c70SJohn Marino otherwise the relative error would be only in 1/log(|log(z)|).
2164a238c70SJohn Marino */
2174a238c70SJohn Marino if (n == 0 && MPFR_EXP(z) < - (mpfr_exp_t) (MPFR_PREC(res) / 2))
2184a238c70SJohn Marino {
2194a238c70SJohn Marino mpfr_t l, h, t, logz;
2204a238c70SJohn Marino mpfr_prec_t prec;
2214a238c70SJohn Marino int ok, inex2;
2224a238c70SJohn Marino
2234a238c70SJohn Marino prec = MPFR_PREC(res) + 10;
2244a238c70SJohn Marino mpfr_init2 (l, prec);
2254a238c70SJohn Marino mpfr_init2 (h, prec);
2264a238c70SJohn Marino mpfr_init2 (t, prec);
2274a238c70SJohn Marino mpfr_init2 (logz, prec);
2284a238c70SJohn Marino /* first enclose log(z) + euler - log(2) = log(z/2) + euler */
2294a238c70SJohn Marino mpfr_log (logz, z, MPFR_RNDD); /* lower bound of log(z) */
2304a238c70SJohn Marino mpfr_set (h, logz, MPFR_RNDU); /* exact */
2314a238c70SJohn Marino mpfr_nextabove (h); /* upper bound of log(z) */
2324a238c70SJohn Marino mpfr_const_euler (t, MPFR_RNDD); /* lower bound of euler */
2334a238c70SJohn Marino mpfr_add (l, logz, t, MPFR_RNDD); /* lower bound of log(z) + euler */
2344a238c70SJohn Marino mpfr_nextabove (t); /* upper bound of euler */
2354a238c70SJohn Marino mpfr_add (h, h, t, MPFR_RNDU); /* upper bound of log(z) + euler */
2364a238c70SJohn Marino mpfr_const_log2 (t, MPFR_RNDU); /* upper bound of log(2) */
2374a238c70SJohn Marino mpfr_sub (l, l, t, MPFR_RNDD); /* lower bound of log(z/2) + euler */
2384a238c70SJohn Marino mpfr_nextbelow (t); /* lower bound of log(2) */
2394a238c70SJohn Marino mpfr_sub (h, h, t, MPFR_RNDU); /* upper bound of log(z/2) + euler */
2404a238c70SJohn Marino mpfr_const_pi (t, MPFR_RNDU); /* upper bound of Pi */
2414a238c70SJohn Marino mpfr_div (l, l, t, MPFR_RNDD); /* lower bound of (log(z/2)+euler)/Pi */
2424a238c70SJohn Marino mpfr_nextbelow (t); /* lower bound of Pi */
2434a238c70SJohn Marino mpfr_div (h, h, t, MPFR_RNDD); /* upper bound of (log(z/2)+euler)/Pi */
2444a238c70SJohn Marino mpfr_mul_2ui (l, l, 1, MPFR_RNDD); /* lower bound on g(z)*log(z) */
2454a238c70SJohn Marino mpfr_mul_2ui (h, h, 1, MPFR_RNDU); /* upper bound on g(z)*log(z) */
2464a238c70SJohn Marino /* we now have l <= g(z)*log(z) <= h, and we need to add -z^2/2*log(z)
2474a238c70SJohn Marino to h */
2484a238c70SJohn Marino mpfr_mul (t, z, z, MPFR_RNDU); /* upper bound on z^2 */
2494a238c70SJohn Marino /* since logz is negative, a lower bound corresponds to an upper bound
2504a238c70SJohn Marino for its absolute value */
2514a238c70SJohn Marino mpfr_neg (t, t, MPFR_RNDD);
2524a238c70SJohn Marino mpfr_div_2ui (t, t, 1, MPFR_RNDD);
2534a238c70SJohn Marino mpfr_mul (t, t, logz, MPFR_RNDU); /* upper bound on z^2/2*log(z) */
2544a238c70SJohn Marino mpfr_add (h, h, t, MPFR_RNDU);
2554a238c70SJohn Marino inex = mpfr_prec_round (l, MPFR_PREC(res), r);
2564a238c70SJohn Marino inex2 = mpfr_prec_round (h, MPFR_PREC(res), r);
2574a238c70SJohn Marino /* we need h=l and inex=inex2 */
2584a238c70SJohn Marino ok = (inex == inex2) && mpfr_equal_p (l, h);
2594a238c70SJohn Marino if (ok)
2604a238c70SJohn Marino mpfr_set (res, h, r); /* exact */
2614a238c70SJohn Marino mpfr_clear (l);
2624a238c70SJohn Marino mpfr_clear (h);
2634a238c70SJohn Marino mpfr_clear (t);
2644a238c70SJohn Marino mpfr_clear (logz);
2654a238c70SJohn Marino if (ok)
2664a238c70SJohn Marino goto end;
2674a238c70SJohn Marino }
2684a238c70SJohn Marino
2694a238c70SJohn Marino /* small argument check for y1(z) = -2/Pi/z + O(log(z)):
2704a238c70SJohn Marino for 0 <= z <= 1, |y1(z) + 2/Pi/z| <= 0.25 */
2714a238c70SJohn Marino if (n == 1 && MPFR_EXP(z) + 1 < - (mpfr_exp_t) MPFR_PREC(res))
2724a238c70SJohn Marino {
2734a238c70SJohn Marino mpfr_t y;
2744a238c70SJohn Marino mpfr_prec_t prec;
2754a238c70SJohn Marino mpfr_exp_t err1;
2764a238c70SJohn Marino int ok;
2774a238c70SJohn Marino MPFR_BLOCK_DECL (flags);
2784a238c70SJohn Marino
2794a238c70SJohn Marino /* since 2/Pi > 0.5, and |y1(z)| >= |2/Pi/z|, if z <= 2^(-emax-1),
2804a238c70SJohn Marino then |y1(z)| > 2^emax */
2814a238c70SJohn Marino prec = MPFR_PREC(res) + 10;
2824a238c70SJohn Marino mpfr_init2 (y, prec);
2834a238c70SJohn Marino mpfr_const_pi (y, MPFR_RNDU); /* Pi*(1+u)^2, where here and below u
2844a238c70SJohn Marino represents a quantity <= 1/2^prec */
2854a238c70SJohn Marino mpfr_mul (y, y, z, MPFR_RNDU); /* Pi*z * (1+u)^4, upper bound */
2864a238c70SJohn Marino MPFR_BLOCK (flags, mpfr_ui_div (y, 2, y, MPFR_RNDZ));
2874a238c70SJohn Marino /* 2/Pi/z * (1+u)^6, lower bound, with possible overflow */
2884a238c70SJohn Marino if (MPFR_OVERFLOW (flags))
2894a238c70SJohn Marino {
2904a238c70SJohn Marino mpfr_clear (y);
2914a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
2924a238c70SJohn Marino return mpfr_overflow (res, r, -1);
2934a238c70SJohn Marino }
2944a238c70SJohn Marino mpfr_neg (y, y, MPFR_RNDN);
2954a238c70SJohn Marino /* (1+u)^6 can be written 1+7u [for another value of u], thus the
2964a238c70SJohn Marino error on 2/Pi/z is less than 7ulp(y). The truncation error is less
2974a238c70SJohn Marino than 1/4, thus if ulp(y)>=1/4, the total error is less than 8ulp(y),
2984a238c70SJohn Marino otherwise it is less than 1/4+7/8 <= 2. */
2994a238c70SJohn Marino if (MPFR_EXP(y) + 2 >= MPFR_PREC(y)) /* ulp(y) >= 1/4 */
3004a238c70SJohn Marino err1 = 3;
3014a238c70SJohn Marino else /* ulp(y) <= 1/8 */
3024a238c70SJohn Marino err1 = (mpfr_exp_t) MPFR_PREC(y) - MPFR_EXP(y) + 1;
3034a238c70SJohn Marino ok = MPFR_CAN_ROUND (y, prec - err1, MPFR_PREC(res), r);
3044a238c70SJohn Marino if (ok)
3054a238c70SJohn Marino inex = mpfr_set (res, y, r);
3064a238c70SJohn Marino mpfr_clear (y);
3074a238c70SJohn Marino if (ok)
3084a238c70SJohn Marino goto end;
3094a238c70SJohn Marino }
3104a238c70SJohn Marino
3114a238c70SJohn Marino /* we can use the asymptotic expansion as soon as z > p log(2)/2,
3124a238c70SJohn Marino but to get some margin we use it for z > p/2 */
3134a238c70SJohn Marino if (mpfr_cmp_ui (z, MPFR_PREC(res) / 2 + 3) > 0)
3144a238c70SJohn Marino {
3154a238c70SJohn Marino inex = mpfr_yn_asympt (res, n, z, r);
3164a238c70SJohn Marino if (inex != 0)
3174a238c70SJohn Marino goto end;
3184a238c70SJohn Marino }
3194a238c70SJohn Marino
3204a238c70SJohn Marino /* General case */
3214a238c70SJohn Marino {
3224a238c70SJohn Marino mpfr_prec_t prec;
3234a238c70SJohn Marino mpfr_exp_t err1, err2, err3;
3244a238c70SJohn Marino mpfr_t y, s1, s2, s3;
3254a238c70SJohn Marino MPFR_ZIV_DECL (loop);
3264a238c70SJohn Marino
3274a238c70SJohn Marino mpfr_init (y);
3284a238c70SJohn Marino mpfr_init (s1);
3294a238c70SJohn Marino mpfr_init (s2);
3304a238c70SJohn Marino mpfr_init (s3);
3314a238c70SJohn Marino
3324a238c70SJohn Marino prec = MPFR_PREC(res) + 2 * MPFR_INT_CEIL_LOG2 (MPFR_PREC (res)) + 13;
3334a238c70SJohn Marino MPFR_ZIV_INIT (loop, prec);
3344a238c70SJohn Marino for (;;)
3354a238c70SJohn Marino {
3364a238c70SJohn Marino mpfr_set_prec (y, prec);
3374a238c70SJohn Marino mpfr_set_prec (s1, prec);
3384a238c70SJohn Marino mpfr_set_prec (s2, prec);
3394a238c70SJohn Marino mpfr_set_prec (s3, prec);
3404a238c70SJohn Marino
3414a238c70SJohn Marino mpfr_mul (y, z, z, MPFR_RNDN);
3424a238c70SJohn Marino mpfr_div_2ui (y, y, 2, MPFR_RNDN); /* z^2/4 */
3434a238c70SJohn Marino
3444a238c70SJohn Marino /* store (z/2)^n temporarily in s2 */
3454a238c70SJohn Marino mpfr_pow_ui (s2, z, absn, MPFR_RNDN);
3464a238c70SJohn Marino mpfr_div_2si (s2, s2, absn, MPFR_RNDN);
3474a238c70SJohn Marino
3484a238c70SJohn Marino /* compute S1 * (z/2)^(-n) */
3494a238c70SJohn Marino if (n == 0)
3504a238c70SJohn Marino {
3514a238c70SJohn Marino mpfr_set_ui (s1, 0, MPFR_RNDN);
3524a238c70SJohn Marino err1 = 0;
3534a238c70SJohn Marino }
3544a238c70SJohn Marino else
3554a238c70SJohn Marino err1 = mpfr_yn_s1 (s1, y, absn - 1);
3564a238c70SJohn Marino mpfr_div (s1, s1, s2, MPFR_RNDN); /* (z/2)^(-n) * S1 */
3574a238c70SJohn Marino /* See algorithms.tex: the relative error on s1 is bounded by
3584a238c70SJohn Marino (3n+3)*2^(e+1-prec). */
3594a238c70SJohn Marino err1 = MPFR_INT_CEIL_LOG2 (3 * absn + 3) + err1 + 1;
3604a238c70SJohn Marino /* rel_err(s1) <= 2^(err1-prec), thus err(s1) <= 2^err1 ulps */
3614a238c70SJohn Marino
3624a238c70SJohn Marino /* compute (z/2)^n * S3 */
3634a238c70SJohn Marino mpfr_neg (y, y, MPFR_RNDN); /* -z^2/4 */
3644a238c70SJohn Marino err3 = mpfr_yn_s3 (s3, y, s2, absn); /* (z/2)^n * S3 */
3654a238c70SJohn Marino /* the error on s3 is bounded by 2^err3 ulps */
3664a238c70SJohn Marino
3674a238c70SJohn Marino /* add s1+s3 */
3684a238c70SJohn Marino err1 += MPFR_EXP(s1);
3694a238c70SJohn Marino mpfr_add (s1, s1, s3, MPFR_RNDN);
3704a238c70SJohn Marino /* the error is bounded by 1/2 + 2^err1*2^(- EXP(s1))
3714a238c70SJohn Marino + 2^err3*2^(EXP(s3) - EXP(s1)) */
3724a238c70SJohn Marino err3 += MPFR_EXP(s3);
3734a238c70SJohn Marino err1 = (err3 > err1) ? err3 + 1 : err1 + 1;
3744a238c70SJohn Marino err1 -= MPFR_EXP(s1);
3754a238c70SJohn Marino err1 = (err1 >= 0) ? err1 + 1 : 1;
3764a238c70SJohn Marino /* now the error on s1 is bounded by 2^err1*ulp(s1) */
3774a238c70SJohn Marino
3784a238c70SJohn Marino /* compute S2 */
3794a238c70SJohn Marino mpfr_div_2ui (s2, z, 1, MPFR_RNDN); /* z/2 */
3804a238c70SJohn Marino mpfr_log (s2, s2, MPFR_RNDN); /* log(z/2) */
3814a238c70SJohn Marino mpfr_const_euler (s3, MPFR_RNDN);
3824a238c70SJohn Marino err2 = MPFR_EXP(s2) > MPFR_EXP(s3) ? MPFR_EXP(s2) : MPFR_EXP(s3);
3834a238c70SJohn Marino mpfr_add (s2, s2, s3, MPFR_RNDN); /* log(z/2) + gamma */
3844a238c70SJohn Marino err2 -= MPFR_EXP(s2);
3854a238c70SJohn Marino mpfr_mul_2ui (s2, s2, 1, MPFR_RNDN); /* 2*(log(z/2) + gamma) */
3864a238c70SJohn Marino mpfr_jn (s3, absn, z, MPFR_RNDN); /* Jn(z) */
3874a238c70SJohn Marino mpfr_mul (s2, s2, s3, MPFR_RNDN); /* 2*(log(z/2) + gamma)*Jn(z) */
3884a238c70SJohn Marino err2 += 4; /* the error on s2 is bounded by 2^err2 ulps, see
3894a238c70SJohn Marino algorithms.tex */
3904a238c70SJohn Marino
3914a238c70SJohn Marino /* add all three sums */
3924a238c70SJohn Marino err1 += MPFR_EXP(s1); /* the error on s1 is bounded by 2^err1 */
3934a238c70SJohn Marino err2 += MPFR_EXP(s2); /* the error on s2 is bounded by 2^err2 */
3944a238c70SJohn Marino mpfr_sub (s2, s2, s1, MPFR_RNDN); /* s2 - (s1+s3) */
3954a238c70SJohn Marino err2 = (err1 > err2) ? err1 + 1 : err2 + 1;
3964a238c70SJohn Marino err2 -= MPFR_EXP(s2);
3974a238c70SJohn Marino err2 = (err2 >= 0) ? err2 + 1 : 1;
3984a238c70SJohn Marino /* now the error on s2 is bounded by 2^err2*ulp(s2) */
3994a238c70SJohn Marino mpfr_const_pi (y, MPFR_RNDN); /* error bounded by 1 ulp */
4004a238c70SJohn Marino mpfr_div (s2, s2, y, MPFR_RNDN); /* error bounded by
4014a238c70SJohn Marino 2^(err2+1)*ulp(s2) */
4024a238c70SJohn Marino err2 ++;
4034a238c70SJohn Marino
4044a238c70SJohn Marino if (MPFR_LIKELY (MPFR_CAN_ROUND (s2, prec - err2, MPFR_PREC(res), r)))
4054a238c70SJohn Marino break;
4064a238c70SJohn Marino MPFR_ZIV_NEXT (loop, prec);
4074a238c70SJohn Marino }
4084a238c70SJohn Marino MPFR_ZIV_FREE (loop);
4094a238c70SJohn Marino
4104a238c70SJohn Marino /* Assume two's complement for the test n & 1 */
4114a238c70SJohn Marino inex = mpfr_set4 (res, s2, r, n >= 0 || (n & 1) == 0 ?
4124a238c70SJohn Marino MPFR_SIGN (s2) : - MPFR_SIGN (s2));
4134a238c70SJohn Marino
4144a238c70SJohn Marino mpfr_clear (y);
4154a238c70SJohn Marino mpfr_clear (s1);
4164a238c70SJohn Marino mpfr_clear (s2);
4174a238c70SJohn Marino mpfr_clear (s3);
4184a238c70SJohn Marino }
4194a238c70SJohn Marino
4204a238c70SJohn Marino end:
4214a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
4224a238c70SJohn Marino return mpfr_check_range (res, inex, r);
4234a238c70SJohn Marino }
4244a238c70SJohn Marino
4254a238c70SJohn Marino #define MPFR_YN
4264a238c70SJohn Marino #include "jyn_asympt.c"
427