14a238c70SJohn Marino /* mpfr_li2 -- Dilogarithm.
24a238c70SJohn Marino
3*ab6d115fSJohn Marino Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4*ab6d115fSJohn Marino Contributed by the AriC and Caramel projects, INRIA.
54a238c70SJohn Marino
64a238c70SJohn Marino This file is part of the GNU MPFR Library.
74a238c70SJohn Marino
84a238c70SJohn Marino The GNU MPFR Library is free software; you can redistribute it and/or modify
94a238c70SJohn Marino it under the terms of the GNU Lesser General Public License as published by
104a238c70SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
114a238c70SJohn Marino option) any later version.
124a238c70SJohn Marino
134a238c70SJohn Marino The GNU MPFR Library is distributed in the hope that it will be useful, but
144a238c70SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
154a238c70SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
164a238c70SJohn Marino License for more details.
174a238c70SJohn Marino
184a238c70SJohn Marino You should have received a copy of the GNU Lesser General Public License
194a238c70SJohn Marino along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
204a238c70SJohn Marino http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
214a238c70SJohn Marino 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
224a238c70SJohn Marino
234a238c70SJohn Marino #define MPFR_NEED_LONGLONG_H
244a238c70SJohn Marino #include "mpfr-impl.h"
254a238c70SJohn Marino
264a238c70SJohn Marino /* Compute the alternating series
274a238c70SJohn Marino s = S(z) = \sum_{k=0}^infty B_{2k} (z))^{2k+1} / (2k+1)!
284a238c70SJohn Marino with 0 < z <= log(2) to the precision of s rounded in the direction
294a238c70SJohn Marino rnd_mode.
304a238c70SJohn Marino Return the maximum index of the truncature which is useful
314a238c70SJohn Marino for determinating the relative error.
324a238c70SJohn Marino */
334a238c70SJohn Marino static int
li2_series(mpfr_t sum,mpfr_srcptr z,mpfr_rnd_t rnd_mode)344a238c70SJohn Marino li2_series (mpfr_t sum, mpfr_srcptr z, mpfr_rnd_t rnd_mode)
354a238c70SJohn Marino {
364a238c70SJohn Marino int i, Bm, Bmax;
374a238c70SJohn Marino mpfr_t s, u, v, w;
384a238c70SJohn Marino mpfr_prec_t sump, p;
394a238c70SJohn Marino mpfr_exp_t se, err;
404a238c70SJohn Marino mpz_t *B;
414a238c70SJohn Marino MPFR_ZIV_DECL (loop);
424a238c70SJohn Marino
434a238c70SJohn Marino /* The series converges for |z| < 2 pi, but in mpfr_li2 the argument is
444a238c70SJohn Marino reduced so that 0 < z <= log(2). Here is additionnal check that z is
454a238c70SJohn Marino (nearly) correct */
464a238c70SJohn Marino MPFR_ASSERTD (MPFR_IS_STRICTPOS (z));
474a238c70SJohn Marino MPFR_ASSERTD (mpfr_cmp_d (z, 0.6953125) <= 0);
484a238c70SJohn Marino
494a238c70SJohn Marino sump = MPFR_PREC (sum); /* target precision */
504a238c70SJohn Marino p = sump + MPFR_INT_CEIL_LOG2 (sump) + 4; /* the working precision */
514a238c70SJohn Marino mpfr_init2 (s, p);
524a238c70SJohn Marino mpfr_init2 (u, p);
534a238c70SJohn Marino mpfr_init2 (v, p);
544a238c70SJohn Marino mpfr_init2 (w, p);
554a238c70SJohn Marino
564a238c70SJohn Marino B = mpfr_bernoulli_internal ((mpz_t *) 0, 0);
574a238c70SJohn Marino Bm = Bmax = 1;
584a238c70SJohn Marino
594a238c70SJohn Marino MPFR_ZIV_INIT (loop, p);
604a238c70SJohn Marino for (;;)
614a238c70SJohn Marino {
624a238c70SJohn Marino mpfr_sqr (u, z, MPFR_RNDU);
634a238c70SJohn Marino mpfr_set (v, z, MPFR_RNDU);
644a238c70SJohn Marino mpfr_set (s, z, MPFR_RNDU);
654a238c70SJohn Marino se = MPFR_GET_EXP (s);
664a238c70SJohn Marino err = 0;
674a238c70SJohn Marino
684a238c70SJohn Marino for (i = 1;; i++)
694a238c70SJohn Marino {
704a238c70SJohn Marino if (i >= Bmax)
714a238c70SJohn Marino B = mpfr_bernoulli_internal (B, Bmax++); /* B_2i*(2i+1)!, exact */
724a238c70SJohn Marino
734a238c70SJohn Marino mpfr_mul (v, u, v, MPFR_RNDU);
744a238c70SJohn Marino mpfr_div_ui (v, v, 2 * i, MPFR_RNDU);
754a238c70SJohn Marino mpfr_div_ui (v, v, 2 * i, MPFR_RNDU);
764a238c70SJohn Marino mpfr_div_ui (v, v, 2 * i + 1, MPFR_RNDU);
774a238c70SJohn Marino mpfr_div_ui (v, v, 2 * i + 1, MPFR_RNDU);
784a238c70SJohn Marino /* here, v_2i = v_{2i-2} / (2i * (2i+1))^2 */
794a238c70SJohn Marino
804a238c70SJohn Marino mpfr_mul_z (w, v, B[i], MPFR_RNDN);
814a238c70SJohn Marino /* here, w_2i = v_2i * B_2i * (2i+1)! with
824a238c70SJohn Marino error(w_2i) < 2^(5 * i + 8) ulp(w_2i) (see algorithms.tex) */
834a238c70SJohn Marino
844a238c70SJohn Marino mpfr_add (s, s, w, MPFR_RNDN);
854a238c70SJohn Marino
864a238c70SJohn Marino err = MAX (err + se, 5 * i + 8 + MPFR_GET_EXP (w))
874a238c70SJohn Marino - MPFR_GET_EXP (s);
884a238c70SJohn Marino err = 2 + MAX (-1, err);
894a238c70SJohn Marino se = MPFR_GET_EXP (s);
904a238c70SJohn Marino if (MPFR_GET_EXP (w) <= se - (mpfr_exp_t) p)
914a238c70SJohn Marino break;
924a238c70SJohn Marino }
934a238c70SJohn Marino
944a238c70SJohn Marino /* the previous value of err is the rounding error,
954a238c70SJohn Marino the truncation error is less than EXP(z) - 6 * i - 5
964a238c70SJohn Marino (see algorithms.tex) */
974a238c70SJohn Marino err = MAX (err, MPFR_GET_EXP (z) - 6 * i - 5) + 1;
984a238c70SJohn Marino if (MPFR_CAN_ROUND (s, (mpfr_exp_t) p - err, sump, rnd_mode))
994a238c70SJohn Marino break;
1004a238c70SJohn Marino
1014a238c70SJohn Marino MPFR_ZIV_NEXT (loop, p);
1024a238c70SJohn Marino mpfr_set_prec (s, p);
1034a238c70SJohn Marino mpfr_set_prec (u, p);
1044a238c70SJohn Marino mpfr_set_prec (v, p);
1054a238c70SJohn Marino mpfr_set_prec (w, p);
1064a238c70SJohn Marino }
1074a238c70SJohn Marino MPFR_ZIV_FREE (loop);
1084a238c70SJohn Marino mpfr_set (sum, s, rnd_mode);
1094a238c70SJohn Marino
1104a238c70SJohn Marino Bm = Bmax;
1114a238c70SJohn Marino while (Bm--)
1124a238c70SJohn Marino mpz_clear (B[Bm]);
1134a238c70SJohn Marino (*__gmp_free_func) (B, Bmax * sizeof (mpz_t));
1144a238c70SJohn Marino mpfr_clears (s, u, v, w, (mpfr_ptr) 0);
1154a238c70SJohn Marino
1164a238c70SJohn Marino /* Let K be the returned value.
1174a238c70SJohn Marino 1. As we compute an alternating series, the truncation error has the same
1184a238c70SJohn Marino sign as the next term w_{K+2} which is positive iff K%4 == 0.
1194a238c70SJohn Marino 2. Assume that error(z) <= (1+t) z', where z' is the actual value, then
1204a238c70SJohn Marino error(s) <= 2 * (K+1) * t (see algorithms.tex).
1214a238c70SJohn Marino */
1224a238c70SJohn Marino return 2 * i;
1234a238c70SJohn Marino }
1244a238c70SJohn Marino
1254a238c70SJohn Marino /* try asymptotic expansion when x is large and positive:
1264a238c70SJohn Marino Li2(x) = -log(x)^2/2 + Pi^2/3 - 1/x + O(1/x^2).
1274a238c70SJohn Marino More precisely for x >= 2 we have for g(x) = -log(x)^2/2 + Pi^2/3:
1284a238c70SJohn Marino -2 <= x * (Li2(x) - g(x)) <= -1
1294a238c70SJohn Marino thus |Li2(x) - g(x)| <= 2/x.
1304a238c70SJohn Marino Assumes x >= 38, which ensures log(x)^2/2 >= 2*Pi^2/3, and g(x) <= -3.3.
1314a238c70SJohn Marino Return 0 if asymptotic expansion failed (unable to round), otherwise
1324a238c70SJohn Marino returns correct ternary value.
1334a238c70SJohn Marino */
1344a238c70SJohn Marino static int
mpfr_li2_asympt_pos(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)1354a238c70SJohn Marino mpfr_li2_asympt_pos (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
1364a238c70SJohn Marino {
1374a238c70SJohn Marino mpfr_t g, h;
1384a238c70SJohn Marino mpfr_prec_t w = MPFR_PREC (y) + 20;
1394a238c70SJohn Marino int inex = 0;
1404a238c70SJohn Marino
1414a238c70SJohn Marino MPFR_ASSERTN (mpfr_cmp_ui (x, 38) >= 0);
1424a238c70SJohn Marino
1434a238c70SJohn Marino mpfr_init2 (g, w);
1444a238c70SJohn Marino mpfr_init2 (h, w);
1454a238c70SJohn Marino mpfr_log (g, x, MPFR_RNDN); /* rel. error <= |(1 + theta) - 1| */
1464a238c70SJohn Marino mpfr_sqr (g, g, MPFR_RNDN); /* rel. error <= |(1 + theta)^3 - 1| <= 2^(2-w) */
1474a238c70SJohn Marino mpfr_div_2ui (g, g, 1, MPFR_RNDN); /* rel. error <= 2^(2-w) */
1484a238c70SJohn Marino mpfr_const_pi (h, MPFR_RNDN); /* error <= 2^(1-w) */
1494a238c70SJohn Marino mpfr_sqr (h, h, MPFR_RNDN); /* rel. error <= 2^(2-w) */
1504a238c70SJohn Marino mpfr_div_ui (h, h, 3, MPFR_RNDN); /* rel. error <= |(1 + theta)^4 - 1|
1514a238c70SJohn Marino <= 5 * 2^(-w) */
1524a238c70SJohn Marino /* since x is chosen such that log(x)^2/2 >= 2 * (Pi^2/3), we should have
1534a238c70SJohn Marino g >= 2*h, thus |g-h| >= |h|, and the relative error on g is at most
1544a238c70SJohn Marino multiplied by 2 in the difference, and that by h is unchanged. */
1554a238c70SJohn Marino MPFR_ASSERTN (MPFR_EXP (g) > MPFR_EXP (h));
1564a238c70SJohn Marino mpfr_sub (g, h, g, MPFR_RNDN); /* err <= ulp(g)/2 + g*2^(3-w) + g*5*2^(-w)
1574a238c70SJohn Marino <= ulp(g) * (1/2 + 8 + 5) < 14 ulp(g).
1584a238c70SJohn Marino
1594a238c70SJohn Marino If in addition 2/x <= 2 ulp(g), i.e.,
1604a238c70SJohn Marino 1/x <= ulp(g), then the total error is
1614a238c70SJohn Marino bounded by 16 ulp(g). */
1624a238c70SJohn Marino if ((MPFR_EXP (x) >= (mpfr_exp_t) w - MPFR_EXP (g)) &&
1634a238c70SJohn Marino MPFR_CAN_ROUND (g, w - 4, MPFR_PREC (y), rnd_mode))
1644a238c70SJohn Marino inex = mpfr_set (y, g, rnd_mode);
1654a238c70SJohn Marino
1664a238c70SJohn Marino mpfr_clear (g);
1674a238c70SJohn Marino mpfr_clear (h);
1684a238c70SJohn Marino
1694a238c70SJohn Marino return inex;
1704a238c70SJohn Marino }
1714a238c70SJohn Marino
1724a238c70SJohn Marino /* try asymptotic expansion when x is large and negative:
1734a238c70SJohn Marino Li2(x) = -log(-x)^2/2 - Pi^2/6 - 1/x + O(1/x^2).
1744a238c70SJohn Marino More precisely for x <= -2 we have for g(x) = -log(-x)^2/2 - Pi^2/6:
1754a238c70SJohn Marino |Li2(x) - g(x)| <= 1/|x|.
1764a238c70SJohn Marino Assumes x <= -7, which ensures |log(-x)^2/2| >= Pi^2/6, and g(x) <= -3.5.
1774a238c70SJohn Marino Return 0 if asymptotic expansion failed (unable to round), otherwise
1784a238c70SJohn Marino returns correct ternary value.
1794a238c70SJohn Marino */
1804a238c70SJohn Marino static int
mpfr_li2_asympt_neg(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)1814a238c70SJohn Marino mpfr_li2_asympt_neg (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
1824a238c70SJohn Marino {
1834a238c70SJohn Marino mpfr_t g, h;
1844a238c70SJohn Marino mpfr_prec_t w = MPFR_PREC (y) + 20;
1854a238c70SJohn Marino int inex = 0;
1864a238c70SJohn Marino
1874a238c70SJohn Marino MPFR_ASSERTN (mpfr_cmp_si (x, -7) <= 0);
1884a238c70SJohn Marino
1894a238c70SJohn Marino mpfr_init2 (g, w);
1904a238c70SJohn Marino mpfr_init2 (h, w);
1914a238c70SJohn Marino mpfr_neg (g, x, MPFR_RNDN);
1924a238c70SJohn Marino mpfr_log (g, g, MPFR_RNDN); /* rel. error <= |(1 + theta) - 1| */
1934a238c70SJohn Marino mpfr_sqr (g, g, MPFR_RNDN); /* rel. error <= |(1 + theta)^3 - 1| <= 2^(2-w) */
1944a238c70SJohn Marino mpfr_div_2ui (g, g, 1, MPFR_RNDN); /* rel. error <= 2^(2-w) */
1954a238c70SJohn Marino mpfr_const_pi (h, MPFR_RNDN); /* error <= 2^(1-w) */
1964a238c70SJohn Marino mpfr_sqr (h, h, MPFR_RNDN); /* rel. error <= 2^(2-w) */
1974a238c70SJohn Marino mpfr_div_ui (h, h, 6, MPFR_RNDN); /* rel. error <= |(1 + theta)^4 - 1|
1984a238c70SJohn Marino <= 5 * 2^(-w) */
1994a238c70SJohn Marino MPFR_ASSERTN (MPFR_EXP (g) >= MPFR_EXP (h));
2004a238c70SJohn Marino mpfr_add (g, g, h, MPFR_RNDN); /* err <= ulp(g)/2 + g*2^(2-w) + g*5*2^(-w)
2014a238c70SJohn Marino <= ulp(g) * (1/2 + 4 + 5) < 10 ulp(g).
2024a238c70SJohn Marino
2034a238c70SJohn Marino If in addition |1/x| <= 4 ulp(g), then the
2044a238c70SJohn Marino total error is bounded by 16 ulp(g). */
2054a238c70SJohn Marino if ((MPFR_EXP (x) >= (mpfr_exp_t) (w - 2) - MPFR_EXP (g)) &&
2064a238c70SJohn Marino MPFR_CAN_ROUND (g, w - 4, MPFR_PREC (y), rnd_mode))
2074a238c70SJohn Marino inex = mpfr_neg (y, g, rnd_mode);
2084a238c70SJohn Marino
2094a238c70SJohn Marino mpfr_clear (g);
2104a238c70SJohn Marino mpfr_clear (h);
2114a238c70SJohn Marino
2124a238c70SJohn Marino return inex;
2134a238c70SJohn Marino }
2144a238c70SJohn Marino
2154a238c70SJohn Marino /* Compute the real part of the dilogarithm defined by
2164a238c70SJohn Marino Li2(x) = -\Int_{t=0}^x log(1-t)/t dt */
2174a238c70SJohn Marino int
mpfr_li2(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)2184a238c70SJohn Marino mpfr_li2 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
2194a238c70SJohn Marino {
2204a238c70SJohn Marino int inexact;
2214a238c70SJohn Marino mpfr_exp_t err;
2224a238c70SJohn Marino mpfr_prec_t yp, m;
2234a238c70SJohn Marino MPFR_ZIV_DECL (loop);
2244a238c70SJohn Marino MPFR_SAVE_EXPO_DECL (expo);
2254a238c70SJohn Marino
2264a238c70SJohn Marino MPFR_LOG_FUNC
2274a238c70SJohn Marino (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
2284a238c70SJohn Marino ("y[%Pu]=%.*Rg inexact=%d",
2294a238c70SJohn Marino mpfr_get_prec (y), mpfr_log_prec, y, inexact));
2304a238c70SJohn Marino
2314a238c70SJohn Marino if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
2324a238c70SJohn Marino {
2334a238c70SJohn Marino if (MPFR_IS_NAN (x))
2344a238c70SJohn Marino {
2354a238c70SJohn Marino MPFR_SET_NAN (y);
2364a238c70SJohn Marino MPFR_RET_NAN;
2374a238c70SJohn Marino }
2384a238c70SJohn Marino else if (MPFR_IS_INF (x))
2394a238c70SJohn Marino {
2404a238c70SJohn Marino MPFR_SET_NEG (y);
2414a238c70SJohn Marino MPFR_SET_INF (y);
2424a238c70SJohn Marino MPFR_RET (0);
2434a238c70SJohn Marino }
2444a238c70SJohn Marino else /* x is zero */
2454a238c70SJohn Marino {
2464a238c70SJohn Marino MPFR_ASSERTD (MPFR_IS_ZERO (x));
2474a238c70SJohn Marino MPFR_SET_SAME_SIGN (y, x);
2484a238c70SJohn Marino MPFR_SET_ZERO (y);
2494a238c70SJohn Marino MPFR_RET (0);
2504a238c70SJohn Marino }
2514a238c70SJohn Marino }
2524a238c70SJohn Marino
2534a238c70SJohn Marino /* Li2(x) = x + x^2/4 + x^3/9 + ..., more precisely for 0 < x <= 1/2
2544a238c70SJohn Marino we have |Li2(x) - x| < x^2/2 <= 2^(2EXP(x)-1) and for -1/2 <= x < 0
2554a238c70SJohn Marino we have |Li2(x) - x| < x^2/4 <= 2^(2EXP(x)-2) */
2564a238c70SJohn Marino if (MPFR_IS_POS (x))
2574a238c70SJohn Marino MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, -MPFR_GET_EXP (x), 1, 1, rnd_mode,
2584a238c70SJohn Marino {});
2594a238c70SJohn Marino else
2604a238c70SJohn Marino MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, -MPFR_GET_EXP (x), 2, 0, rnd_mode,
2614a238c70SJohn Marino {});
2624a238c70SJohn Marino
2634a238c70SJohn Marino MPFR_SAVE_EXPO_MARK (expo);
2644a238c70SJohn Marino yp = MPFR_PREC (y);
2654a238c70SJohn Marino m = yp + MPFR_INT_CEIL_LOG2 (yp) + 13;
2664a238c70SJohn Marino
2674a238c70SJohn Marino if (MPFR_LIKELY ((mpfr_cmp_ui (x, 0) > 0) && (mpfr_cmp_d (x, 0.5) <= 0)))
2684a238c70SJohn Marino /* 0 < x <= 1/2: Li2(x) = S(-log(1-x))-log^2(1-x)/4 */
2694a238c70SJohn Marino {
2704a238c70SJohn Marino mpfr_t s, u;
2714a238c70SJohn Marino mpfr_exp_t expo_l;
2724a238c70SJohn Marino int k;
2734a238c70SJohn Marino
2744a238c70SJohn Marino mpfr_init2 (u, m);
2754a238c70SJohn Marino mpfr_init2 (s, m);
2764a238c70SJohn Marino
2774a238c70SJohn Marino MPFR_ZIV_INIT (loop, m);
2784a238c70SJohn Marino for (;;)
2794a238c70SJohn Marino {
2804a238c70SJohn Marino mpfr_ui_sub (u, 1, x, MPFR_RNDN);
2814a238c70SJohn Marino mpfr_log (u, u, MPFR_RNDU);
2824a238c70SJohn Marino if (MPFR_IS_ZERO(u))
2834a238c70SJohn Marino goto next_m;
2844a238c70SJohn Marino mpfr_neg (u, u, MPFR_RNDN); /* u = -log(1-x) */
2854a238c70SJohn Marino expo_l = MPFR_GET_EXP (u);
2864a238c70SJohn Marino k = li2_series (s, u, MPFR_RNDU);
2874a238c70SJohn Marino err = 1 + MPFR_INT_CEIL_LOG2 (k + 1);
2884a238c70SJohn Marino
2894a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDU);
2904a238c70SJohn Marino mpfr_div_2ui (u, u, 2, MPFR_RNDU); /* u = log^2(1-x) / 4 */
2914a238c70SJohn Marino mpfr_sub (s, s, u, MPFR_RNDN);
2924a238c70SJohn Marino
2934a238c70SJohn Marino /* error(s) <= (0.5 + 2^(d-EXP(s))
2944a238c70SJohn Marino + 2^(3 + MAX(1, - expo_l) - EXP(s))) ulp(s) */
2954a238c70SJohn Marino err = MAX (err, MAX (1, - expo_l) - 1) - MPFR_GET_EXP (s);
2964a238c70SJohn Marino err = 2 + MAX (-1, err);
2974a238c70SJohn Marino if (MPFR_CAN_ROUND (s, (mpfr_exp_t) m - err, yp, rnd_mode))
2984a238c70SJohn Marino break;
2994a238c70SJohn Marino
3004a238c70SJohn Marino next_m:
3014a238c70SJohn Marino MPFR_ZIV_NEXT (loop, m);
3024a238c70SJohn Marino mpfr_set_prec (u, m);
3034a238c70SJohn Marino mpfr_set_prec (s, m);
3044a238c70SJohn Marino }
3054a238c70SJohn Marino MPFR_ZIV_FREE (loop);
3064a238c70SJohn Marino inexact = mpfr_set (y, s, rnd_mode);
3074a238c70SJohn Marino
3084a238c70SJohn Marino mpfr_clear (u);
3094a238c70SJohn Marino mpfr_clear (s);
3104a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
3114a238c70SJohn Marino return mpfr_check_range (y, inexact, rnd_mode);
3124a238c70SJohn Marino }
3134a238c70SJohn Marino else if (!mpfr_cmp_ui (x, 1))
3144a238c70SJohn Marino /* Li2(1)= pi^2 / 6 */
3154a238c70SJohn Marino {
3164a238c70SJohn Marino mpfr_t u;
3174a238c70SJohn Marino mpfr_init2 (u, m);
3184a238c70SJohn Marino
3194a238c70SJohn Marino MPFR_ZIV_INIT (loop, m);
3204a238c70SJohn Marino for (;;)
3214a238c70SJohn Marino {
3224a238c70SJohn Marino mpfr_const_pi (u, MPFR_RNDU);
3234a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDN);
3244a238c70SJohn Marino mpfr_div_ui (u, u, 6, MPFR_RNDN);
3254a238c70SJohn Marino
3264a238c70SJohn Marino err = m - 4; /* error(u) <= 19/2 ulp(u) */
3274a238c70SJohn Marino if (MPFR_CAN_ROUND (u, err, yp, rnd_mode))
3284a238c70SJohn Marino break;
3294a238c70SJohn Marino
3304a238c70SJohn Marino MPFR_ZIV_NEXT (loop, m);
3314a238c70SJohn Marino mpfr_set_prec (u, m);
3324a238c70SJohn Marino }
3334a238c70SJohn Marino MPFR_ZIV_FREE (loop);
3344a238c70SJohn Marino inexact = mpfr_set (y, u, rnd_mode);
3354a238c70SJohn Marino
3364a238c70SJohn Marino mpfr_clear (u);
3374a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
3384a238c70SJohn Marino return mpfr_check_range (y, inexact, rnd_mode);
3394a238c70SJohn Marino }
3404a238c70SJohn Marino else if (mpfr_cmp_ui (x, 2) >= 0)
3414a238c70SJohn Marino /* x >= 2: Li2(x) = -S(-log(1-1/x))-log^2(x)/2+log^2(1-1/x)/4+pi^2/3 */
3424a238c70SJohn Marino {
3434a238c70SJohn Marino int k;
3444a238c70SJohn Marino mpfr_exp_t expo_l;
3454a238c70SJohn Marino mpfr_t s, u, xx;
3464a238c70SJohn Marino
3474a238c70SJohn Marino if (mpfr_cmp_ui (x, 38) >= 0)
3484a238c70SJohn Marino {
3494a238c70SJohn Marino inexact = mpfr_li2_asympt_pos (y, x, rnd_mode);
3504a238c70SJohn Marino if (inexact != 0)
3514a238c70SJohn Marino goto end_of_case_gt2;
3524a238c70SJohn Marino }
3534a238c70SJohn Marino
3544a238c70SJohn Marino mpfr_init2 (u, m);
3554a238c70SJohn Marino mpfr_init2 (s, m);
3564a238c70SJohn Marino mpfr_init2 (xx, m);
3574a238c70SJohn Marino
3584a238c70SJohn Marino MPFR_ZIV_INIT (loop, m);
3594a238c70SJohn Marino for (;;)
3604a238c70SJohn Marino {
3614a238c70SJohn Marino mpfr_ui_div (xx, 1, x, MPFR_RNDN);
3624a238c70SJohn Marino mpfr_neg (xx, xx, MPFR_RNDN);
3634a238c70SJohn Marino mpfr_log1p (u, xx, MPFR_RNDD);
3644a238c70SJohn Marino mpfr_neg (u, u, MPFR_RNDU); /* u = -log(1-1/x) */
3654a238c70SJohn Marino expo_l = MPFR_GET_EXP (u);
3664a238c70SJohn Marino k = li2_series (s, u, MPFR_RNDN);
3674a238c70SJohn Marino mpfr_neg (s, s, MPFR_RNDN);
3684a238c70SJohn Marino err = MPFR_INT_CEIL_LOG2 (k + 1) + 1; /* error(s) <= 2^err ulp(s) */
3694a238c70SJohn Marino
3704a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDN);
3714a238c70SJohn Marino mpfr_div_2ui (u, u, 2, MPFR_RNDN); /* u= log^2(1-1/x)/4 */
3724a238c70SJohn Marino mpfr_add (s, s, u, MPFR_RNDN);
3734a238c70SJohn Marino err =
3744a238c70SJohn Marino MAX (err,
3754a238c70SJohn Marino 3 + MAX (1, -expo_l) + MPFR_GET_EXP (u)) - MPFR_GET_EXP (s);
3764a238c70SJohn Marino err = 2 + MAX (-1, err); /* error(s) <= 2^err ulp(s) */
3774a238c70SJohn Marino err += MPFR_GET_EXP (s);
3784a238c70SJohn Marino
3794a238c70SJohn Marino mpfr_log (u, x, MPFR_RNDU);
3804a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDN);
3814a238c70SJohn Marino mpfr_div_2ui (u, u, 1, MPFR_RNDN); /* u = log^2(x)/2 */
3824a238c70SJohn Marino mpfr_sub (s, s, u, MPFR_RNDN);
3834a238c70SJohn Marino err = MAX (err, 3 + MPFR_GET_EXP (u)) - MPFR_GET_EXP (s);
3844a238c70SJohn Marino err = 2 + MAX (-1, err); /* error(s) <= 2^err ulp(s) */
3854a238c70SJohn Marino err += MPFR_GET_EXP (s);
3864a238c70SJohn Marino
3874a238c70SJohn Marino mpfr_const_pi (u, MPFR_RNDU);
3884a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDN);
3894a238c70SJohn Marino mpfr_div_ui (u, u, 3, MPFR_RNDN); /* u = pi^2/3 */
3904a238c70SJohn Marino mpfr_add (s, s, u, MPFR_RNDN);
3914a238c70SJohn Marino err = MAX (err, 2) - MPFR_GET_EXP (s);
3924a238c70SJohn Marino err = 2 + MAX (-1, err); /* error(s) <= 2^err ulp(s) */
3934a238c70SJohn Marino if (MPFR_CAN_ROUND (s, (mpfr_exp_t) m - err, yp, rnd_mode))
3944a238c70SJohn Marino break;
3954a238c70SJohn Marino
3964a238c70SJohn Marino MPFR_ZIV_NEXT (loop, m);
3974a238c70SJohn Marino mpfr_set_prec (u, m);
3984a238c70SJohn Marino mpfr_set_prec (s, m);
3994a238c70SJohn Marino mpfr_set_prec (xx, m);
4004a238c70SJohn Marino }
4014a238c70SJohn Marino MPFR_ZIV_FREE (loop);
4024a238c70SJohn Marino inexact = mpfr_set (y, s, rnd_mode);
4034a238c70SJohn Marino mpfr_clears (s, u, xx, (mpfr_ptr) 0);
4044a238c70SJohn Marino
4054a238c70SJohn Marino end_of_case_gt2:
4064a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
4074a238c70SJohn Marino return mpfr_check_range (y, inexact, rnd_mode);
4084a238c70SJohn Marino }
4094a238c70SJohn Marino else if (mpfr_cmp_ui (x, 1) > 0)
4104a238c70SJohn Marino /* 2 > x > 1: Li2(x) = S(log(x))+log^2(x)/4-log(x)log(x-1)+pi^2/6 */
4114a238c70SJohn Marino {
4124a238c70SJohn Marino int k;
4134a238c70SJohn Marino mpfr_exp_t e1, e2;
4144a238c70SJohn Marino mpfr_t s, u, v, xx;
4154a238c70SJohn Marino mpfr_init2 (s, m);
4164a238c70SJohn Marino mpfr_init2 (u, m);
4174a238c70SJohn Marino mpfr_init2 (v, m);
4184a238c70SJohn Marino mpfr_init2 (xx, m);
4194a238c70SJohn Marino
4204a238c70SJohn Marino MPFR_ZIV_INIT (loop, m);
4214a238c70SJohn Marino for (;;)
4224a238c70SJohn Marino {
4234a238c70SJohn Marino mpfr_log (v, x, MPFR_RNDU);
4244a238c70SJohn Marino k = li2_series (s, v, MPFR_RNDN);
4254a238c70SJohn Marino e1 = MPFR_GET_EXP (s);
4264a238c70SJohn Marino
4274a238c70SJohn Marino mpfr_sqr (u, v, MPFR_RNDN);
4284a238c70SJohn Marino mpfr_div_2ui (u, u, 2, MPFR_RNDN); /* u = log^2(x)/4 */
4294a238c70SJohn Marino mpfr_add (s, s, u, MPFR_RNDN);
4304a238c70SJohn Marino
4314a238c70SJohn Marino mpfr_sub_ui (xx, x, 1, MPFR_RNDN);
4324a238c70SJohn Marino mpfr_log (u, xx, MPFR_RNDU);
4334a238c70SJohn Marino e2 = MPFR_GET_EXP (u);
4344a238c70SJohn Marino mpfr_mul (u, v, u, MPFR_RNDN); /* u = log(x) * log(x-1) */
4354a238c70SJohn Marino mpfr_sub (s, s, u, MPFR_RNDN);
4364a238c70SJohn Marino
4374a238c70SJohn Marino mpfr_const_pi (u, MPFR_RNDU);
4384a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDN);
4394a238c70SJohn Marino mpfr_div_ui (u, u, 6, MPFR_RNDN); /* u = pi^2/6 */
4404a238c70SJohn Marino mpfr_add (s, s, u, MPFR_RNDN);
4414a238c70SJohn Marino /* error(s) <= (31 + (k+1) * 2^(1-e1) + 2^(1-e2)) ulp(s)
4424a238c70SJohn Marino see algorithms.tex */
4434a238c70SJohn Marino err = MAX (MPFR_INT_CEIL_LOG2 (k + 1) + 1 - e1, 1 - e2);
4444a238c70SJohn Marino err = 2 + MAX (5, err);
4454a238c70SJohn Marino if (MPFR_CAN_ROUND (s, (mpfr_exp_t) m - err, yp, rnd_mode))
4464a238c70SJohn Marino break;
4474a238c70SJohn Marino
4484a238c70SJohn Marino MPFR_ZIV_NEXT (loop, m);
4494a238c70SJohn Marino mpfr_set_prec (s, m);
4504a238c70SJohn Marino mpfr_set_prec (u, m);
4514a238c70SJohn Marino mpfr_set_prec (v, m);
4524a238c70SJohn Marino mpfr_set_prec (xx, m);
4534a238c70SJohn Marino }
4544a238c70SJohn Marino MPFR_ZIV_FREE (loop);
4554a238c70SJohn Marino inexact = mpfr_set (y, s, rnd_mode);
4564a238c70SJohn Marino
4574a238c70SJohn Marino mpfr_clears (s, u, v, xx, (mpfr_ptr) 0);
4584a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
4594a238c70SJohn Marino return mpfr_check_range (y, inexact, rnd_mode);
4604a238c70SJohn Marino }
4614a238c70SJohn Marino else if (mpfr_cmp_ui_2exp (x, 1, -1) > 0) /* 1/2 < x < 1 */
4624a238c70SJohn Marino /* 1 > x > 1/2: Li2(x) = -S(-log(x))+log^2(x)/4-log(x)log(1-x)+pi^2/6 */
4634a238c70SJohn Marino {
4644a238c70SJohn Marino int k;
4654a238c70SJohn Marino mpfr_t s, u, v, xx;
4664a238c70SJohn Marino mpfr_init2 (s, m);
4674a238c70SJohn Marino mpfr_init2 (u, m);
4684a238c70SJohn Marino mpfr_init2 (v, m);
4694a238c70SJohn Marino mpfr_init2 (xx, m);
4704a238c70SJohn Marino
4714a238c70SJohn Marino
4724a238c70SJohn Marino MPFR_ZIV_INIT (loop, m);
4734a238c70SJohn Marino for (;;)
4744a238c70SJohn Marino {
4754a238c70SJohn Marino mpfr_log (u, x, MPFR_RNDD);
4764a238c70SJohn Marino mpfr_neg (u, u, MPFR_RNDN);
4774a238c70SJohn Marino k = li2_series (s, u, MPFR_RNDN);
4784a238c70SJohn Marino mpfr_neg (s, s, MPFR_RNDN);
4794a238c70SJohn Marino err = 1 + MPFR_INT_CEIL_LOG2 (k + 1) - MPFR_GET_EXP (s);
4804a238c70SJohn Marino
4814a238c70SJohn Marino mpfr_ui_sub (xx, 1, x, MPFR_RNDN);
4824a238c70SJohn Marino mpfr_log (v, xx, MPFR_RNDU);
4834a238c70SJohn Marino mpfr_mul (v, v, u, MPFR_RNDN); /* v = - log(x) * log(1-x) */
4844a238c70SJohn Marino mpfr_add (s, s, v, MPFR_RNDN);
4854a238c70SJohn Marino err = MAX (err, 1 - MPFR_GET_EXP (v));
4864a238c70SJohn Marino err = 2 + MAX (3, err) - MPFR_GET_EXP (s);
4874a238c70SJohn Marino
4884a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDN);
4894a238c70SJohn Marino mpfr_div_2ui (u, u, 2, MPFR_RNDN); /* u = log^2(x)/4 */
4904a238c70SJohn Marino mpfr_add (s, s, u, MPFR_RNDN);
4914a238c70SJohn Marino err = MAX (err, 2 + MPFR_GET_EXP (u)) - MPFR_GET_EXP (s);
4924a238c70SJohn Marino err = 2 + MAX (-1, err) + MPFR_GET_EXP (s);
4934a238c70SJohn Marino
4944a238c70SJohn Marino mpfr_const_pi (u, MPFR_RNDU);
4954a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDN);
4964a238c70SJohn Marino mpfr_div_ui (u, u, 6, MPFR_RNDN); /* u = pi^2/6 */
4974a238c70SJohn Marino mpfr_add (s, s, u, MPFR_RNDN);
4984a238c70SJohn Marino err = MAX (err, 3) - MPFR_GET_EXP (s);
4994a238c70SJohn Marino err = 2 + MAX (-1, err);
5004a238c70SJohn Marino
5014a238c70SJohn Marino if (MPFR_CAN_ROUND (s, (mpfr_exp_t) m - err, yp, rnd_mode))
5024a238c70SJohn Marino break;
5034a238c70SJohn Marino
5044a238c70SJohn Marino MPFR_ZIV_NEXT (loop, m);
5054a238c70SJohn Marino mpfr_set_prec (s, m);
5064a238c70SJohn Marino mpfr_set_prec (u, m);
5074a238c70SJohn Marino mpfr_set_prec (v, m);
5084a238c70SJohn Marino mpfr_set_prec (xx, m);
5094a238c70SJohn Marino }
5104a238c70SJohn Marino MPFR_ZIV_FREE (loop);
5114a238c70SJohn Marino inexact = mpfr_set (y, s, rnd_mode);
5124a238c70SJohn Marino
5134a238c70SJohn Marino mpfr_clears (s, u, v, xx, (mpfr_ptr) 0);
5144a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
5154a238c70SJohn Marino return mpfr_check_range (y, inexact, rnd_mode);
5164a238c70SJohn Marino }
5174a238c70SJohn Marino else if (mpfr_cmp_si (x, -1) >= 0)
5184a238c70SJohn Marino /* 0 > x >= -1: Li2(x) = -S(log(1-x))-log^2(1-x)/4 */
5194a238c70SJohn Marino {
5204a238c70SJohn Marino int k;
5214a238c70SJohn Marino mpfr_exp_t expo_l;
5224a238c70SJohn Marino mpfr_t s, u, xx;
5234a238c70SJohn Marino mpfr_init2 (s, m);
5244a238c70SJohn Marino mpfr_init2 (u, m);
5254a238c70SJohn Marino mpfr_init2 (xx, m);
5264a238c70SJohn Marino
5274a238c70SJohn Marino MPFR_ZIV_INIT (loop, m);
5284a238c70SJohn Marino for (;;)
5294a238c70SJohn Marino {
5304a238c70SJohn Marino mpfr_neg (xx, x, MPFR_RNDN);
5314a238c70SJohn Marino mpfr_log1p (u, xx, MPFR_RNDN);
5324a238c70SJohn Marino k = li2_series (s, u, MPFR_RNDN);
5334a238c70SJohn Marino mpfr_neg (s, s, MPFR_RNDN);
5344a238c70SJohn Marino expo_l = MPFR_GET_EXP (u);
5354a238c70SJohn Marino err = 1 + MPFR_INT_CEIL_LOG2 (k + 1) - MPFR_GET_EXP (s);
5364a238c70SJohn Marino
5374a238c70SJohn Marino mpfr_sqr (u, u, MPFR_RNDN);
5384a238c70SJohn Marino mpfr_div_2ui (u, u, 2, MPFR_RNDN); /* u = log^2(1-x)/4 */
5394a238c70SJohn Marino mpfr_sub (s, s, u, MPFR_RNDN);
5404a238c70SJohn Marino err = MAX (err, - expo_l);
5414a238c70SJohn Marino err = 2 + MAX (err, 3);
5424a238c70SJohn Marino if (MPFR_CAN_ROUND (s, (mpfr_exp_t) m - err, yp, rnd_mode))
5434a238c70SJohn Marino break;
5444a238c70SJohn Marino
5454a238c70SJohn Marino MPFR_ZIV_NEXT (loop, m);
5464a238c70SJohn Marino mpfr_set_prec (s, m);
5474a238c70SJohn Marino mpfr_set_prec (u, m);
5484a238c70SJohn Marino mpfr_set_prec (xx, m);
5494a238c70SJohn Marino }
5504a238c70SJohn Marino MPFR_ZIV_FREE (loop);
5514a238c70SJohn Marino inexact = mpfr_set (y, s, rnd_mode);
5524a238c70SJohn Marino
5534a238c70SJohn Marino mpfr_clears (s, u, xx, (mpfr_ptr) 0);
5544a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
5554a238c70SJohn Marino return mpfr_check_range (y, inexact, rnd_mode);
5564a238c70SJohn Marino }
5574a238c70SJohn Marino else
5584a238c70SJohn Marino /* x < -1: Li2(x)
5594a238c70SJohn Marino = S(log(1-1/x))-log^2(-x)/4-log(1-x)log(-x)/2+log^2(1-x)/4-pi^2/6 */
5604a238c70SJohn Marino {
5614a238c70SJohn Marino int k;
5624a238c70SJohn Marino mpfr_t s, u, v, w, xx;
5634a238c70SJohn Marino
5644a238c70SJohn Marino if (mpfr_cmp_si (x, -7) <= 0)
5654a238c70SJohn Marino {
5664a238c70SJohn Marino inexact = mpfr_li2_asympt_neg (y, x, rnd_mode);
5674a238c70SJohn Marino if (inexact != 0)
5684a238c70SJohn Marino goto end_of_case_ltm1;
5694a238c70SJohn Marino }
5704a238c70SJohn Marino
5714a238c70SJohn Marino mpfr_init2 (s, m);
5724a238c70SJohn Marino mpfr_init2 (u, m);
5734a238c70SJohn Marino mpfr_init2 (v, m);
5744a238c70SJohn Marino mpfr_init2 (w, m);
5754a238c70SJohn Marino mpfr_init2 (xx, m);
5764a238c70SJohn Marino
5774a238c70SJohn Marino MPFR_ZIV_INIT (loop, m);
5784a238c70SJohn Marino for (;;)
5794a238c70SJohn Marino {
5804a238c70SJohn Marino mpfr_ui_div (xx, 1, x, MPFR_RNDN);
5814a238c70SJohn Marino mpfr_neg (xx, xx, MPFR_RNDN);
5824a238c70SJohn Marino mpfr_log1p (u, xx, MPFR_RNDN);
5834a238c70SJohn Marino k = li2_series (s, u, MPFR_RNDN);
5844a238c70SJohn Marino
5854a238c70SJohn Marino mpfr_ui_sub (xx, 1, x, MPFR_RNDN);
5864a238c70SJohn Marino mpfr_log (u, xx, MPFR_RNDU);
5874a238c70SJohn Marino mpfr_neg (xx, x, MPFR_RNDN);
5884a238c70SJohn Marino mpfr_log (v, xx, MPFR_RNDU);
5894a238c70SJohn Marino mpfr_mul (w, v, u, MPFR_RNDN);
5904a238c70SJohn Marino mpfr_div_2ui (w, w, 1, MPFR_RNDN); /* w = log(-x) * log(1-x) / 2 */
5914a238c70SJohn Marino mpfr_sub (s, s, w, MPFR_RNDN);
5924a238c70SJohn Marino err = 1 + MAX (3, MPFR_INT_CEIL_LOG2 (k+1) + 1 - MPFR_GET_EXP (s))
5934a238c70SJohn Marino + MPFR_GET_EXP (s);
5944a238c70SJohn Marino
5954a238c70SJohn Marino mpfr_sqr (w, v, MPFR_RNDN);
5964a238c70SJohn Marino mpfr_div_2ui (w, w, 2, MPFR_RNDN); /* w = log^2(-x) / 4 */
5974a238c70SJohn Marino mpfr_sub (s, s, w, MPFR_RNDN);
5984a238c70SJohn Marino err = MAX (err, 3 + MPFR_GET_EXP(w)) - MPFR_GET_EXP (s);
5994a238c70SJohn Marino err = 2 + MAX (-1, err) + MPFR_GET_EXP (s);
6004a238c70SJohn Marino
6014a238c70SJohn Marino mpfr_sqr (w, u, MPFR_RNDN);
6024a238c70SJohn Marino mpfr_div_2ui (w, w, 2, MPFR_RNDN); /* w = log^2(1-x) / 4 */
6034a238c70SJohn Marino mpfr_add (s, s, w, MPFR_RNDN);
6044a238c70SJohn Marino err = MAX (err, 3 + MPFR_GET_EXP (w)) - MPFR_GET_EXP (s);
6054a238c70SJohn Marino err = 2 + MAX (-1, err) + MPFR_GET_EXP (s);
6064a238c70SJohn Marino
6074a238c70SJohn Marino mpfr_const_pi (w, MPFR_RNDU);
6084a238c70SJohn Marino mpfr_sqr (w, w, MPFR_RNDN);
6094a238c70SJohn Marino mpfr_div_ui (w, w, 6, MPFR_RNDN); /* w = pi^2 / 6 */
6104a238c70SJohn Marino mpfr_sub (s, s, w, MPFR_RNDN);
6114a238c70SJohn Marino err = MAX (err, 3) - MPFR_GET_EXP (s);
6124a238c70SJohn Marino err = 2 + MAX (-1, err) + MPFR_GET_EXP (s);
6134a238c70SJohn Marino
6144a238c70SJohn Marino if (MPFR_CAN_ROUND (s, (mpfr_exp_t) m - err, yp, rnd_mode))
6154a238c70SJohn Marino break;
6164a238c70SJohn Marino
6174a238c70SJohn Marino MPFR_ZIV_NEXT (loop, m);
6184a238c70SJohn Marino mpfr_set_prec (s, m);
6194a238c70SJohn Marino mpfr_set_prec (u, m);
6204a238c70SJohn Marino mpfr_set_prec (v, m);
6214a238c70SJohn Marino mpfr_set_prec (w, m);
6224a238c70SJohn Marino mpfr_set_prec (xx, m);
6234a238c70SJohn Marino }
6244a238c70SJohn Marino MPFR_ZIV_FREE (loop);
6254a238c70SJohn Marino inexact = mpfr_set (y, s, rnd_mode);
6264a238c70SJohn Marino mpfr_clears (s, u, v, w, xx, (mpfr_ptr) 0);
6274a238c70SJohn Marino
6284a238c70SJohn Marino end_of_case_ltm1:
6294a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
6304a238c70SJohn Marino return mpfr_check_range (y, inexact, rnd_mode);
6314a238c70SJohn Marino }
6324a238c70SJohn Marino
6334a238c70SJohn Marino MPFR_ASSERTN (0); /* should never reach this point */
6344a238c70SJohn Marino }
635