Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - basemath - bern.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 30072-2ccdc2326c) Lines: 341 359 95.0 %
Date: 2025-03-12 09:19:58 Functions: 35 36 97.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2018  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation; either version 2 of the License, or (at your option) any later
       8             : version. It is distributed in the hope that it will be useful, but WITHOUT
       9             : ANY WARRANTY WHATSOEVER.
      10             : 
      11             : Check the License for details. You should have received a copy of it, along
      12             : with the package; see the file 'COPYING'. If not, write to the Free Software
      13             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14             : 
      15             : #include "pari.h"
      16             : #include "paripriv.h"
      17             : 
      18             : #define DEBUGLEVEL DEBUGLEVEL_bern
      19             : 
      20             : /********************************************************************/
      21             : /**                                                                **/
      22             : /**                     BERNOULLI NUMBERS B_2k                     **/
      23             : /**                                                                **/
      24             : /********************************************************************/
      25             : 
      26             : /* D = divisorsu(n). Return a/b = \sum_{p-1 | 2n: p prime} 1/p
      27             :  * B_2k + a/b in Z [Clausen-von Staudt] */
      28             : static GEN
      29       83227 : fracB2k(GEN D)
      30             : {
      31       83227 :   GEN a = utoipos(5), b = utoipos(6); /* 1/2 + 1/3 */
      32       83301 :   long i, l = lg(D);
      33      629338 :   for (i = 2; i < l; i++) /* skip 1 */
      34             :   {
      35      546131 :     ulong p = 2*D[i] + 1; /* a/b += 1/p */
      36      546131 :     if (uisprime(p)) { a = addii(muliu(a,p), b); b = muliu(b,p); }
      37             :   }
      38       83207 :   return mkfrac(a,b);
      39             : }
      40             : /* precision needed to compute B_k for all k <= N */
      41             : long
      42        1905 : bernbitprec(long N)
      43             : { /* 1.612086 ~ log(8Pi) / 2 */
      44        1905 :   const double log2PI = 1.83787706641;
      45        1905 :   double logN = log((double)N);
      46        1905 :   double t = (N + 4) * logN - N*(1 + log2PI) + 1.612086;
      47        1905 :   return (long)ceil(t / M_LN2) + 10;
      48             : }
      49             : static long
      50          21 : bernprec(long N) { return nbits2prec(bernbitprec(N)); }
      51             : /* \sum_{k > M} k^(-n) <= M^(1-n) / (n-1) < 2^-b */
      52             : static long
      53        1408 : zetamaxpow(long n)
      54             : {
      55        1408 :   long M = (long)ceil(n / (2 * M_PI * M_E));
      56        1408 :   return M | 1; /* make it odd */
      57             : }
      58             : /* v * zeta(k) using r precomputed odd powers */
      59             : static GEN
      60       83207 : bern_zeta(GEN v, long k, GEN pow, long r, long p)
      61             : {
      62       83207 :   GEN z, s = gel(pow, r);
      63             :   long j;
      64    10383740 :   for (j = r - 2; j >= 3; j -= 2) s = addii(s, gel(pow,j));
      65       83095 :   z = s = itor(s, nbits2prec(p));
      66       83202 :   shiftr_inplace(s, -p); /* zeta(k)(1 - 2^(-k)) - 1*/
      67       83202 :   s = addrs(s, 1); shiftr_inplace(s, -k);
      68             :   /* divide by 1 - 2^(-k): s + s/2^k + s/2^(2k) + ... */
      69      367901 :   for (; k < p; k <<= 1) s = addrr(s, shiftr(s, -k));
      70       83211 :   return addrr(v, mulrr(v, addrr(z, s)));
      71             : }
      72             : /* z * j^2 */
      73             : static GEN
      74    50938545 : muliu2(GEN z, ulong j)
      75    50938545 : { return (j | HIGHMASK)? mulii(z, sqru(j)): muliu(z, j*j); }
      76             : /* 1 <= m <= n, set y[1] = B_{2m}, ... y[n-m+1] = B_{2n} in Q */
      77             : static void
      78         309 : bernset(GEN *y, long m, long n)
      79             : {
      80         309 :   long i, j, k, p, prec, r, N = n << 1; /* up to B_N */
      81             :   GEN u, b, v, t;
      82         309 :   p = bernbitprec(N); prec = nbits2prec(p);
      83         309 :   u = sqrr(Pi2n(1, prec)); /* (2Pi)^2 */
      84         309 :   v = divrr(mpfactr(N, prec), powru(u, n)); shiftr_inplace(v,1);
      85         309 :   r = zetamaxpow(N);
      86         309 :   t = cgetg(r+1, t_VEC); b = int2n(p); /* fixed point */
      87        5775 :   for (j = 3; j <= r; j += 2)
      88             :   {
      89        5466 :     GEN z = cgeti(nbits2lg(p));
      90        5466 :     pari_sp av2 = avma;
      91        5466 :     affii(divii(b, powuu(j, N)), z);
      92        5466 :     gel(t,j) = z; set_avma(av2);
      93             :   }
      94         309 :   y += n - m;
      95         309 :   for (i = n, k = N;; i--)
      96       82887 :   { /* set B_n, k = 2i */
      97       83196 :     pari_sp av2 = avma;
      98       83196 :     GEN z = fracB2k(divisorsu(i)), B = bern_zeta(v, k, t, r, p);
      99             :     long j;
     100             :     /* B = v * zeta(k), v = 2*k! / (2Pi)^k */
     101       83209 :     if (!odd(i)) setsigne(B, -1); /* B ~ B_n */
     102       83207 :     B = roundr(addrr(B, fractor(z,LOWDEFAULTPREC))); /* B - z = B_n */
     103       83210 :     *y-- = gclone(gsub(B, z));
     104       83213 :     if (i == m) break;
     105       82904 :     affrr(divrunextu(mulrr(v,u), k-1), v);
     106    10464134 :     for (j = r; j >= 3; j -= 2) affii(muliu2(gel(t,j), j), gel(t,j));
     107       82874 :     set_avma(av2); k -= 2;
     108       82882 :     if (((N - k) & 0x7f) == 0x7e)
     109             :     { /* reduce precision if possible */
     110        1099 :       long p2 = p, prec2 = prec;
     111        1099 :       p = bernbitprec(k); prec = nbits2prec(p); if (prec2 == prec) continue;
     112        1099 :       setprec(v, prec); r = zetamaxpow(k);
     113      158659 :       for (j = 3; j <= r; j += 2) affii(shifti(gel(t,j), p - p2), gel(t,j));
     114        1099 :       set_avma(av2);
     115             :     }
     116             :   }
     117         309 : }
     118             : /* need B[2..2*nb] as t_INT or t_FRAC */
     119             : void
     120     7234498 : constbern(long nb)
     121             : {
     122     7234498 :   const pari_sp av = avma;
     123             :   long i, l;
     124             :   GEN B;
     125             :   pari_timer T;
     126             : 
     127     7234498 :   l = bernzone? lg(bernzone): 0;
     128     7234498 :   if (l > nb) return;
     129             : 
     130         309 :   nb = maxss(nb, l + 127);
     131         309 :   B = cgetg_block(nb+1, t_VEC);
     132         309 :   if (bernzone)
     133        8832 :   { for (i = 1; i < l; i++) gel(B,i) = gel(bernzone,i); }
     134             :   else
     135             :   {
     136         254 :     gel(B,1) = gclone(mkfracss(1,6));
     137         254 :     gel(B,2) = gclone(mkfracss(-1,30));
     138         254 :     gel(B,3) = gclone(mkfracss(1,42));
     139         254 :     gel(B,4) = gclone(mkfracss(-1,30));
     140         254 :     gel(B,5) = gclone(mkfracss(5,66));
     141         254 :     gel(B,6) = gclone(mkfracss(-691,2730));
     142         254 :     gel(B,7) = gclone(mkfracss(7,6));
     143         254 :     gel(B,8) = gclone(mkfracss(-3617,510));
     144         254 :     gel(B,9) = gclone(mkfracss(43867,798));
     145         254 :     gel(B,10)= gclone(mkfracss(-174611,330));
     146         254 :     gel(B,11)= gclone(mkfracss(854513,138));
     147         254 :     gel(B,12)= gclone(mkfracss(-236364091,2730));
     148         254 :     gel(B,13)= gclone(mkfracss(8553103,6)); /* B_26 */
     149         254 :     l = 14;
     150             :   }
     151         309 :   set_avma(av);
     152         309 :   if (DEBUGLEVEL) {
     153           0 :     err_printf("caching Bernoulli numbers 2*%ld to 2*%ld\n", l, nb);
     154           0 :     timer_start(&T);
     155             :   }
     156         309 :   bernset((GEN*)B + l, l, nb);
     157         309 :   if (DEBUGLEVEL) timer_printf(&T, "Bernoulli");
     158         309 :   swap(B, bernzone); guncloneNULL(B);
     159         309 :   set_avma(av);
     160             : #if 0
     161             :   if (nb > 200000)
     162             : #endif
     163             :   {
     164         309 :     const ulong p = 4294967291UL;
     165         309 :     long n = 2 * nb + 2;
     166         309 :     GEN t = const_vecsmall(n+1, 1);
     167         309 :     t[1] = evalvarn(0); t[2] = 0;
     168         309 :     t = Flx_shift(Flx_invLaplace(t, p), -1); /* t = (exp(x)-1)/x */
     169         309 :     t = Flx_Laplace(Flxn_inv(t, n, p), p);
     170       95606 :     for (i = 1; i <= nb; i++)
     171       95297 :       if (Rg_to_Fl(bernfrac(2*i), p) != uel(t,2*i+2))
     172             :       {
     173           0 :         gunclone(bernzone); bernzone = NULL;
     174           0 :         pari_err_BUG(stack_sprintf("B_{2*%ld}", i));
     175             :       }
     176         309 :     set_avma(av);
     177             :   }
     178             : }
     179             : /* Obsolete, kept for backward compatibility */
     180             : void
     181           0 : mpbern(long n, long prec) { (void)prec; constbern(n); }
     182             : 
     183             : /* assume n even > 0, if iz != NULL, assume iz = 1/zeta(n) */
     184             : static GEN
     185          21 : bernreal_using_zeta(long n, long prec)
     186             : {
     187          21 :   GEN pi2 = Pi2n(1, prec+EXTRAPREC64);
     188          21 :   GEN iz = inv_szeta_euler(n, prec);
     189          21 :   GEN z = divrr(mpfactr(n, prec), mulrr(powru(pi2, n), iz));
     190          21 :   shiftr_inplace(z, 1); /* 2 * n! * zeta(n) / (2Pi)^n */
     191          21 :   if ((n & 3) == 0) setsigne(z, -1);
     192          21 :   return z;
     193             : }
     194             : /* assume n even > 0, B = NULL or good approximation to B_n */
     195             : static GEN
     196          14 : bernfrac_i(long n, GEN B)
     197             : {
     198          14 :   GEN z = fracB2k(divisorsu(n >> 1));
     199          14 :   if (!B) B = bernreal_using_zeta(n, bernprec(n));
     200          14 :   B = roundr( gadd(B, fractor(z,LOWDEFAULTPREC)) );
     201          14 :   return gsub(B, z);
     202             : }
     203             : GEN
     204    51167431 : bernfrac(long n)
     205             : {
     206             :   pari_sp av;
     207             :   long k;
     208    51167431 :   if (n <= 1)
     209             :   {
     210    14007558 :     if (n < 0) pari_err_DOMAIN("bernfrac", "index", "<", gen_0, stoi(n));
     211    14007551 :     return n? mkfrac(gen_m1,gen_2): gen_1;
     212             :   }
     213    37159873 :   if (odd(n)) return gen_0;
     214    23155999 :   k = n >> 1;
     215    23155999 :   if (!bernzone) constbern(0);
     216    23155999 :   if (bernzone && k < lg(bernzone)) return gel(bernzone, k);
     217          36 :   av = avma;
     218          36 :   return gerepileupto(av, bernfrac_i(n, NULL));
     219             : }
     220             : GEN
     221         329 : bernvec(long n)
     222             : {
     223             :   long i, l;
     224             :   GEN y;
     225         329 :   if (n < 0) return cgetg(1, t_VEC);
     226         329 :   constbern(n);
     227         329 :   l = n+2; y = cgetg(l, t_VEC); gel(y,1) = gen_1;
     228       56679 :   for (i = 2; i < l; i++) gel(y,i) = gel(bernzone,i-1);
     229         329 :   return y;
     230             : }
     231             : 
     232             : /* x := pol_x(v); B_k(x) = \sum_{i=0}^k binomial(k, i) B_i x^{k-i} */
     233             : static GEN
     234     7002226 : bernpol_i(long k, long v)
     235             : {
     236             :   GEN B, C;
     237             :   long i;
     238     7002226 :   if (v < 0) v = 0;
     239     7002226 :   constbern(k >> 1); /* cache B_2, ..., B_2[k/2] */
     240     7002226 :   C = vecbinomial(k);
     241     7002226 :   B = cgetg(k + 3, t_POL);
     242    49015099 :   for (i = 0; i <= k; ++i) gel(B, k-i+2) = gmul(gel(C,i+1), bernfrac(i));
     243     7002226 :   B[1] = evalsigne(1) | evalvarn(v);
     244     7002226 :   return B;
     245             : }
     246             : GEN
     247        2114 : bernpol(long k, long v)
     248             : {
     249        2114 :   pari_sp av = avma;
     250        2114 :   if (k < 0) pari_err_DOMAIN("bernpol", "index", "<", gen_0, stoi(k));
     251        2107 :   return gerepileupto(av, bernpol_i(k, v));
     252             : }
     253             : GEN
     254     7000098 : bernpol_eval(long k, GEN x)
     255             : {
     256     7000098 :   pari_sp av = avma;
     257             :   GEN B;
     258     7000098 :   if (!x) return bernpol(k, 0);
     259     7000049 :   if (gequalX(x)) return bernpol(k, varn(x));
     260     7000049 :   if (k < 0) pari_err_DOMAIN("bernpol", "index", "<", gen_0, stoi(k));
     261     7000042 :   B = poleval(bernpol_i(k, fetch_var_higher()), x);
     262     7000042 :   delete_var();
     263     7000042 :   return gerepileupto(av, B);
     264             : }
     265             : 
     266             : /* x := pol_x(v); return 1^e + ... + x^e = x^e + (B_{e+1}(x) - B_{e+1})/(e+1) */
     267             : static GEN
     268          49 : faulhaber(long e, long v)
     269             : {
     270             :   GEN B;
     271          49 :   if (e == 0) return pol_x(v);
     272          35 :   B = RgX_integ(bernpol_i(e, v)); /* (B_{e+1}(x) - B_{e+1}) / (e+1) */
     273          35 :   gel(B,e+2) = gaddgs(gel(B,e+2), 1); /* add x^e, in place */
     274          35 :   return B;
     275             : }
     276             : /* sum_v T(v), T a polynomial expression in v */
     277             : GEN
     278          49 : sumformal(GEN T, long v)
     279             : {
     280          49 :   pari_sp av = avma, av2;
     281             :   long i, t, d;
     282             :   GEN R;
     283             : 
     284          49 :   T = simplify_shallow(T);
     285          49 :   t = typ(T);
     286          49 :   if (is_scalar_t(t))
     287          14 :     return gerepileupto(av, monomialcopy(T, 1, v < 0? 0: v));
     288          35 :   if (t != t_POL) pari_err_TYPE("sumformal [not a t_POL]", T);
     289          28 :   if (v < 0) v = varn(T);
     290          28 :   av2 = avma;
     291          28 :   R = gen_0;
     292          28 :   d = poldegree(T,v);
     293          91 :   for (i = d; i >= 0; i--)
     294             :   {
     295          63 :     GEN c = polcoef_i(T, i, v);
     296          63 :     if (gequal0(c)) continue;
     297          42 :     R = gadd(R, gmul(c, faulhaber(i, v)));
     298          42 :     if (gc_needed(av2,3))
     299             :     {
     300           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"sumformal, i = %ld/%ld", i,d);
     301           0 :       R = gerepileupto(av2, R);
     302             :     }
     303             :   }
     304          28 :   return gerepileupto(av, R);
     305             : }
     306             : 
     307             : /* 1/zeta(n) using Euler product. Assume n > 0. */
     308             : GEN
     309        1194 : inv_szeta_euler(long n, long prec)
     310             : {
     311        1194 :   long bit = prec2nbits(prec);
     312             :   GEN z, res;
     313             :   pari_sp av, av2;
     314             :   double A, D, lba;
     315             :   ulong p, lim;
     316             :   forprime_t S;
     317             : 
     318        1194 :   if (n > bit) return real_1(prec);
     319             : 
     320        1187 :   lba = prec2nbits_mul(prec, M_LN2);
     321        1187 :   D = exp((lba - log((double)(n-1))) / (n-1));
     322        1187 :   lim = 1 + (ulong)ceil(D);
     323        1187 :   if (lim < 3) return subir(gen_1,real2n(-n,prec));
     324        1187 :   res = cgetr(prec); av = avma; incrprec(prec);
     325             : 
     326        1187 :   (void)u_forprime_init(&S, 3, lim);
     327        1187 :   av2 = avma; A = n / M_LN2; z = subir(gen_1, real2n(-n, prec));
     328       86205 :   while ((p = u_forprime_next(&S)))
     329             :   {
     330       85018 :     long l = bit - (long)floor(A * log((double)p));
     331             :     GEN h;
     332             : 
     333       85018 :     if (l < BITS_IN_LONG) l = BITS_IN_LONG;
     334       85018 :     l = minss(prec, nbits2prec(l));
     335       85018 :     h = divrr(z, rpowuu(p, (ulong)n, l));
     336       85018 :     z = subrr(z, h);
     337       85018 :     if (gc_needed(av,1))
     338             :     {
     339           0 :       if (DEBUGMEM>1) pari_warn(warnmem,"inv_szeta_euler, p = %lu/%lu", p,lim);
     340           0 :       z = gerepileuptoleaf(av2, z);
     341             :     }
     342             :   }
     343        1187 :   affrr(z, res); set_avma(av); return res;
     344             : }
     345             : 
     346             : /* Return B_n */
     347             : GEN
     348       15414 : bernreal(long n, long prec)
     349             : {
     350             :   pari_sp av;
     351             :   GEN B;
     352             :   long p, k;
     353       15414 :   if (n < 0) pari_err_DOMAIN("bernreal", "index", "<", gen_0, stoi(n));
     354       15407 :   if (n == 0) return real_1(prec);
     355       15407 :   if (n == 1) return real_m2n(-1,prec); /*-1/2*/
     356       15407 :   if (odd(n)) return real_0(prec);
     357             : 
     358       15407 :   k = n >> 1;
     359       15407 :   if (!bernzone) constbern(0);
     360       15407 :   if (k < lg(bernzone)) return fractor(gel(bernzone,k), prec);
     361           7 :   p = bernprec(n); av = avma;
     362           7 :   B = bernreal_using_zeta(n, minss(p, prec));
     363           7 :   if (p < prec) B = fractor(bernfrac_i(n, B), prec);
     364           7 :   return gerepileuptoleaf(av, B);
     365             : }
     366             : 
     367             : GEN
     368          49 : eulerpol(long k, long v)
     369             : {
     370          49 :   pari_sp av = avma;
     371             :   GEN B, E;
     372          49 :   if (k < 0) pari_err_DOMAIN("eulerpol", "index", "<", gen_0, stoi(k));
     373          42 :   k++; B = bernpol_i(k, v);
     374          42 :   E = RgX_Rg_mul(RgX_sub(B, RgX_rescale(B, gen_2)), uutoQ(2,k));
     375          42 :   return gerepileupto(av, E);
     376             : }
     377             : 
     378             : /*******************************************************************/
     379             : /**                      HARMONIC NUMBERS                         **/
     380             : /*******************************************************************/
     381             : /* 1/a + ... + 1/(b-1); a < b <= 2^(BIL-1) */
     382             : static GEN
     383        4683 : hrec(ulong a, ulong b)
     384             : {
     385             :   ulong m;
     386        4683 :   switch(b - a)
     387             :   {
     388        4501 :     case 1: retmkfrac(gen_1, utoipos(a));
     389         140 :     case 2: if (a < 65536) retmkfrac(utoipos(2*a + 1), utoipos(a * a + a));
     390           0 :       retmkfrac(utoipos(2*a + 1), muluu(a, a+1));
     391             :   }
     392          42 :   m = (a + b) >> 1;
     393          42 :   return gadd(hrec(a, m), hrec(m, b));
     394             : }
     395             : /* exact Harmonic number H_n, n < 2^(BIL-1).
     396             :  * Could use H_n = sum_k 2^(-k) H^odd_{n \ 2^k} */
     397             : GEN
     398        4599 : harmonic(ulong n)
     399             : {
     400        4599 :   pari_sp av = avma;
     401        4599 :   return n? gerepileupto(av, hrec(1, n+1)): gen_0;
     402             : }
     403             : 
     404             : /* 1/a^k + ... + 1/(b-1)^k; a < b */
     405             : static GEN
     406          77 : hreck(ulong a, ulong b, ulong k)
     407             : {
     408             :   ulong m;
     409          77 :   switch(b - a)
     410             :   {
     411             :     GEN x, y;
     412          14 :     case 1: retmkfrac(gen_1, powuu(a, k));
     413          28 :     case 2:
     414          28 :       x = powuu(a, k); y = powuu(a + 1, k);
     415          28 :       retmkfrac(addii(x, y), mulii(x, y));
     416             :   }
     417          35 :   m = (a + b) >> 1;
     418          35 :   return gadd(hreck(a, m, k), hreck(m, b, k));
     419             : }
     420             : GEN
     421          56 : harmonic0(ulong n, GEN k)
     422             : {
     423          56 :   pari_sp av = avma;
     424             :   ulong r;
     425          56 :   if (!n) return gen_0;
     426          49 :   if (n & HIGHBIT) pari_err_OVERFLOW("harmonic");
     427          49 :   if (!k) return harmonic(n);
     428          21 :   if (typ(k) != t_INT) pari_err_TYPE("harmonic", k);
     429          14 :   if (signe(k) < 0)
     430             :   {
     431           7 :     GEN H = poleval(faulhaber(-itos(k), 0), utoipos(n));
     432           7 :     return gerepileuptoint(av, H);
     433             :   }
     434           7 :   r = itou(k);
     435           7 :   if (!r) return utoipos(n);
     436           7 :   if (r == 1) return harmonic(n);
     437           7 :   return gerepileupto(av, hreck(1, n+1, r));
     438             : }
     439             : 
     440             : 
     441             : /**************************************************************/
     442             : /*                      Euler numbers                         */
     443             : /**************************************************************/
     444             : 
     445             : /* precision needed to compute E_k for all k <= N */
     446             : static long
     447         798 : eulerbitprec(long N)
     448             : { /* 1.1605 ~ log(32/Pi) / 2 */
     449         798 :   const double logPIS2 = 0.4515827;
     450         798 :   double t = (N + 1) * log((double)N) - N*(1 + logPIS2) + 1.1605;
     451         798 :   return (long)ceil(t / M_LN2) + 10;
     452             : }
     453             : static long
     454          14 : eulerprec(long N) { return nbits2prec(eulerbitprec(N)); }
     455             : 
     456             : /* sum_{k > M, k odd} (-1)^((k-1)/2)k^(-n) < M^(-n) < 2^-b */
     457             : static long
     458         784 : lfun4maxpow(long n)
     459             : {
     460         784 :   long M = (long)ceil(2 * n / (M_E * M_PI));
     461         784 :   return M | 1; /* make it odd */
     462             : }
     463             : 
     464             : /* lfun4(k) using r precomputed odd powers */
     465             : static GEN
     466       49791 : euler_lfun4(GEN v, GEN pow, long r, long p)
     467             : {
     468       49791 :   GEN s = ((r & 3L) == 1)? gel(pow, r): negi(gel(pow, r));
     469             :   long j;
     470    40556894 :   for (j = r - 2; j >= 3; j -= 2)
     471    40507103 :     s = ((j & 3L) == 1)? addii(s, gel(pow,j)): subii(s, gel(pow,j));
     472       49791 :   s = mulri(v, s); shiftr_inplace(s, -p);
     473       49791 :   return addrr(v, s);
     474             : }
     475             : 
     476             : /* 1 <= m <= n, set y[1] = E_{2m}, ... y[n-m+1] = E_{2n} in Z */
     477             : static void
     478          21 : eulerset(GEN *y, long m, long n)
     479             : {
     480          21 :   long i, j, k, p, prec, r, N = n << 1, N1 = N + 1; /* up to E_N */
     481             :   GEN b, u, v, t;
     482          21 :   p = eulerbitprec(N); prec = nbits2prec(p);
     483          21 :   u = sqrr(Pi2n(-1, prec)); /* (Pi/2)^2 */
     484          21 :   v = divrr(mpfactr(N, prec), mulrr(powru(u, n), Pi2n(-2,prec)));
     485          21 :   r = lfun4maxpow(N1);
     486          21 :   t = cgetg(r+1, t_VEC); b = int2n(p); /* fixed point */
     487       11921 :   for (j = 3; j <= r; j += 2)
     488             :   {
     489       11900 :     GEN z = cgeti(nbits2lg(p));
     490       11900 :     pari_sp av2 = avma;
     491       11900 :     affii(divii(b, powuu(j, N+1)), z);
     492       11900 :     gel(t,j) = z; set_avma(av2);
     493             :   }
     494          21 :   y += n - m;
     495          21 :   for (i = n, k = N1;; i--)
     496       49770 :   { /* set E_n, k = 2i + 1 */
     497       49791 :     pari_sp av2 = avma;
     498       49791 :     GEN E = euler_lfun4(v, t, r, p);
     499             :     long j;
     500             :     /* E = v * lfun4(k), v = (4/Pi)*k! / (Pi/2)^k */
     501       49791 :     E = roundr(E); if (odd(i)) setsigne(E, -1); /* E ~ E_n */
     502       49791 :     *y-- = gclone(E);
     503       49791 :     if (i == m) break;
     504       49770 :     affrr(divrunextu(mulrr(v,u), k-2), v);
     505    40606202 :     for (j = r; j >= 3; j -= 2) affii(muliu2(gel(t,j), j), gel(t,j));
     506       49770 :     set_avma(av2); k -= 2;
     507       49770 :     if (((N1 - k) & 0x7f) == 0x7e)
     508             :     { /* reduce precision if possible */
     509         763 :       long p2 = p, prec2 = prec;
     510         763 :       p = eulerbitprec(k); prec = nbits2prec(p); if (prec2 == prec) continue;
     511         763 :       setprec(v, prec); r = lfun4maxpow(k);
     512      622923 :       for (j = 3; j <= r; j += 2) affii(shifti(gel(t,j), p - p2), gel(t,j));
     513         763 :       set_avma(av2);
     514             :     }
     515             :   }
     516          21 : }
     517             : 
     518             : /* need E[2..2*nb] as t_INT */
     519             : static void
     520          28 : constreuler(long nb)
     521             : {
     522          28 :   const pari_sp av = avma;
     523             :   long i, l;
     524             :   GEN E;
     525             :   pari_timer T;
     526             : 
     527          28 :   l = eulerzone? lg(eulerzone): 0;
     528          28 :   if (l > nb) return;
     529             : 
     530          21 :   nb = maxss(nb, l + 127);
     531          21 :   E = cgetg_block(nb+1, t_VEC);
     532          21 :   if (eulerzone)
     533         896 :   { for (i = 1; i < l; i++) gel(E,i) = gel(eulerzone,i); }
     534             :   else
     535             :   {
     536          14 :     gel(E,1) = gclone(stoi(-1));
     537          14 :     gel(E,2) = gclone(stoi(5));
     538          14 :     gel(E,3) = gclone(stoi(-61));
     539          14 :     gel(E,4) = gclone(stoi(1385));
     540          14 :     gel(E,5) = gclone(stoi(-50521));
     541          14 :     gel(E,6) = gclone(stoi(2702765));
     542          14 :     gel(E,7) = gclone(stoi(-199360981));
     543          14 :     l = 8;
     544             :   }
     545          21 :   set_avma(av);
     546          21 :   if (DEBUGLEVEL) {
     547           0 :     err_printf("caching Euler numbers 2*%ld to 2*%ld\n", l, nb);
     548           0 :     timer_start(&T);
     549             :   }
     550          21 :   eulerset((GEN*)E + l, l, nb);
     551          21 :   if (DEBUGLEVEL) timer_printf(&T, "Euler");
     552          21 :   swap(E, eulerzone); guncloneNULL(E);
     553          21 :   set_avma(av);
     554             : }
     555             : 
     556             : /* 1/lfun(-4,n) using Euler product. Assume n > 0. */
     557             : static GEN
     558          14 : inv_lfun4(long n, long prec)
     559             : {
     560          14 :   long bit = prec2nbits(prec);
     561             :   GEN z, res;
     562             :   pari_sp av, av2;
     563             :   double A;
     564             :   ulong p, lim;
     565             :   forprime_t S;
     566             : 
     567          14 :   if (n > bit) return real_1(prec);
     568             : 
     569          14 :   lim = 1 + (ulong)ceil(exp2((double)bit / n));
     570          14 :   res = cgetr(prec); av = avma; incrprec(prec);
     571             : 
     572          14 :   (void)u_forprime_init(&S, 3, lim);
     573          14 :   av2 = avma; A = n / M_LN2; z = real_1(prec);
     574         369 :   while ((p = u_forprime_next(&S)))
     575             :   {
     576         355 :     long l = bit - (long)floor(A * log((double)p));
     577             :     GEN h;
     578             : 
     579         355 :     if (l < BITS_IN_LONG) l = BITS_IN_LONG;
     580         355 :     l = minss(prec, nbits2prec(l));
     581         355 :     h = rpowuu(p, (ulong)n, l); if ((p & 3UL) == 1) setsigne(h, -1);
     582         355 :     z = addrr(z, divrr(z, h)); /* z *= 1 - chi_{-4}(p) / p^n */
     583         355 :     if (gc_needed(av,1))
     584             :     {
     585           0 :       if (DEBUGMEM>1) pari_warn(warnmem,"inv_lfun4, p = %lu/%lu", p,lim);
     586           0 :       z = gerepileuptoleaf(av2, z);
     587             :     }
     588             :   }
     589          14 :   affrr(z, res); set_avma(av); return res;
     590             : }
     591             : /* assume n even > 0, E_n = (-1)^(n/2) (4/Pi) n! lfun4(n+1) / (Pi/2)^n */
     592             : static GEN
     593          14 : eulerreal_using_lfun4(long n, long prec)
     594             : {
     595          14 :   GEN pisur2 = Pi2n(-1, prec+EXTRAPREC64);
     596          14 :   GEN iz = inv_lfun4(n+1, prec);
     597          14 :   GEN z = divrr(mpfactr(n, prec), mulrr(powru(pisur2, n+1), iz));
     598          14 :   if ((n & 3L) == 2) setsigne(z, -1);
     599          14 :   shiftr_inplace(z, 1); return z;
     600             : }
     601             : /* Euler numbers: 1, 0, -1, 0, 5, 0, -61,... */
     602             : GEN
     603         217 : eulerfrac(long n)
     604             : {
     605             :   pari_sp av;
     606             :   long k;
     607             :   GEN E;
     608         217 :   if (n <= 0)
     609             :   {
     610          21 :     if (n < 0) pari_err_DOMAIN("eulerfrac", "index", "<", gen_0, stoi(n));
     611          14 :     return gen_1;
     612             :   }
     613         196 :   if (odd(n)) return gen_0;
     614         189 :   k = n >> 1;
     615         189 :   if (!eulerzone) constreuler(0);
     616         189 :   if (eulerzone && k < lg(eulerzone)) return gel(eulerzone, k);
     617          14 :   av = avma; E = eulerreal_using_lfun4(n, eulerprec(n));
     618          14 :   return gerepileuptoleaf(av, roundr(E));
     619             : }
     620             : GEN
     621          14 : eulervec(long n)
     622             : {
     623             :   long i, l;
     624             :   GEN y;
     625          14 :   if (n < 0) return cgetg(1, t_VEC);
     626          14 :   constreuler(n);
     627          14 :   l = n+2; y = cgetg(l, t_VEC); gel(y,1) = gen_1;
     628       49224 :   for (i = 2; i < l; i++) gel(y,i) = gel(eulerzone,i-1);
     629          14 :   return y;
     630             : }
     631             : 
     632             : /* Return E_n */
     633             : GEN
     634          21 : eulerreal(long n, long prec)
     635             : {
     636          21 :   pari_sp av = avma;
     637             :   GEN B;
     638             :   long p, k;
     639          21 :   if (n < 0) pari_err_DOMAIN("eulerreal", "index", "<", gen_0, stoi(n));
     640          14 :   if (n == 0) return real_1(prec);
     641          14 :   if (odd(n)) return real_0(prec);
     642             : 
     643          14 :   k = n >> 1;
     644          14 :   if (!eulerzone) constreuler(0);
     645          14 :   if (k < lg(eulerzone)) return itor(gel(eulerzone,k), prec);
     646           0 :   p = eulerprec(n);
     647           0 :   B = eulerreal_using_lfun4(n, minss(p, prec));
     648           0 :   if (p < prec) B = itor(roundr(B), prec);
     649           0 :   return gerepileuptoleaf(av, B);
     650             : }

Generated by: LCOV version 1.16