xref: /dflybsd-src/contrib/mpfr/src/zeta_ui.c (revision 2786097444a0124b5d33763854de247e230c6629)
14a238c70SJohn Marino /* mpfr_zeta_ui -- compute the Riemann Zeta function for integer argument.
24a238c70SJohn Marino 
3*ab6d115fSJohn Marino Copyright 2005, 2006, 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 int
mpfr_zeta_ui(mpfr_ptr z,unsigned long m,mpfr_rnd_t r)274a238c70SJohn Marino mpfr_zeta_ui (mpfr_ptr z, unsigned long m, mpfr_rnd_t r)
284a238c70SJohn Marino {
294a238c70SJohn Marino   MPFR_ZIV_DECL (loop);
304a238c70SJohn Marino 
314a238c70SJohn Marino   if (m == 0)
324a238c70SJohn Marino     {
334a238c70SJohn Marino       mpfr_set_ui (z, 1, r);
344a238c70SJohn Marino       mpfr_div_2ui (z, z, 1, r);
354a238c70SJohn Marino       MPFR_CHANGE_SIGN (z);
364a238c70SJohn Marino       MPFR_RET (0);
374a238c70SJohn Marino     }
384a238c70SJohn Marino   else if (m == 1)
394a238c70SJohn Marino     {
404a238c70SJohn Marino       MPFR_SET_INF (z);
414a238c70SJohn Marino       MPFR_SET_POS (z);
424a238c70SJohn Marino       mpfr_set_divby0 ();
434a238c70SJohn Marino       return 0;
444a238c70SJohn Marino     }
454a238c70SJohn Marino   else /* m >= 2 */
464a238c70SJohn Marino     {
474a238c70SJohn Marino       mpfr_prec_t p = MPFR_PREC(z);
484a238c70SJohn Marino       unsigned long n, k, err, kbits;
494a238c70SJohn Marino       mpz_t d, t, s, q;
504a238c70SJohn Marino       mpfr_t y;
514a238c70SJohn Marino       int inex;
524a238c70SJohn Marino 
534a238c70SJohn Marino       if (r == MPFR_RNDA)
544a238c70SJohn Marino         r = MPFR_RNDU; /* since the result is always positive */
554a238c70SJohn Marino 
564a238c70SJohn Marino       if (m >= p) /* 2^(-m) < ulp(1) = 2^(1-p). This means that
574a238c70SJohn Marino                      2^(-m) <= 1/2*ulp(1). We have 3^(-m)+4^(-m)+... < 2^(-m)
584a238c70SJohn Marino                      i.e. zeta(m) < 1+2*2^(-m) for m >= 3 */
594a238c70SJohn Marino 
604a238c70SJohn Marino         {
614a238c70SJohn Marino           if (m == 2) /* necessarily p=2 */
624a238c70SJohn Marino             return mpfr_set_ui_2exp (z, 13, -3, r);
634a238c70SJohn Marino           else if (r == MPFR_RNDZ || r == MPFR_RNDD || (r == MPFR_RNDN && m > p))
644a238c70SJohn Marino             {
654a238c70SJohn Marino               mpfr_set_ui (z, 1, r);
664a238c70SJohn Marino               return -1;
674a238c70SJohn Marino             }
684a238c70SJohn Marino           else
694a238c70SJohn Marino             {
704a238c70SJohn Marino               mpfr_set_ui (z, 1, r);
714a238c70SJohn Marino               mpfr_nextabove (z);
724a238c70SJohn Marino               return 1;
734a238c70SJohn Marino             }
744a238c70SJohn Marino         }
754a238c70SJohn Marino 
764a238c70SJohn Marino       /* now treat also the case where zeta(m) - (1+1/2^m) < 1/2*ulp(1),
774a238c70SJohn Marino          and the result is either 1+2^(-m) or 1+2^(-m)+2^(1-p). */
784a238c70SJohn Marino       mpfr_init2 (y, 31);
794a238c70SJohn Marino 
804a238c70SJohn Marino       if (m >= p / 2) /* otherwise 4^(-m) > 2^(-p) */
814a238c70SJohn Marino         {
824a238c70SJohn Marino           /* the following is a lower bound for log(3)/log(2) */
834a238c70SJohn Marino           mpfr_set_str_binary (y, "1.100101011100000000011010001110");
844a238c70SJohn Marino           mpfr_mul_ui (y, y, m, MPFR_RNDZ); /* lower bound for log2(3^m) */
854a238c70SJohn Marino           if (mpfr_cmp_ui (y, p + 2) >= 0)
864a238c70SJohn Marino             {
874a238c70SJohn Marino               mpfr_clear (y);
884a238c70SJohn Marino               mpfr_set_ui (z, 1, MPFR_RNDZ);
894a238c70SJohn Marino               mpfr_div_2ui (z, z, m, MPFR_RNDZ);
904a238c70SJohn Marino               mpfr_add_ui (z, z, 1, MPFR_RNDZ);
914a238c70SJohn Marino               if (r != MPFR_RNDU)
924a238c70SJohn Marino                 return -1;
934a238c70SJohn Marino               mpfr_nextabove (z);
944a238c70SJohn Marino               return 1;
954a238c70SJohn Marino             }
964a238c70SJohn Marino         }
974a238c70SJohn Marino 
984a238c70SJohn Marino       mpz_init (s);
994a238c70SJohn Marino       mpz_init (d);
1004a238c70SJohn Marino       mpz_init (t);
1014a238c70SJohn Marino       mpz_init (q);
1024a238c70SJohn Marino 
1034a238c70SJohn Marino       p += MPFR_INT_CEIL_LOG2(p); /* account of the n term in the error */
1044a238c70SJohn Marino 
1054a238c70SJohn Marino       p += MPFR_INT_CEIL_LOG2(p) + 15; /* initial value */
1064a238c70SJohn Marino 
1074a238c70SJohn Marino       MPFR_ZIV_INIT (loop, p);
1084a238c70SJohn Marino       for(;;)
1094a238c70SJohn Marino         {
1104a238c70SJohn Marino           /* 0.39321985067869744 = log(2)/log(3+sqrt(8)) */
1114a238c70SJohn Marino           n = 1 + (unsigned long) (0.39321985067869744 * (double) p);
1124a238c70SJohn Marino           err = n + 4;
1134a238c70SJohn Marino 
1144a238c70SJohn Marino           mpfr_set_prec (y, p);
1154a238c70SJohn Marino 
1164a238c70SJohn Marino           /* computation of the d[k] */
1174a238c70SJohn Marino           mpz_set_ui (s, 0);
1184a238c70SJohn Marino           mpz_set_ui (t, 1);
1194a238c70SJohn Marino           mpz_mul_2exp (t, t, 2 * n - 1); /* t[n] */
1204a238c70SJohn Marino           mpz_set (d, t);
1214a238c70SJohn Marino           for (k = n; k > 0; k--)
1224a238c70SJohn Marino             {
1234a238c70SJohn Marino               count_leading_zeros (kbits, k);
1244a238c70SJohn Marino               kbits = GMP_NUMB_BITS - kbits;
1254a238c70SJohn Marino               /* if k^m is too large, use mpz_tdiv_q */
1264a238c70SJohn Marino               if (m * kbits > 2 * GMP_NUMB_BITS)
1274a238c70SJohn Marino                 {
1284a238c70SJohn Marino                   /* if we know in advance that k^m > d, then floor(d/k^m) will
1294a238c70SJohn Marino                      be zero below, so there is no need to compute k^m */
1304a238c70SJohn Marino                   kbits = (kbits - 1) * m + 1;
1314a238c70SJohn Marino                   /* k^m has at least kbits bits */
1324a238c70SJohn Marino                   if (kbits > mpz_sizeinbase (d, 2))
1334a238c70SJohn Marino                     mpz_set_ui (q, 0);
1344a238c70SJohn Marino                   else
1354a238c70SJohn Marino                     {
1364a238c70SJohn Marino                       mpz_ui_pow_ui (q, k, m);
1374a238c70SJohn Marino                       mpz_tdiv_q (q, d, q);
1384a238c70SJohn Marino                     }
1394a238c70SJohn Marino                 }
1404a238c70SJohn Marino               else /* use several mpz_tdiv_q_ui calls */
1414a238c70SJohn Marino                 {
1424a238c70SJohn Marino                   unsigned long km = k, mm = m - 1;
1434a238c70SJohn Marino                   while (mm > 0 && km < ULONG_MAX / k)
1444a238c70SJohn Marino                     {
1454a238c70SJohn Marino                       km *= k;
1464a238c70SJohn Marino                       mm --;
1474a238c70SJohn Marino                     }
1484a238c70SJohn Marino                   mpz_tdiv_q_ui (q, d, km);
1494a238c70SJohn Marino                   while (mm > 0)
1504a238c70SJohn Marino                     {
1514a238c70SJohn Marino                       km = k;
1524a238c70SJohn Marino                       mm --;
1534a238c70SJohn Marino                       while (mm > 0 && km < ULONG_MAX / k)
1544a238c70SJohn Marino                         {
1554a238c70SJohn Marino                           km *= k;
1564a238c70SJohn Marino                           mm --;
1574a238c70SJohn Marino                         }
1584a238c70SJohn Marino                       mpz_tdiv_q_ui (q, q, km);
1594a238c70SJohn Marino                     }
1604a238c70SJohn Marino                 }
1614a238c70SJohn Marino               if (k % 2)
1624a238c70SJohn Marino                 mpz_add (s, s, q);
1634a238c70SJohn Marino               else
1644a238c70SJohn Marino                 mpz_sub (s, s, q);
1654a238c70SJohn Marino 
1664a238c70SJohn Marino               /* we have d[k] = sum(t[i], i=k+1..n)
1674a238c70SJohn Marino                  with t[i] = n*(n+i-1)!*4^i/(n-i)!/(2i)!
1684a238c70SJohn Marino                  t[k-1]/t[k] = k*(2k-1)/(n-k+1)/(n+k-1)/2 */
1694a238c70SJohn Marino #if (GMP_NUMB_BITS == 32)
1704a238c70SJohn Marino #define KMAX 46341 /* max k such that k*(2k-1) < 2^32 */
1714a238c70SJohn Marino #elif (GMP_NUMB_BITS == 64)
1724a238c70SJohn Marino #define KMAX 3037000500
1734a238c70SJohn Marino #endif
1744a238c70SJohn Marino #ifdef KMAX
1754a238c70SJohn Marino               if (k <= KMAX)
1764a238c70SJohn Marino                 mpz_mul_ui (t, t, k * (2 * k - 1));
1774a238c70SJohn Marino               else
1784a238c70SJohn Marino #endif
1794a238c70SJohn Marino                 {
1804a238c70SJohn Marino                   mpz_mul_ui (t, t, k);
1814a238c70SJohn Marino                   mpz_mul_ui (t, t, 2 * k - 1);
1824a238c70SJohn Marino                 }
1834a238c70SJohn Marino               mpz_fdiv_q_2exp (t, t, 1);
1844a238c70SJohn Marino               /* Warning: the test below assumes that an unsigned long
1854a238c70SJohn Marino                  has no padding bits. */
1864a238c70SJohn Marino               if (n < 1UL << ((sizeof(unsigned long) * CHAR_BIT) / 2))
1874a238c70SJohn Marino                 /* (n - k + 1) * (n + k - 1) < n^2 */
1884a238c70SJohn Marino                 mpz_divexact_ui (t, t, (n - k + 1) * (n + k - 1));
1894a238c70SJohn Marino               else
1904a238c70SJohn Marino                 {
1914a238c70SJohn Marino                   mpz_divexact_ui (t, t, n - k + 1);
1924a238c70SJohn Marino                   mpz_divexact_ui (t, t, n + k - 1);
1934a238c70SJohn Marino                 }
1944a238c70SJohn Marino               mpz_add (d, d, t);
1954a238c70SJohn Marino             }
1964a238c70SJohn Marino 
1974a238c70SJohn Marino           /* multiply by 1/(1-2^(1-m)) = 1 + 2^(1-m) + 2^(2-m) + ... */
1984a238c70SJohn Marino           mpz_fdiv_q_2exp (t, s, m - 1);
1994a238c70SJohn Marino           do
2004a238c70SJohn Marino             {
2014a238c70SJohn Marino               err ++;
2024a238c70SJohn Marino               mpz_add (s, s, t);
2034a238c70SJohn Marino               mpz_fdiv_q_2exp (t, t, m - 1);
2044a238c70SJohn Marino             }
2054a238c70SJohn Marino           while (mpz_cmp_ui (t, 0) > 0);
2064a238c70SJohn Marino 
2074a238c70SJohn Marino           /* divide by d[n] */
2084a238c70SJohn Marino           mpz_mul_2exp (s, s, p);
2094a238c70SJohn Marino           mpz_tdiv_q (s, s, d);
2104a238c70SJohn Marino           mpfr_set_z (y, s, MPFR_RNDN);
2114a238c70SJohn Marino           mpfr_div_2ui (y, y, p, MPFR_RNDN);
2124a238c70SJohn Marino 
2134a238c70SJohn Marino           err = MPFR_INT_CEIL_LOG2 (err);
2144a238c70SJohn Marino 
2154a238c70SJohn Marino           if (MPFR_LIKELY(MPFR_CAN_ROUND (y, p - err, MPFR_PREC(z), r)))
2164a238c70SJohn Marino             break;
2174a238c70SJohn Marino 
2184a238c70SJohn Marino           MPFR_ZIV_NEXT (loop, p);
2194a238c70SJohn Marino         }
2204a238c70SJohn Marino       MPFR_ZIV_FREE (loop);
2214a238c70SJohn Marino 
2224a238c70SJohn Marino       mpz_clear (d);
2234a238c70SJohn Marino       mpz_clear (t);
2244a238c70SJohn Marino       mpz_clear (q);
2254a238c70SJohn Marino       mpz_clear (s);
2264a238c70SJohn Marino       inex = mpfr_set (z, y, r);
2274a238c70SJohn Marino       mpfr_clear (y);
2284a238c70SJohn Marino       return inex;
2294a238c70SJohn Marino     }
2304a238c70SJohn Marino }
231