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 - arith1.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 30288-703288f808) Lines: 2080 2301 90.4 %
Date: 2025-05-19 09:23:07 Functions: 218 233 93.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000  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             : /*********************************************************************/
      16             : /**                     ARITHMETIC FUNCTIONS                        **/
      17             : /**                         (first part)                            **/
      18             : /*********************************************************************/
      19             : #include "pari.h"
      20             : #include "paripriv.h"
      21             : 
      22             : #define DEBUGLEVEL DEBUGLEVEL_arith
      23             : 
      24             : /******************************************************************/
      25             : /*                 GENERATOR of (Z/mZ)*                           */
      26             : /******************************************************************/
      27             : static GEN
      28        1812 : remove2(GEN q) { long v = vali(q); return v? shifti(q, -v): q; }
      29             : static ulong
      30      464114 : u_remove2(ulong q) { return q >> vals(q); }
      31             : GEN
      32        1812 : odd_prime_divisors(GEN q) { return gel(Z_factor(remove2(q)), 1); }
      33             : static GEN
      34      464114 : u_odd_prime_divisors(ulong q) { return gel(factoru(u_remove2(q)), 1); }
      35             : /* p odd prime, q=(p-1)/2; L0 list of (some) divisors of q = (p-1)/2 or NULL
      36             :  * (all prime divisors of q); return the q/l, l in L0 */
      37             : static GEN
      38        4909 : is_gener_expo(GEN p, GEN L0)
      39             : {
      40        4909 :   GEN L, q = shifti(p,-1);
      41             :   long i, l;
      42        4909 :   if (L0) {
      43        3134 :     l = lg(L0);
      44        3134 :     L = cgetg(l, t_VEC);
      45             :   } else {
      46        1775 :     L0 = L = odd_prime_divisors(q);
      47        1775 :     l = lg(L);
      48             :   }
      49       14199 :   for (i=1; i<l; i++) gel(L,i) = diviiexact(q, gel(L0,i));
      50        4909 :   return L;
      51             : }
      52             : static GEN
      53      531394 : u_is_gener_expo(ulong p, GEN L0)
      54             : {
      55      531394 :   const ulong q = p >> 1;
      56             :   long i;
      57             :   GEN L;
      58      531394 :   if (!L0) L0 = u_odd_prime_divisors(q);
      59      531387 :   L = cgetg_copy(L0,&i);
      60     1150275 :   while (--i) L[i] = q / uel(L0,i);
      61      531386 :   return L;
      62             : }
      63             : 
      64             : int
      65     1628688 : is_gener_Fl(ulong x, ulong p, ulong p_1, GEN L)
      66             : {
      67             :   long i;
      68     1628688 :   if (krouu(x, p) >= 0) return 0;
      69     1375381 :   for (i=lg(L)-1; i; i--)
      70             :   {
      71      839231 :     ulong t = Fl_powu(x, uel(L,i), p);
      72      839225 :     if (t == p_1 || t == 1) return 0;
      73             :   }
      74      536150 :   return 1;
      75             : }
      76             : /* assume p prime */
      77             : ulong
      78     1051380 : pgener_Fl_local(ulong p, GEN L0)
      79             : {
      80     1051380 :   const pari_sp av = avma;
      81     1051380 :   const ulong p_1 = p-1;
      82             :   long x;
      83             :   GEN L;
      84     1051380 :   if (p <= 19) switch(p)
      85             :   { /* quick trivial cases */
      86          63 :     case 2:  return 1;
      87      116200 :     case 7:
      88      116200 :     case 17: return 3;
      89      403765 :     default: return 2;
      90             :   }
      91      531352 :   L = u_is_gener_expo(p,L0);
      92     1620965 :   for (x = 2;; x++)
      93     1620965 :     if (is_gener_Fl(x,p,p_1,L)) return gc_ulong(av, x);
      94             : }
      95             : ulong
      96      575237 : pgener_Fl(ulong p) { return pgener_Fl_local(p, NULL); }
      97             : 
      98             : /* L[i] = set of (p-1)/2l, l ODD prime divisor of p-1 (l=2 can be included,
      99             :  * but wasteful) */
     100             : int
     101       13951 : is_gener_Fp(GEN x, GEN p, GEN p_1, GEN L)
     102             : {
     103       13951 :   long i, t = lgefint(x)==3? kroui(x[2], p): kronecker(x, p);
     104       13951 :   if (t >= 0) return 0;
     105       21948 :   for (i = lg(L)-1; i; i--)
     106             :   {
     107       14446 :     GEN t = Fp_pow(x, gel(L,i), p);
     108       14446 :     if (equalii(t, p_1) || equali1(t)) return 0;
     109             :   }
     110        7502 :   return 1;
     111             : }
     112             : 
     113             : /* assume p prime, return a generator of all L[i]-Sylows in F_p^*. */
     114             : GEN
     115      358524 : pgener_Fp_local(GEN p, GEN L0)
     116             : {
     117      358524 :   pari_sp av0 = avma;
     118             :   GEN x, p_1, L;
     119      358524 :   if (lgefint(p) == 3)
     120             :   {
     121             :     ulong z;
     122      353620 :     if (p[2] == 2) return gen_1;
     123      258435 :     if (L0) L0 = ZV_to_nv(L0);
     124      258432 :     z = pgener_Fl_local(uel(p,2), L0);
     125      258449 :     return gc_utoipos(av0, z);
     126             :   }
     127        4904 :   p_1 = subiu(p,1); L = is_gener_expo(p, L0);
     128        4904 :   x = utoipos(2);
     129        9927 :   for (;; x[2]++) { if (is_gener_Fp(x, p, p_1, L)) break; }
     130        4904 :   return gc_utoipos(av0, uel(x,2));
     131             : }
     132             : 
     133             : GEN
     134       44247 : pgener_Fp(GEN p) { return pgener_Fp_local(p, NULL); }
     135             : 
     136             : ulong
     137      205731 : pgener_Zl(ulong p)
     138             : {
     139      205731 :   if (p == 2) pari_err_DOMAIN("pgener_Zl","p","=",gen_2,gen_2);
     140             :   /* only p < 2^32 such that znprimroot(p) != znprimroot(p^2) */
     141      205731 :   if (p == 40487) return 10;
     142             : #ifndef LONG_IS_64BIT
     143       29811 :   return pgener_Fl(p);
     144             : #else
     145      175920 :   if (p < (1UL<<32)) return pgener_Fl(p);
     146             :   else
     147             :   {
     148          30 :     const pari_sp av = avma;
     149          30 :     const ulong p_1 = p-1;
     150             :     long x ;
     151          30 :     GEN p2 = sqru(p), L = u_is_gener_expo(p, NULL);
     152         102 :     for (x=2;;x++)
     153         102 :       if (is_gener_Fl(x,p,p_1,L) && !is_pm1(Fp_powu(utoipos(x),p_1,p2)))
     154          30 :         return gc_ulong(av, x);
     155             :   }
     156             : #endif
     157             : }
     158             : 
     159             : /* p prime. Return a primitive root modulo p^e, e > 1 */
     160             : GEN
     161      170975 : pgener_Zp(GEN p)
     162             : {
     163      170975 :   if (lgefint(p) == 3) return utoipos(pgener_Zl(p[2]));
     164             :   else
     165             :   {
     166           5 :     const pari_sp av = avma;
     167           5 :     GEN p_1 = subiu(p,1), p2 = sqri(p), L = is_gener_expo(p,NULL);
     168           5 :     GEN x = utoipos(2);
     169          12 :     for (;; x[2]++)
     170          17 :       if (is_gener_Fp(x,p,p_1,L) && !equali1(Fp_pow(x,p_1,p2))) break;
     171           5 :     return gc_utoipos(av, uel(x,2));
     172             :   }
     173             : }
     174             : 
     175             : static GEN
     176         259 : gener_Zp(GEN q, GEN F)
     177             : {
     178         259 :   GEN p = NULL;
     179         259 :   long e = 0;
     180         259 :   if (F)
     181             :   {
     182          14 :     GEN P = gel(F,1), E = gel(F,2);
     183          14 :     long i, l = lg(P);
     184          42 :     for (i = 1; i < l; i++)
     185             :     {
     186          28 :       p = gel(P,i);
     187          28 :       if (absequaliu(p, 2)) continue;
     188          14 :       if (i < l-1) pari_err_DOMAIN("znprimroot", "n","=",F,F);
     189          14 :       e = itos(gel(E,i));
     190             :     }
     191          14 :     if (!p) pari_err_DOMAIN("znprimroot", "n","=",F,F);
     192             :   }
     193             :   else
     194         245 :     e = Z_isanypower(q, &p);
     195         259 :   if (!BPSW_psp(e? p: q)) pari_err_DOMAIN("znprimroot", "n","=", q,q);
     196         245 :   return e > 1? pgener_Zp(p): pgener_Fp(q);
     197             : }
     198             : 
     199             : GEN
     200         329 : znprimroot(GEN N)
     201             : {
     202         329 :   pari_sp av = avma;
     203             :   GEN x, n, F;
     204             : 
     205         329 :   if ((F = check_arith_non0(N,"znprimroot")))
     206             :   {
     207          14 :     F = clean_Z_factor(F);
     208          14 :     N = typ(N) == t_VEC? gel(N,1): factorback(F);
     209             :   }
     210         322 :   N = absi_shallow(N);
     211         322 :   if (abscmpiu(N, 4) <= 0) { set_avma(av); return mkintmodu(N[2]-1,N[2]); }
     212         273 :   switch(mod4(N))
     213             :   {
     214          14 :     case 0: /* N = 0 mod 4 */
     215          14 :       pari_err_DOMAIN("znprimroot", "n","=",N,N);
     216           0 :       x = NULL; break;
     217          28 :     case 2: /* N = 2 mod 4 */
     218          28 :       n = shifti(N,-1); /* becomes odd */
     219          28 :       x = gener_Zp(n,F); if (!mod2(x)) x = addii(x,n);
     220          21 :       break;
     221         231 :     default: /* N odd */
     222         231 :       x = gener_Zp(N,F);
     223         224 :       break;
     224             :   }
     225         245 :   return gc_GEN(av, mkintmod(x, N));
     226             : }
     227             : 
     228             : /* n | (p-1), returns a primitive n-th root of 1 in F_p^* */
     229             : GEN
     230           0 : rootsof1_Fp(GEN n, GEN p)
     231             : {
     232           0 :   pari_sp av = avma;
     233           0 :   GEN L = odd_prime_divisors(n); /* 2 implicit in pgener_Fp_local */
     234           0 :   GEN z = pgener_Fp_local(p, L);
     235           0 :   z = Fp_pow(z, diviiexact(subiu(p,1), n), p); /* prim. n-th root of 1 */
     236           0 :   return gc_INT(av, z);
     237             : }
     238             : 
     239             : GEN
     240        3033 : rootsof1u_Fp(ulong n, GEN p)
     241             : {
     242        3033 :   pari_sp av = avma;
     243        3033 :   GEN z, L = u_odd_prime_divisors(n); /* 2 implicit in pgener_Fp_local */
     244        3033 :   z = pgener_Fp_local(p, Flv_to_ZV(L));
     245        3033 :   z = Fp_pow(z, diviuexact(subiu(p,1), n), p); /* prim. n-th root of 1 */
     246        3033 :   return gc_INT(av, z);
     247             : }
     248             : 
     249             : ulong
     250      215530 : rootsof1_Fl(ulong n, ulong p)
     251             : {
     252      215530 :   pari_sp av = avma;
     253      215530 :   GEN L = u_odd_prime_divisors(n); /* 2 implicit in pgener_Fl_local */
     254      215530 :   ulong z = pgener_Fl_local(p, L);
     255      215530 :   z = Fl_powu(z, (p-1) / n, p); /* prim. n-th root of 1 */
     256      215530 :   return gc_ulong(av,z);
     257             : }
     258             : 
     259             : /*********************************************************************/
     260             : /**                     INVERSE TOTIENT FUNCTION                    **/
     261             : /*********************************************************************/
     262             : /* N t_INT, L a ZV containing all prime divisors of N, and possibly other
     263             :  * primes. Return factor(N) */
     264             : GEN
     265      350651 : Z_factor_listP(GEN N, GEN L)
     266             : {
     267      350651 :   long i, k, l = lg(L);
     268      350651 :   GEN P = cgetg(l, t_COL), E = cgetg(l, t_COL);
     269     1346688 :   for (i = k = 1; i < l; i++)
     270             :   {
     271      996037 :     GEN p = gel(L,i);
     272      996037 :     long v = Z_pvalrem(N, p, &N);
     273      996037 :     if (v)
     274             :     {
     275      792176 :       gel(P,k) = p;
     276      792176 :       gel(E,k) = utoipos(v);
     277      792176 :       k++;
     278             :     }
     279             :   }
     280      350651 :   setlg(P, k);
     281      350651 :   setlg(E, k); return mkmat2(P,E);
     282             : }
     283             : 
     284             : /* look for x such that phi(x) = n, p | x => p > m (if m = NULL: no condition).
     285             :  * L is a list of primes containing all prime divisors of n. */
     286             : static long
     287      621565 : istotient_i(GEN n, GEN m, GEN L, GEN *px)
     288             : {
     289      621565 :   pari_sp av = avma, av2;
     290             :   GEN k, D;
     291             :   long i, v;
     292      621565 :   if (m && mod2(n))
     293             :   {
     294      270914 :     if (!equali1(n)) return 0;
     295       69986 :     if (px) *px = gen_1;
     296       69986 :     return 1;
     297             :   }
     298      350651 :   D = divisors(Z_factor_listP(shifti(n, -1), L));
     299             :   /* loop through primes p > m, d = p-1 | n */
     300      350651 :   av2 = avma;
     301      350651 :   if (!m)
     302             :   { /* special case p = 2, d = 1 */
     303       69986 :     k = n;
     304       69986 :     for (v = 1;; v++) {
     305       69986 :       if (istotient_i(k, gen_2, L, px)) {
     306       69986 :         if (px) *px = shifti(*px, v);
     307       69986 :         return 1;
     308             :       }
     309           0 :       if (mod2(k)) break;
     310           0 :       k = shifti(k,-1);
     311             :     }
     312           0 :     set_avma(av2);
     313             :   }
     314     1099462 :   for (i = 1; i < lg(D); ++i)
     315             :   {
     316     1001588 :     GEN p, d = shifti(gel(D, i), 1); /* even divisors of n */
     317     1001588 :     if (m && cmpii(d, m) < 0) continue;
     318      677782 :     p = addiu(d, 1);
     319      677782 :     if (!isprime(p)) continue;
     320      442064 :     k = diviiexact(n, d);
     321      481593 :     for (v = 1;; v++) {
     322             :       GEN r;
     323      481593 :       if (istotient_i(k, p, L, px)) {
     324      182791 :         if (px) *px = mulii(*px, powiu(p, v));
     325      182791 :         return 1;
     326             :       }
     327      298802 :       k = dvmdii(k, p, &r);
     328      298802 :       if (r != gen_0) break;
     329             :     }
     330      259273 :     set_avma(av2);
     331             :   }
     332       97874 :   return gc_long(av,0);
     333             : }
     334             : 
     335             : /* find x such that phi(x) = n */
     336             : long
     337       70000 : istotient(GEN n, GEN *px)
     338             : {
     339       70000 :   pari_sp av = avma;
     340       70000 :   if (typ(n) != t_INT) pari_err_TYPE("istotient", n);
     341       70000 :   if (signe(n) < 1) return 0;
     342       70000 :   if (mod2(n))
     343             :   {
     344          14 :     if (!equali1(n)) return 0;
     345          14 :     if (px) *px = gen_1;
     346          14 :     return 1;
     347             :   }
     348       69986 :   if (istotient_i(n, NULL, gel(Z_factor(n), 1), px))
     349             :   {
     350       69986 :     if (!px) set_avma(av);
     351             :     else
     352       69986 :       *px = gc_INT(av, *px);
     353       69986 :     return 1;
     354             :   }
     355           0 :   return gc_long(av,0);
     356             : }
     357             : 
     358             : /*********************************************************************/
     359             : /**                        KRONECKER SYMBOL                         **/
     360             : /*********************************************************************/
     361             : /* t = 3,5 mod 8 ?  (= 2 not a square mod t) */
     362             : static int
     363   321036966 : ome(long t)
     364             : {
     365   321036966 :   switch(t & 7)
     366             :   {
     367   182046634 :     case 3:
     368   182046634 :     case 5: return 1;
     369   138990332 :     default: return 0;
     370             :   }
     371             : }
     372             : /* t a t_INT, is t = 3,5 mod 8 ? */
     373             : static int
     374     5609012 : gome(GEN t)
     375     5609012 : { return signe(t)? ome( mod2BIL(t) ): 0; }
     376             : 
     377             : /* assume y odd, return kronecker(x,y) * s */
     378             : static long
     379   227711812 : krouu_s(ulong x, ulong y, long s)
     380             : {
     381   227711812 :   ulong x1 = x, y1 = y, z;
     382  1032100794 :   while (x1)
     383             :   {
     384   804368993 :     long r = vals(x1);
     385   804388989 :     if (r)
     386             :     {
     387   427530598 :       if (odd(r) && ome(y1)) s = -s;
     388   427530591 :       x1 >>= r;
     389             :     }
     390   804388982 :     if (x1 & y1 & 2) s = -s;
     391   804388982 :     z = y1 % x1; y1 = x1; x1 = z;
     392             :   }
     393   227731801 :   return (y1 == 1)? s: 0;
     394             : }
     395             : 
     396             : long
     397    11958235 : kronecker(GEN x, GEN y)
     398             : {
     399    11958235 :   pari_sp av = avma;
     400    11958235 :   long s = 1, r;
     401             :   ulong xu;
     402             : 
     403    11958235 :   if (typ(x) != t_INT) pari_err_TYPE("kronecker",x);
     404    11958235 :   if (typ(y) != t_INT) pari_err_TYPE("kronecker",y);
     405    11958235 :   switch (signe(y))
     406             :   {
     407          63 :     case -1: y = negi(y); if (signe(x) < 0) s = -1; break;
     408         133 :     case 0: return is_pm1(x);
     409             :   }
     410    11958102 :   r = vali(y);
     411    11958102 :   if (r)
     412             :   {
     413     1348912 :     if (!mpodd(x)) return gc_long(av,0);
     414      321711 :     if (odd(r) && gome(x)) s = -s;
     415      321711 :     y = shifti(y,-r);
     416             :   }
     417    10930901 :   x = modii(x,y);
     418    13359060 :   while (lgefint(x) > 3) /* x < y */
     419             :   {
     420             :     GEN z;
     421     2428176 :     r = vali(x);
     422     2428089 :     if (r)
     423             :     {
     424     1326124 :       if (odd(r) && gome(y)) s = -s;
     425     1326083 :       x = shifti(x,-r);
     426             :     }
     427             :     /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */
     428     2427536 :     if (mod2BIL(x) & mod2BIL(y) & 2) s = -s;
     429     2426995 :     z = remii(y,x); y = x; x = z;
     430     2428140 :     if (gc_needed(av,2))
     431             :     {
     432           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"kronecker");
     433           0 :       (void)gc_all(av, 2, &x, &y);
     434             :     }
     435             :   }
     436    10930884 :   xu = itou(x);
     437    10930885 :   if (!xu) return is_pm1(y)? s: 0;
     438    10833654 :   r = vals(xu);
     439    10833652 :   if (r)
     440             :   {
     441     5753665 :     if (odd(r) && gome(y)) s = -s;
     442     5753665 :     xu >>= r;
     443             :   }
     444             :   /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */
     445    10833652 :   if (xu & mod2BIL(y) & 2) s = -s;
     446    10833654 :   return gc_long(av, krouu_s(umodiu(y,xu), xu, s));
     447             : }
     448             : 
     449             : long
     450       40033 : krois(GEN x, long y)
     451             : {
     452             :   ulong yu;
     453       40033 :   long s = 1;
     454             : 
     455       40033 :   if (y <= 0)
     456             :   {
     457          35 :     if (y == 0) return is_pm1(x);
     458           0 :     yu = (ulong)-y; if (signe(x) < 0) s = -1;
     459             :   }
     460             :   else
     461       39998 :     yu = (ulong)y;
     462       39998 :   if (!odd(yu))
     463             :   {
     464             :     long r;
     465       18550 :     if (!mpodd(x)) return 0;
     466       12600 :     r = vals(yu); yu >>= r;
     467       12600 :     if (odd(r) && gome(x)) s = -s;
     468             :   }
     469       34048 :   return krouu_s(umodiu(x, yu), yu, s);
     470             : }
     471             : /* assume y != 0 */
     472             : long
     473    27617296 : kroiu(GEN x, ulong y)
     474             : {
     475             :   long r;
     476    27617296 :   if (odd(y)) return krouu_s(umodiu(x,y), y, 1);
     477      302892 :   if (!mpodd(x)) return 0;
     478      208327 :   r = vals(y); y >>= r;
     479      208329 :   return krouu_s(umodiu(x,y), y, (odd(r) && gome(x))? -1: 1);
     480             : }
     481             : 
     482             : /* assume y > 0, odd, return s * kronecker(x,y) */
     483             : static long
     484      178626 : krouodd(ulong x, GEN y, long s)
     485             : {
     486             :   long r;
     487      178626 :   if (lgefint(y) == 3) return krouu_s(x, y[2], s);
     488       28053 :   if (!x) return 0; /* y != 1 */
     489       28053 :   r = vals(x);
     490       28053 :   if (r)
     491             :   {
     492       14645 :     if (odd(r) && gome(y)) s = -s;
     493       14645 :     x >>= r;
     494             :   }
     495             :   /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */
     496       28053 :   if (x & mod2BIL(y) & 2) s = -s;
     497       28053 :   return krouu_s(umodiu(y,x), x, s);
     498             : }
     499             : 
     500             : long
     501      143239 : krosi(long x, GEN y)
     502             : {
     503      143239 :   const pari_sp av = avma;
     504      143239 :   long s = 1, r;
     505      143239 :   switch (signe(y))
     506             :   {
     507           0 :     case -1: y = negi(y); if (x < 0) s = -1; break;
     508           0 :     case 0: return (x==1 || x==-1);
     509             :   }
     510      143239 :   r = vali(y);
     511      143239 :   if (r)
     512             :   {
     513       16884 :     if (!odd(x)) return gc_long(av,0);
     514       16884 :     if (odd(r) && ome(x)) s = -s;
     515       16884 :     y = shifti(y,-r);
     516             :   }
     517      143239 :   if (x < 0) { x = -x; if (mod4(y) == 3) s = -s; }
     518      143239 :   return gc_long(av, krouodd((ulong)x, y, s));
     519             : }
     520             : 
     521             : long
     522       35387 : kroui(ulong x, GEN y)
     523             : {
     524       35387 :   const pari_sp av = avma;
     525       35387 :   long s = 1, r;
     526       35387 :   switch (signe(y))
     527             :   {
     528           0 :     case -1: y = negi(y); break;
     529           0 :     case 0: return x==1UL;
     530             :   }
     531       35387 :   r = vali(y);
     532       35387 :   if (r)
     533             :   {
     534           0 :     if (!odd(x)) return gc_long(av,0);
     535           0 :     if (odd(r) && ome(x)) s = -s;
     536           0 :     y = shifti(y,-r);
     537             :   }
     538       35387 :   return gc_long(av, krouodd(x, y, s));
     539             : }
     540             : 
     541             : long
     542    97370958 : kross(long x, long y)
     543             : {
     544             :   ulong yu;
     545    97370958 :   long s = 1;
     546             : 
     547    97370958 :   if (y <= 0)
     548             :   {
     549       64694 :     if (y == 0) return (labs(x)==1);
     550       64666 :     yu = (ulong)-y; if (x < 0) s = -1;
     551             :   }
     552             :   else
     553    97306264 :     yu = (ulong)y;
     554    97370930 :   if (!odd(yu))
     555             :   {
     556             :     long r;
     557    23549729 :     if (!odd(x)) return 0;
     558    16625375 :     r = vals(yu); yu >>= r;
     559    16625375 :     if (odd(r) && ome(x)) s = -s;
     560             :   }
     561    90446576 :   x %= (long)yu; if (x < 0) x += yu;
     562    90446576 :   return krouu_s((ulong)x, yu, s);
     563             : }
     564             : 
     565             : long
     566    98699080 : krouu(ulong x, ulong y)
     567             : {
     568             :   long r;
     569    98699080 :   if (odd(y)) return krouu_s(x, y, 1);
     570       14526 :   if (!odd(x)) return 0;
     571       17037 :   r = vals(y); y >>= r;
     572       17037 :   return krouu_s(x, y, (odd(r) && ome(x))? -1: 1);
     573             : }
     574             : 
     575             : /*********************************************************************/
     576             : /**                          HILBERT SYMBOL                         **/
     577             : /*********************************************************************/
     578             : /* x,y are t_INT or t_REAL */
     579             : static long
     580        7329 : mphilbertoo(GEN x, GEN y)
     581             : {
     582        7329 :   long sx = signe(x), sy = signe(y);
     583        7329 :   if (!sx || !sy) return 0;
     584        7329 :   return (sx < 0 && sy < 0)? -1: 1;
     585             : }
     586             : 
     587             : long
     588      140826 : hilbertii(GEN x, GEN y, GEN p)
     589             : {
     590             :   pari_sp av;
     591             :   long oddvx, oddvy, z;
     592             : 
     593      140826 :   if (!p) return mphilbertoo(x,y);
     594      133518 :   if (is_pm1(p) || signe(p) < 0) pari_err_PRIME("hilbertii",p);
     595      133518 :   if (!signe(x) || !signe(y)) return 0;
     596      133497 :   av = avma;
     597      133497 :   oddvx = odd(Z_pvalrem(x,p,&x));
     598      133497 :   oddvy = odd(Z_pvalrem(y,p,&y));
     599             :   /* x, y are p-units, compute hilbert(x * p^oddvx, y * p^oddvy, p) */
     600      133497 :   if (absequaliu(p, 2))
     601             :   {
     602       12355 :     z = (Mod4(x) == 3 && Mod4(y) == 3)? -1: 1;
     603       12355 :     if (oddvx && gome(y)) z = -z;
     604       12355 :     if (oddvy && gome(x)) z = -z;
     605             :   }
     606             :   else
     607             :   {
     608      121142 :     z = (oddvx && oddvy && mod4(p) == 3)? -1: 1;
     609      121142 :     if (oddvx && kronecker(y,p) < 0) z = -z;
     610      121142 :     if (oddvy && kronecker(x,p) < 0) z = -z;
     611             :   }
     612      133497 :   return gc_long(av, z);
     613             : }
     614             : 
     615             : static void
     616         196 : err_prec(void) { pari_err_PREC("hilbert"); }
     617             : static void
     618         161 : err_p(GEN p, GEN q) { pari_err_MODULUS("hilbert", p,q); }
     619             : static void
     620          56 : err_oo(GEN p) { pari_err_MODULUS("hilbert", p, strtoGENstr("oo")); }
     621             : 
     622             : /* x t_INTMOD, *pp = prime or NULL [ unset, set it to x.mod ].
     623             :  * Return lift(x) provided it's p-adic accuracy is large enough to decide
     624             :  * hilbert()'s value [ problem at p = 2 ] */
     625             : static GEN
     626         420 : lift_intmod(GEN x, GEN *pp)
     627             : {
     628         420 :   GEN p = *pp, N = gel(x,1);
     629         420 :   x = gel(x,2);
     630         420 :   if (!p)
     631             :   {
     632         266 :     *pp = p = N;
     633         266 :     switch(itos_or_0(p))
     634             :     {
     635         126 :       case 2:
     636         126 :       case 4: err_prec();
     637             :     }
     638         140 :     return x;
     639             :   }
     640         154 :   if (!signe(p)) err_oo(N);
     641         112 :   if (absequaliu(p,2))
     642          42 :   { if (vali(N) <= 2) err_prec(); }
     643             :   else
     644          70 :   { if (!dvdii(N,p)) err_p(N,p); }
     645          28 :   if (!signe(x)) err_prec();
     646          21 :   return x;
     647             : }
     648             : /* x t_PADIC, *pp = prime or NULL [ unset, set it to x.p ].
     649             :  * Return lift(x)*p^(v(x) mod 2) provided it's p-adic accuracy is large enough
     650             :  * to decide hilbert()'s value [ problem at p = 2 ]*/
     651             : static GEN
     652         210 : lift_padic(GEN x, GEN *pp)
     653             : {
     654         210 :   GEN p = *pp, q = padic_p(x), u = padic_u(x);
     655         210 :   if (!p) *pp = p = q;
     656         147 :   else if (!equalii(p,q)) err_p(p, q);
     657         105 :   if (absequaliu(p,2) && precp(x) <= 2) err_prec();
     658          70 :   if (!signe(u)) err_prec();
     659          70 :   return odd(valp(x))? mulii(p,u): u;
     660             : }
     661             : 
     662             : long
     663       62314 : hilbert(GEN x, GEN y, GEN p)
     664             : {
     665       62314 :   pari_sp av = avma;
     666       62314 :   long tx = typ(x), ty = typ(y);
     667             : 
     668       62314 :   if (p && typ(p) != t_INT) pari_err_TYPE("hilbert",p);
     669       62314 :   if (tx == t_REAL)
     670             :   {
     671          77 :     if (p && signe(p)) err_oo(p);
     672          63 :     switch (ty)
     673             :     {
     674           7 :       case t_INT:
     675           7 :       case t_REAL: return mphilbertoo(x,y);
     676           0 :       case t_FRAC: return mphilbertoo(x,gel(y,1));
     677          56 :       default: pari_err_TYPE2("hilbert",x,y);
     678             :     }
     679             :   }
     680       62237 :   if (ty == t_REAL)
     681             :   {
     682          14 :     if (p && signe(p)) err_oo(p);
     683          14 :     switch (tx)
     684             :     {
     685          14 :       case t_INT:
     686          14 :       case t_REAL: return mphilbertoo(x,y);
     687           0 :       case t_FRAC: return mphilbertoo(gel(x,1),y);
     688           0 :       default: pari_err_TYPE2("hilbert",x,y);
     689             :     }
     690             :   }
     691       62223 :   if (tx == t_INTMOD) { x = lift_intmod(x, &p); tx = t_INT; }
     692       62020 :   if (ty == t_INTMOD) { y = lift_intmod(y, &p); ty = t_INT; }
     693             : 
     694       61964 :   if (tx == t_PADIC) { x = lift_padic(x, &p); tx = t_INT; }
     695       61901 :   if (ty == t_PADIC) { y = lift_padic(y, &p); ty = t_INT; }
     696             : 
     697       61824 :   if (tx == t_FRAC) { tx = t_INT; x = p? mulii(gel(x,1),gel(x,2)): gel(x,1); }
     698       61824 :   if (ty == t_FRAC) { ty = t_INT; y = p? mulii(gel(y,1),gel(y,2)): gel(y,1); }
     699             : 
     700       61824 :   if (tx != t_INT || ty != t_INT) pari_err_TYPE2("hilbert",x,y);
     701       61824 :   if (p && !signe(p)) p = NULL;
     702       61824 :   return gc_long(av, hilbertii(x,y,p));
     703             : }
     704             : 
     705             : /*******************************************************************/
     706             : /*                       SQUARE ROOT MODULO p                      */
     707             : /*******************************************************************/
     708             : static void
     709     2295924 : checkp(ulong q, ulong p)
     710     2295924 : { if (!q) pari_err_PRIME("Fl_nonsquare",utoipos(p)); }
     711             : /* p = 1 (mod 4) prime, return the first quadratic nonresidue, a prime */
     712             : static ulong
     713    11623941 : nonsquare1_Fl(ulong p)
     714             : {
     715             :   forprime_t S;
     716             :   ulong q;
     717    11623941 :   if ((p & 7UL) != 1) return 2UL;
     718     4335316 :   q = p % 3; if (q == 2) return 3UL;
     719     1427076 :   checkp(q, p);
     720     1431239 :   q = p % 5; if (q == 2 || q == 3) return 5UL;
     721      531304 :   checkp(q, p);
     722      531298 :   q = p % 7; if (q != 4 && q >= 3) return 7UL;
     723      201756 :   checkp(q, p);
     724             :   /* log^2(2^64) < 1968 is enough under GRH (and p^(1/4)log(p) without it)*/
     725      201776 :   u_forprime_init(&S, 11, 1967);
     726      333498 :   while ((q = u_forprime_next(&S)))
     727             :   {
     728      333498 :     if (krouu(q, p) < 0) return q;
     729      131716 :     checkp(q, p);
     730             :   }
     731           0 :   checkp(0, p);
     732             :   return 0; /*LCOV_EXCL_LINE*/
     733             : }
     734             : /* p > 2 a prime */
     735             : ulong
     736        7930 : nonsquare_Fl(ulong p)
     737        7930 : { return ((p & 3UL) == 3)? p-1: nonsquare1_Fl(p); }
     738             : 
     739             : /* allow pi = 0 */
     740             : ulong
     741      178491 : Fl_2gener_pre(ulong p, ulong pi)
     742             : {
     743      178491 :   ulong p1 = p-1;
     744      178491 :   long e = vals(p1);
     745      178479 :   if (e == 1) return p1;
     746       66158 :   return Fl_powu_pre(nonsquare1_Fl(p), p1 >> e, p, pi);
     747             : }
     748             : 
     749             : ulong
     750       65765 : Fl_2gener_pre_i(ulong  ns, ulong p, ulong pi)
     751             : {
     752       65765 :   ulong p1 = p-1;
     753       65765 :   long e = vals(p1);
     754       65765 :   if (e == 1) return p1;
     755       25152 :   return Fl_powu_pre(ns, p1 >> e, p, pi);
     756             : }
     757             : 
     758             : static ulong
     759    12423879 : Fl_sqrt_i(ulong a, ulong y, ulong p)
     760             : {
     761             :   long i, e, k;
     762             :   ulong p1, q, v, w;
     763             : 
     764    12423879 :   if (!a) return 0;
     765    11149093 :   p1 = p - 1; e = vals(p1);
     766    11149723 :   if (e == 0) /* p = 2 */
     767             :   {
     768      650076 :     if (p != 2) pari_err_PRIME("Fl_sqrt [modulus]",utoi(p));
     769      651335 :     return ((a & 1) == 0)? 0: 1;
     770             :   }
     771    10499647 :   if (e == 1)
     772             :   {
     773     4995526 :     v = Fl_powu(a, (p+1) >> 2, p);
     774     4995586 :     if (Fl_sqr(v, p) != a) return ~0UL;
     775     4990706 :     p1 = p - v; if (v > p1) v = p1;
     776     4990706 :     return v;
     777             :   }
     778     5504121 :   q = p1 >> e; /* q = (p-1)/2^oo is odd */
     779     5504121 :   p1 = Fl_powu(a, q >> 1, p); /* a ^ [(q-1)/2] */
     780     5504122 :   if (!p1) return 0;
     781     5504122 :   v = Fl_mul(a, p1, p);
     782     5504122 :   w = Fl_mul(v, p1, p);
     783     5504175 :   if (!y) y = Fl_powu(nonsquare1_Fl(p), q, p);
     784     9347905 :   while (w != 1)
     785             :   { /* a*w = v^2, y primitive 2^e-th root of 1
     786             :        a square --> w even power of y, hence w^(2^(e-1)) = 1 */
     787     3845608 :     p1 = Fl_sqr(w, p);
     788     6372113 :     for (k=1; p1 != 1 && k < e; k++) p1 = Fl_sqr(p1, p);
     789     3845595 :     if (k == e) return ~0UL;
     790             :     /* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */
     791     3843518 :     p1 = y;
     792     5118224 :     for (i=1; i < e-k; i++) p1 = Fl_sqr(p1, p);
     793     3843522 :     y = Fl_sqr(p1, p); e = k;
     794     3843559 :     w = Fl_mul(y, w, p);
     795     3843567 :     v = Fl_mul(v, p1, p);
     796             :   }
     797     5502297 :   p1 = p - v; if (v > p1) v = p1;
     798     5502297 :   return v;
     799             : }
     800             : 
     801             : /* Tonelli-Shanks. Assume p is prime and (a,p) != -1. Allow pi = 0 */
     802             : ulong
     803    33652805 : Fl_sqrt_pre_i(ulong a, ulong y, ulong p, ulong pi)
     804             : {
     805             :   long i, e, k;
     806             :   ulong p1, q, v, w;
     807             : 
     808    33652805 :   if (!pi) return Fl_sqrt_i(a, y, p);
     809    21228887 :   if (!a) return 0;
     810    21103705 :   p1 = p - 1; e = vals(p1);
     811    21104080 :   if (e == 0) /* p = 2 */
     812             :   {
     813           0 :     if (p != 2) pari_err_PRIME("Fl_sqrt [modulus]",utoi(p));
     814           0 :     return ((a & 1) == 0)? 0: 1;
     815             :   }
     816    21109707 :   if (e == 1)
     817             :   {
     818    15009237 :     v = Fl_powu_pre(a, (p+1) >> 2, p, pi);
     819    15027819 :     if (Fl_sqr_pre(v, p, pi) != a) return ~0UL;
     820    15028419 :     p1 = p - v; if (v > p1) v = p1;
     821    15028419 :     return v;
     822             :   }
     823     6100470 :   q = p1 >> e; /* q = (p-1)/2^oo is odd */
     824     6100470 :   p1 = Fl_powu_pre(a, q >> 1, p, pi); /* a ^ [(q-1)/2] */
     825     6102360 :   if (!p1) return 0;
     826     6102360 :   v = Fl_mul_pre(a, p1, p, pi);
     827     6101931 :   w = Fl_mul_pre(v, p1, p, pi);
     828     6101017 :   if (!y) y = Fl_powu_pre(nonsquare1_Fl(p), q, p, pi);
     829    11597874 :   while (w != 1)
     830             :   { /* a*w = v^2, y primitive 2^e-th root of 1
     831             :        a square --> w even power of y, hence w^(2^(e-1)) = 1 */
     832     5494891 :     p1 = Fl_sqr_pre(w,p,pi);
     833    10246639 :     for (k=1; p1 != 1 && k < e; k++) p1 = Fl_sqr_pre(p1,p,pi);
     834     5494229 :     if (k == e) return ~0UL;
     835             :     /* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */
     836     5494137 :     p1 = y;
     837     7211447 :     for (i=1; i < e-k; i++) p1 = Fl_sqr_pre(p1, p, pi);
     838     5494153 :     y = Fl_sqr_pre(p1, p, pi); e = k;
     839     5495655 :     w = Fl_mul_pre(y, w, p, pi);
     840     5494831 :     v = Fl_mul_pre(v, p1, p, pi);
     841             :   }
     842     6102983 :   p1 = p - v; if (v > p1) v = p1;
     843     6102983 :   return v;
     844             : }
     845             : 
     846             : ulong
     847    12302819 : Fl_sqrt(ulong a, ulong p)
     848    12302819 : { ulong pi = (p & HIGHMASK)? get_Fl_red(p): 0; return Fl_sqrt_pre_i(a, 0, p, pi); }
     849             : 
     850             : ulong
     851    21149674 : Fl_sqrt_pre(ulong a, ulong p, ulong pi)
     852    21149674 : { return Fl_sqrt_pre_i(a, 0, p, pi); }
     853             : 
     854             : /* allow pi = 0 */
     855             : static ulong
     856      212456 : Fl_lgener_pre_all(ulong l, long e, ulong r, ulong p, ulong pi, ulong *pt_m)
     857             : {
     858             :   ulong m, m1;
     859             :   long i;
     860             :   for (;;)
     861             :   {
     862      212456 :     m = m1 = Fl_powu_pre(random_Fl(p-1)+1UL, r, p, pi);
     863      212454 :     if (m==1) continue;
     864      232367 :     for (i=1; i<e; i++)
     865             :     {
     866       89785 :       m = Fl_powu_pre(m, l, p, pi);
     867       89786 :       if (m == 1) break;
     868             :     }
     869      159924 :     if (i==e) break;
     870             :   }
     871      142581 :   *pt_m = m; return m1;
     872             : }
     873             : 
     874             : /* Solve x^l = a in G = Fp^* of order p-1 = (l^e)*r; l prime, (r,l) = 1, e >= 1
     875             :  * y generates the l-Sylow of G, m = y^(l^(e-1)) != 1. Allow y = 0, in which
     876             :  * case m is ignored and (y,m) are computed from scratch */
     877             : static ulong
     878      226773 : Fl_sqrtl_raw(ulong a, ulong l, ulong e, ulong r, ulong p, ulong pi, ulong y, ulong m)
     879             : {
     880             :   ulong u2, v, w, z, dl;
     881      226773 :   u2 = Fl_inv(l%r, r);
     882      226773 :   v = Fl_powu_pre(a, u2, p, pi);
     883      226772 :   w = Fl_powu_pre(v, l, p, pi); if (w == a) return v;
     884      139961 :   w = pi? Fl_mul_pre(w, Fl_inv(a, p), p, pi): Fl_div(w, a, p);
     885      139947 :   if (!y) y = Fl_lgener_pre_all(l, e, r, p, pi, &m);
     886      166556 :   while (w != 1)
     887             :   {
     888      146475 :     ulong k = 0, p1 = w;
     889             :     do
     890             :     {
     891      190172 :       z = p1; p1 = Fl_powu_pre(p1, l, p, pi);
     892      190174 :       if (++k == e) return ULONG_MAX;
     893       70307 :     } while (p1 != 1);
     894             :     /* z = w^(l^(k-1)) has order l */
     895       26610 :     dl = Fl_log_pre(z, m, l, p, pi);
     896       26610 :     dl = Fl_neg(dl, l);
     897       26610 :     p1 = Fl_powu_pre(y, dl*upowuu(l,e-k-1), p, pi);
     898       26609 :     m = Fl_powu_pre(m, dl, p, pi);
     899       26610 :     e = k;
     900       26610 :     v = pi? Fl_mul_pre(p1,v,p,pi): Fl_mul(p1,v,p);
     901       26610 :     y = Fl_powu_pre(p1,l,p,pi);
     902       26610 :     w = pi? Fl_mul_pre(y,w,p,pi): Fl_mul(y,w,p);
     903             :   }
     904       20081 :   return v;
     905             : }
     906             : 
     907             : /* allow pi = 0 */
     908             : ulong
     909      223933 : Fl_sqrtl_pre(ulong a, ulong l, ulong p, ulong pi)
     910             : {
     911             :   ulong r, e;
     912      223933 :   if (!a) return 0;
     913      223921 :   e = u_lvalrem(p-1, l, &r);
     914      223920 :   return Fl_sqrtl_raw(a, l, e, r, p, pi, 0, 0);
     915             : }
     916             : ulong
     917           0 : Fl_sqrtl(ulong a, ulong l, ulong p)
     918           0 : { ulong pi = (p & HIGHMASK)? get_Fl_red(p): 0;
     919           0 :   return Fl_sqrtl_pre(a, l, p, pi); }
     920             : 
     921             : /* allow pi = 0 */
     922             : ulong
     923      232509 : Fl_sqrtn_pre(ulong a, long n, ulong p, ulong pi, ulong *zetan)
     924             : {
     925      232509 :   ulong m, q = p-1, z;
     926      232509 :   ulong nn = n >= 0 ? (ulong)n: -(ulong)n;
     927      232509 :   if (a==0)
     928             :   {
     929      116389 :     if (n < 0) pari_err_INV("Fl_sqrtn", mkintmod(gen_0,utoi(p)));
     930      116382 :     if (zetan) *zetan = 1UL;
     931      116382 :     return 0;
     932             :   }
     933             :   /* a != 0 */
     934      116120 :   if (n==1)
     935             :   {
     936         420 :     if (zetan) *zetan = 1;
     937         420 :     return n < 0? Fl_inv(a,p): a;
     938             :   }
     939      115700 :   if (n==2)
     940             :   {
     941       42111 :     if (zetan) *zetan = p-1;
     942       42111 :     return Fl_sqrt_pre_i(a, 0, p, pi);
     943             :   }
     944       73589 :   if (a == 1 && !zetan) return a;
     945       44115 :   m = ugcd(nn, q);
     946       44115 :   z = 1;
     947       44115 :   if (m!=1)
     948             :   {
     949        2647 :     GEN F = factoru(m);
     950             :     long i, j, e;
     951             :     ulong r, zeta, y, l;
     952        5691 :     for (i = nbrows(F); i; i--)
     953             :     {
     954        3093 :       l = ucoeff(F,i,1);
     955        3093 :       j = ucoeff(F,i,2);
     956        3093 :       e = u_lvalrem(q,l, &r);
     957        3093 :       y = Fl_lgener_pre_all(l, e, r, p, pi, &zeta);
     958        3093 :       if (zetan)
     959             :       {
     960        1354 :         ulong Y = Fl_powu_pre(y, upowuu(l,e-j), p, pi);
     961        1354 :         z = pi? Fl_mul_pre(z, Y, p, pi): Fl_mul(z, Y, p);
     962             :       }
     963        3093 :       if (a!=1)
     964             :         do
     965             :         {
     966        2853 :           a = Fl_sqrtl_raw(a, l, e, r, p, pi, y, zeta);
     967        2839 :           if (a==ULONG_MAX) return ULONG_MAX;
     968        2804 :         } while (--j);
     969             :     }
     970             :   }
     971       44066 :   if (m != nn)
     972             :   {
     973       41489 :     ulong qm = q/m, nm = (nn/m) % qm;
     974       41489 :     a = Fl_powu_pre(a, Fl_inv(nm, qm), p, pi);
     975             :   }
     976       44066 :   if (n < 0) a = Fl_inv(a, p);
     977       44066 :   if (zetan) *zetan = z;
     978       44066 :   return a;
     979             : }
     980             : 
     981             : ulong
     982      232509 : Fl_sqrtn(ulong a, long n, ulong p, ulong *zetan)
     983             : {
     984      232509 :   ulong pi = (p & HIGHMASK)? get_Fl_red(p): 0;
     985      232509 :   return Fl_sqrtn_pre(a, n, p, pi, zetan);
     986             : }
     987             : 
     988             : /* Cipolla is better than Tonelli-Shanks when e = v_2(p-1) is "too big".
     989             :  * Otherwise, is a constant times worse; for p = 3 (mod 4), is about 3 times worse,
     990             :  * and in average is about 2 or 2.5 times worse. But try both algorithms for
     991             :  * S(n) = (2^n+3)^2-8 with n = 750, 771, 779, 790, 874, 1176, 1728, 2604, etc.
     992             :  *
     993             :  * If X^2 := t^2 - a  is not a square in F_p (so X is in F_p^2), then
     994             :  *   (t+X)^(p+1) = (t-X)(t+X) = a,   hence  sqrt(a) = (t+X)^((p+1)/2)  in F_p^2.
     995             :  * If (a|p)=1, then sqrt(a) is in F_p.
     996             :  * cf: LNCS 2286, pp 430-434 (2002)  [Gonzalo Tornaria] */
     997             : 
     998             : /* compute y^2, y = y[1] + y[2] X */
     999             : static GEN
    1000           0 : sqrt_Cipolla_sqr(void *data, GEN y)
    1001             : {
    1002           0 :   GEN u = gel(y,1), v = gel(y,2), p = gel(data,2), n = gel(data,3);
    1003           0 :   GEN u2 = sqri(u), v2 = sqri(v);
    1004           0 :   v = subii(sqri(addii(v,u)), addii(u2,v2));
    1005           0 :   u = addii(u2, mulii(v2,n));
    1006           0 :   retmkvec2(modii(u,p), modii(v,p));
    1007             : }
    1008             : /* compute (t+X) y^2 */
    1009             : static GEN
    1010           0 : sqrt_Cipolla_msqr(void *data, GEN y)
    1011             : {
    1012           0 :   GEN u = gel(y,1), v = gel(y,2), a = gel(data,1), p = gel(data,2);
    1013           0 :   ulong t = gel(data,4)[2];
    1014           0 :   GEN d = addii(u, mului(t,v)), d2 = sqri(d);
    1015           0 :   GEN b = remii(mulii(a,v), p);
    1016           0 :   u = subii(mului(t,d2), mulii(b,addii(u,d)));
    1017           0 :   v = subii(d2, mulii(b,v));
    1018           0 :   retmkvec2(modii(u,p), modii(v,p));
    1019             : }
    1020             : /* assume a reduced mod p [ otherwise correct but inefficient ] */
    1021             : static GEN
    1022           0 : sqrt_Cipolla(GEN a, GEN p)
    1023             : {
    1024             :   pari_sp av;
    1025             :   GEN u, n, y, pov2;
    1026             :   ulong t;
    1027             : 
    1028           0 :   if (kronecker(a, p) < 0) return NULL;
    1029           0 :   pov2 = shifti(p,-1); /* center to avoid multiplying by huge base*/
    1030           0 :   if (cmpii(a,pov2) > 0) a = subii(a,p);
    1031           0 :   av = avma;
    1032           0 :   for (t=1; ; t++, set_avma(av))
    1033             :   {
    1034           0 :     n = subsi((long)(t*t), a);
    1035           0 :     if (kronecker(n, p) < 0) break;
    1036             :   }
    1037             : 
    1038             :   /* compute (t+X)^((p-1)/2) =: u+vX */
    1039           0 :   u = utoipos(t);
    1040           0 :   y = gen_pow_fold(mkvec2(u, gen_1), pov2, mkvec4(a,p,n,u),
    1041             :                    sqrt_Cipolla_sqr, sqrt_Cipolla_msqr);
    1042             :   /* Now u+vX = (t+X)^((p-1)/2); thus
    1043             :    *   (u+vX)(t+X) = sqrt(a) + 0 X
    1044             :    * Whence,
    1045             :    *   sqrt(a) = (u+vt)t - v*a
    1046             :    *   0       = (u+vt)
    1047             :    * Thus a square root is v*a */
    1048           0 :   return Fp_mul(gel(y,2), a, p);
    1049             : }
    1050             : 
    1051             : /* Return NULL if p is found to be composite.
    1052             :  * p odd, q = (p-1)/2^oo is odd */
    1053             : static GEN
    1054        5748 : Fp_2gener_all(GEN q, GEN p)
    1055             : {
    1056             :   long k;
    1057        5748 :   for (k = 2;; k++)
    1058       12338 :   {
    1059       18086 :     long i = kroui(k, p);
    1060       18086 :     if (i < 0) return Fp_pow(utoipos(k), q, p);
    1061       12338 :     if (i == 0) return NULL;
    1062             :   }
    1063             : }
    1064             : 
    1065             : /* Return NULL if p is found to be composite */
    1066             : GEN
    1067        3187 : Fp_2gener(GEN p)
    1068             : {
    1069        3187 :   GEN q = subiu(p, 1);
    1070        3187 :   long e = Z_lvalrem(q, 2, &q);
    1071        3187 :   if (e == 0 && !equaliu(p,2)) return NULL;
    1072        3187 :   return Fp_2gener_all(q, p);
    1073             : }
    1074             : 
    1075             : GEN
    1076       19392 : Fp_2gener_i(GEN ns, GEN p)
    1077             : {
    1078       19392 :   GEN q = subiu(p,1);
    1079       19392 :   long e = vali(q);
    1080       19392 :   if (e == 1) return q;
    1081       18129 :   return Fp_pow(ns, shifti(q,-e), p);
    1082             : }
    1083             : 
    1084             : static GEN
    1085        1339 : nonsquare_Fp(GEN p)
    1086             : {
    1087             :   forprime_t T;
    1088             :   ulong a;
    1089        1339 :   if (mod4(p)==3) return gen_m1;
    1090        1339 :   if (mod8(p)==5) return gen_2;
    1091         592 :   u_forprime_init(&T, 3, ULONG_MAX);
    1092        1190 :   while((a = u_forprime_next(&T)))
    1093        1190 :     if (kroui(a,p) < 0) return utoi(a);
    1094           0 :   pari_err_PRIME("Fp_sqrt [modulus]",p);
    1095             :   return NULL; /* LCOV_EXCL_LINE */
    1096             : }
    1097             : 
    1098             : static GEN
    1099         760 : Fp_rootsof1(ulong l, GEN p)
    1100             : {
    1101         760 :   GEN z, pl = diviuexact(subis(p,1),l);
    1102             :   ulong a;
    1103             :   forprime_t T;
    1104         760 :   u_forprime_init(&T, 3, ULONG_MAX);
    1105        1028 :   while((a = u_forprime_next(&T)))
    1106             :   {
    1107        1028 :     z = Fp_pow(utoi(a), pl, p);
    1108        1028 :     if (!equali1(z)) return z;
    1109             :   }
    1110           0 :   pari_err_PRIME("Fp_sqrt [modulus]",p);
    1111             :   return NULL; /* LCOV_EXCL_LINE */
    1112             : }
    1113             : 
    1114             : static GEN
    1115         284 : Fp_gausssum(long D, GEN p)
    1116             : {
    1117         284 :   long i, l = labs(D);
    1118         284 :   GEN z = Fp_rootsof1(l, p);
    1119         284 :   GEN s = z, x = z;
    1120        2790 :   for(i = 2; i < l; i++)
    1121             :   {
    1122        2506 :     long k = kross(i,l);
    1123        2506 :     x = mulii(x, z);
    1124        2506 :     if (k==1) s = addii(s, x);
    1125        1395 :     else if (k==-1) s = subii(s, x);
    1126             :   }
    1127         284 :   return s;
    1128             : }
    1129             : 
    1130             : static GEN
    1131       18177 : Fp_sqrts(long a, GEN p)
    1132             : {
    1133       18177 :   long v = vals(a)>>1;
    1134       18177 :   GEN r = gen_0;
    1135       18177 :   a >>= v << 1;
    1136       18177 :   switch(a)
    1137             :   {
    1138           1 :     case 1:
    1139           1 :       r = gen_1;
    1140           1 :       break;
    1141        1061 :     case -1:
    1142        1061 :       if (mod4(p)==1)
    1143        1061 :         r = Fp_pow(nonsquare_Fp(p), shifti(p,-2),p);
    1144             :       else
    1145           0 :         r = NULL;
    1146        1061 :       break;
    1147         125 :     case 2:
    1148         125 :       if (mod8(p)==1)
    1149             :       {
    1150         125 :         GEN z = Fp_pow(nonsquare_Fp(p), shifti(p,-3),p);
    1151         125 :         r = Fp_mul(z,Fp_sub(gen_1,Fp_sqr(z,p),p),p);
    1152           0 :       } else if (mod8(p)==7)
    1153           0 :         r = Fp_pow(gen_2, shifti(addiu(p,1),-2),p);
    1154             :       else
    1155           0 :         return NULL;
    1156         125 :       break;
    1157         153 :     case -2:
    1158         153 :       if (mod8(p)==1)
    1159             :       {
    1160         153 :         GEN z = Fp_pow(nonsquare_Fp(p), shifti(p,-3),p);
    1161         153 :         r = Fp_mul(z,Fp_add(gen_1,Fp_sqr(z,p),p),p);
    1162           0 :       } else if (mod8(p)==3)
    1163           0 :         r = Fp_pow(gen_m2, shifti(addiu(p,1),-2),p);
    1164             :       else
    1165           0 :         return NULL;
    1166         153 :       break;
    1167         476 :     case -3:
    1168         476 :       if (umodiu(p,3)==1)
    1169             :       {
    1170         476 :         GEN z = Fp_rootsof1(3, p);
    1171         476 :         r = Fp_sub(z,Fp_sqr(z,p),p);
    1172             :       }
    1173             :       else
    1174           0 :         return NULL;
    1175         476 :       break;
    1176        2045 :     case 5: case 13: case 17: case 21: case 29: case 33:
    1177             :     case -7: case -11: case -15: case -19: case -23:
    1178        2045 :       if (umodiu(p,labs(a))==1)
    1179         284 :         r = Fp_gausssum(a,p);
    1180             :       else
    1181        1763 :         return gen_0;
    1182         284 :       break;
    1183       14316 :     default:
    1184       14316 :       return gen_0;
    1185             :   }
    1186        2100 :   return remii(shifti(r, v), p);
    1187             : }
    1188             : 
    1189             : static GEN
    1190       75179 : Fp_sqrt_ii(GEN a, GEN y, GEN p)
    1191             : {
    1192       75179 :   pari_sp av = avma;
    1193       75179 :   GEN  q, v, w, p1 = subiu(p,1);
    1194       75165 :   long i, k, e = vali(p1), as;
    1195             : 
    1196             :   /* direct formulas more efficient */
    1197       75166 :   if (e == 0) pari_err_PRIME("Fp_sqrt [modulus]",p); /* p != 2 */
    1198       75166 :   if (e == 1)
    1199             :   {
    1200       18545 :     q = addiu(shifti(p1,-2),1); /* (p+1) / 4 */
    1201       18547 :     v = Fp_pow(a, q, p);
    1202             :     /* must check equality in case (a/p) = -1 or p not prime */
    1203       18557 :     av = avma; e = equalii(Fp_sqr(v,p), a); set_avma(av);
    1204       18557 :     return e? v: NULL;
    1205             :   }
    1206       56621 :   as = itos_or_0(a);
    1207       56623 :   if (!as) as = itos_or_0(subii(a,p));
    1208       56628 :   if (as)
    1209             :   {
    1210       18178 :     GEN res = Fp_sqrts(as, p);
    1211       18179 :     if (!res) return gc_NULL(av);
    1212       18179 :     if (signe(res)) return gc_upto(av, res);
    1213             :   }
    1214       54529 :   if (e == 2)
    1215             :   { /* Atkin's formula */
    1216       17683 :     GEN I, a2 = shifti(a,1);
    1217       17682 :     if (cmpii(a2,p) >= 0) a2 = subii(a2,p);
    1218       17682 :     q = shifti(p1, -3); /* (p-5)/8 */
    1219       17683 :     v = Fp_pow(a2, q, p);
    1220       17686 :     I = Fp_mul(a2, Fp_sqr(v,p), p); /* I^2 = -1 */
    1221       17686 :     v = Fp_mul(a, Fp_mul(v, subiu(I,1), p), p);
    1222             :     /* must check equality in case (a/p) = -1 or p not prime */
    1223       17686 :     av = avma; e = equalii(Fp_sqr(v,p), a); set_avma(av);
    1224       17686 :     return e? v: NULL;
    1225             :   }
    1226             :   /* On average, Cipolla is better than Tonelli/Shanks if and only if
    1227             :    * e(e-1) > 8*log2(n)+20, see LNCS 2286 pp 430 [GTL] */
    1228       36846 :   if (e*(e-1) > 20 + 8 * expi(p)) return sqrt_Cipolla(a,p);
    1229             :   /* Tonelli-Shanks */
    1230       36844 :   av = avma; q = shifti(p1,-e); /* q = (p-1)/2^oo is odd */
    1231       36844 :   if (!y)
    1232             :   {
    1233        2561 :     y = Fp_2gener_all(q, p);
    1234        2561 :     if (!y) pari_err_PRIME("Fp_sqrt [modulus]",p);
    1235             :   }
    1236       36844 :   p1 = Fp_pow(a, shifti(q,-1), p); /* a ^ (q-1)/2 */
    1237       36846 :   v = Fp_mul(a, p1, p);
    1238       36846 :   w = Fp_mul(v, p1, p);
    1239       87762 :   while (!equali1(w))
    1240             :   { /* a*w = v^2, y primitive 2^e-th root of 1
    1241             :        a square --> w even power of y, hence w^(2^(e-1)) = 1 */
    1242       50959 :     p1 = Fp_sqr(w,p);
    1243      106587 :     for (k=1; !equali1(p1) && k < e; k++) p1 = Fp_sqr(p1,p);
    1244       50954 :     if (k == e) return NULL; /* p composite or (a/p) != 1 */
    1245             :     /* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */
    1246       50911 :     p1 = y;
    1247       73068 :     for (i=1; i < e-k; i++) p1 = Fp_sqr(p1,p);
    1248       50911 :     y = Fp_sqr(p1, p); e = k;
    1249       50916 :     w = Fp_mul(y, w, p);
    1250       50918 :     v = Fp_mul(v, p1, p);
    1251       50916 :     if (gc_needed(av,1))
    1252             :     {
    1253           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"Fp_sqrt");
    1254           0 :       (void)gc_all(av,3, &y,&w,&v);
    1255             :     }
    1256             :   }
    1257       36802 :   return v;
    1258             : }
    1259             : 
    1260             : /* Assume p is prime and return NULL if (a,p) = -1; y = NULL or generator
    1261             :  * of Fp^* 2-Sylow */
    1262             : GEN
    1263     4886479 : Fp_sqrt_i(GEN a, GEN y, GEN p)
    1264             : {
    1265     4886479 :   pari_sp av = avma, av2;
    1266             :   GEN q;
    1267             : 
    1268     4886479 :   if (lgefint(p) == 3)
    1269             :   {
    1270     4811183 :     ulong pp = uel(p,2), u = umodiu(a, pp);
    1271     4811198 :     if (!u) return gen_0;
    1272     3599348 :     u = Fl_sqrt(u, pp);
    1273     3599409 :     return (u == ~0UL)? NULL: utoipos(u);
    1274             :   }
    1275       75296 :   a = modii(a, p); if (!signe(a)) return gen_0;
    1276       75179 :   a = Fp_sqrt_ii(a, y, p); if (!a) return gc_NULL(av);
    1277             :   /* smallest square root */
    1278       74770 :   av2 = avma; q = subii(p, a);
    1279       74770 :   if (cmpii(a, q) > 0) a = q; else set_avma(av2);
    1280       74771 :   return gc_INT(av, a);
    1281             : }
    1282             : GEN
    1283     4832682 : Fp_sqrt(GEN a, GEN p) { return Fp_sqrt_i(a, NULL, p); }
    1284             : 
    1285             : /*********************************************************************/
    1286             : /**                        GCD & BEZOUT                             **/
    1287             : /*********************************************************************/
    1288             : 
    1289             : GEN
    1290    53358826 : lcmii(GEN x, GEN y)
    1291             : {
    1292             :   pari_sp av;
    1293             :   GEN a, b;
    1294    53358826 :   if (!signe(x) || !signe(y)) return gen_0;
    1295    53358836 :   av = avma; a = gcdii(x,y);
    1296    53358019 :   if (absequalii(a,y)) { set_avma(av); return absi(x); }
    1297    11690978 :   if (!equali1(a)) y = diviiexact(y,a);
    1298    11690980 :   b = mulii(x,y); setabssign(b); return gc_INT(av, b);
    1299             : }
    1300             : 
    1301             : /* given x in assume 0 < x < N; return u in (Z/NZ)^* such that u x = gcd(x,N) (mod N);
    1302             :  * set *pd = gcd(x,N) */
    1303             : GEN
    1304     5889617 : Fp_invgen(GEN x, GEN N, GEN *pd)
    1305             : {
    1306             :   GEN d, d0, e, v;
    1307     5889617 :   if (lgefint(N) == 3)
    1308             :   {
    1309     5107786 :     ulong dd, NN = N[2], xx = umodiu(x,NN);
    1310     5107785 :     if (!xx) { *pd = N; return gen_0; }
    1311     5107785 :     xx = Fl_invgen(xx, NN, &dd);
    1312     5108546 :     *pd = utoi(dd); return utoi(xx);
    1313             :   }
    1314      781831 :   *pd = d = bezout(x, N, &v, NULL);
    1315      781839 :   if (equali1(d)) return v;
    1316             :   /* vx = gcd(x,N) (mod N), v coprime to N/d but need not be coprime to N */
    1317      685010 :   e = diviiexact(N,d);
    1318      685010 :   d0 = Z_ppo(d, e); /* d = d0 d1, d0 coprime to N/d, rad(d1) | N/d */
    1319      685010 :   if (equali1(d0)) return v;
    1320      542896 :   if (!equalii(d,d0)) e = lcmii(e, diviiexact(d,d0));
    1321      542896 :   return Z_chinese_coprime(v, gen_1, e, d0, mulii(e,d0));
    1322             : }
    1323             : 
    1324             : /*********************************************************************/
    1325             : /**                      CHINESE REMAINDERS                         **/
    1326             : /*********************************************************************/
    1327             : 
    1328             : /* Chinese Remainder Theorem.  x and y must have the same type (integermod,
    1329             :  * polymod, or polynomial/vector/matrix recursively constructed with these
    1330             :  * as coefficients). Creates (with the same type) a z in the same residue
    1331             :  * class as x and the same residue class as y, if it is possible.
    1332             :  *
    1333             :  * We also allow (during recursion) two identical objects even if they are
    1334             :  * not integermod or polymod. For example:
    1335             :  *
    1336             :  * ? x = [1, Mod(5, 11), Mod(X + Mod(2, 7), X^2 + 1)];
    1337             :  * ? y = [1, Mod(7, 17), Mod(X + Mod(0, 3), X^2 + 1)];
    1338             :  * ? chinese(x, y)
    1339             :  * %3 = [1, Mod(16, 187), Mod(X + mod(9, 21), X^2 + 1)] */
    1340             : 
    1341             : static GEN
    1342     2416253 : gen_chinese(GEN x, GEN(*f)(GEN,GEN))
    1343             : {
    1344     2416253 :   GEN z = gassoc_proto(f,x,NULL);
    1345     2416246 :   if (z == gen_1) retmkintmod(gen_0,gen_1);
    1346     2416197 :   return z;
    1347             : }
    1348             : 
    1349             : GEN
    1350        2415 : chinese1(GEN x) { return gen_chinese(x,chinese); }
    1351             : 
    1352             : static GEN
    1353          21 : padic2mod(GEN x)
    1354             : {
    1355          21 :   pari_sp av = avma;
    1356          21 :   GEN pd = padic_pd(x), p = padic_p(x), u = padic_u(x);
    1357          21 :   long v = valp(x);
    1358          21 :   if (v < 0) pari_err_INV("chinese", mkintmod(gen_0, p));
    1359          21 :   if (v)
    1360             :   {
    1361           0 :     GEN pv = powiu(p, v);
    1362           0 :     pd = mulii(pd, pv);
    1363           0 :     u = mulii(u, pv);
    1364             :   }
    1365          21 :   return gc_GEN(av, mkintmod(u, pd));
    1366             : 
    1367             : }
    1368             : /* x t_INTMOD, y t_POLMOD; promote x to t_POLMOD mod Pol(x.mod): makes Mod(0,1)
    1369             :  * a better "neutral" element */
    1370             : static GEN
    1371          21 : intmod2polmod(GEN x,GEN y)
    1372          21 : { retmkpolmod(gel(x,2), scalarpol_shallow(gel(x,1), varn(gel(y,1)))); }
    1373             : 
    1374             : GEN
    1375        5495 : chinese(GEN x, GEN y)
    1376             : {
    1377        5495 :   pari_sp av = avma;
    1378             :   long tx, ty;
    1379             :   GEN z;
    1380             : 
    1381        5495 :   if (!y) return chinese1(x);
    1382        5446 :   if (gidentical(x,y)) return gcopy(x);
    1383             :   /* allows GC optimization for this most frequent case */
    1384        5439 :   z = cgetg(3,t_INTMOD);
    1385        5439 :   tx = typ(x); if (tx == t_PADIC) { x = padic2mod(x); tx = t_INTMOD; }
    1386        5439 :   ty = typ(y); if (ty == t_PADIC) { y = padic2mod(y); ty = t_INTMOD; }
    1387        5439 :   if (tx == t_POLMOD && ty == t_INTMOD)
    1388          14 :   { y = intmod2polmod(y, x); ty = t_POLMOD; }
    1389        5439 :   if (ty == t_POLMOD && tx == t_INTMOD)
    1390           7 :   { x = intmod2polmod(x, y); tx = t_POLMOD; }
    1391        5439 :   if (tx == ty) switch(tx)
    1392             :   {
    1393        3892 :     case t_POLMOD:
    1394             :     {
    1395        3892 :       GEN A = gel(x,1), B = gel(y,1);
    1396        3892 :       GEN a = gel(x,2), b = gel(y,2), t, d, e, u, v;
    1397        3892 :       if (varn(A)!=varn(B)) pari_err_VAR("chinese",A,B);
    1398        3892 :       if (RgX_equal(A,B)) retmkpolmod(chinese(a,b), gcopy(A)); /*same modulus*/
    1399        3892 :       d = RgX_extgcd(A,B,&u,&v);
    1400        3892 :       e = gsub(b, a);
    1401        3892 :       if (!gequal0(gmod(e, d))) pari_err_OP("chinese",x,y);
    1402        3892 :       t = gdiv(A, d);
    1403        3892 :       e = gadd(a, gmul(gmul(u,t), e));
    1404             : 
    1405        3892 :       z = cgetg(3, t_POLMOD);
    1406        3892 :       gel(z,1) = RgX_mul(t, B);
    1407        3892 :       gel(z,2) = gmod(e, gel(z,1));
    1408        3892 :       return gc_upto(av, z);
    1409             :     }
    1410        1519 :     case t_INTMOD:
    1411             :     {
    1412        1519 :       GEN A = gel(x,1), B = gel(y,1);
    1413        1519 :       GEN a = gel(x,2), b = gel(y,2), c, d, C, U;
    1414        1519 :       Z_chinese_pre(A, B, &C, &U, &d);
    1415        1519 :       c = Z_chinese_post(a, b, C, U, d);
    1416        1519 :       if (!c) pari_err_OP("chinese", x,y);
    1417        1519 :       set_avma((pari_sp)z); /* GC optimization */
    1418        1519 :       gel(z,1) = icopy(C);
    1419        1519 :       gel(z,2) = icopy(c); return z;
    1420             :     }
    1421          14 :     case t_POL:
    1422             :     {
    1423          14 :       long i, lx = lg(x), ly = lg(y);
    1424          14 :       if (varn(x) != varn(y)) pari_err_OP("chinese",x,y);
    1425          14 :       if (lx < ly) { swap(x,y); lswap(lx,ly); }
    1426          14 :       set_avma(av);
    1427          14 :       z = cgetg(lx, t_POL); z[1] = x[1];
    1428          42 :       for (i=2; i<ly; i++) gel(z,i) = chinese(gel(x,i),gel(y,i));
    1429          14 :       if (i < lx)
    1430             :       {
    1431          14 :         GEN _0 = Rg_get_0(y);
    1432          28 :         for (   ; i<lx; i++) gel(z,i) = chinese(gel(x,i),_0);
    1433             :       }
    1434          14 :       return z;
    1435             :     }
    1436          14 :     case t_VEC: case t_COL: case t_MAT:
    1437             :     {
    1438             :       long i, lx;
    1439          14 :       set_avma(av);
    1440          14 :       z = cgetg_copy(x, &lx); if (lx!=lg(y)) pari_err_OP("chinese",x,y);
    1441          42 :       for (i=1; i<lx; i++) gel(z,i) = chinese(gel(x,i),gel(y,i));
    1442          14 :       return z;
    1443             :     }
    1444             :   }
    1445           0 :   pari_err_OP("chinese",x,y);
    1446             :   return NULL; /* LCOV_EXCL_LINE */
    1447             : }
    1448             : 
    1449             : /* init chinese(Mod(.,A), Mod(.,B)) */
    1450             : void
    1451      271341 : Z_chinese_pre(GEN A, GEN B, GEN *pC, GEN *pU, GEN *pd)
    1452             : {
    1453      271341 :   GEN u, d = bezout(A,B,&u,NULL); /* U = u(A/d), u(A/d) + v(B/d) = 1 */
    1454      271345 :   GEN t = diviiexact(A,d);
    1455      271340 :   *pU = mulii(u, t);
    1456      271338 :   *pC = mulii(t, B); if (pd) *pd = d;
    1457      271334 : }
    1458             : /* Assume C = lcm(A, B), U = 0 mod (A/d), U = 1 mod (B/d), a = b mod d,
    1459             :  * where d = gcd(A,B) or NULL, return x = a (mod A), b (mod B).
    1460             :  * If d not NULL, check whether a = b mod d. */
    1461             : GEN
    1462     3007534 : Z_chinese_post(GEN a, GEN b, GEN C, GEN U, GEN d)
    1463             : {
    1464             :   GEN e;
    1465     3007534 :   if (!signe(a))
    1466             :   {
    1467      797090 :     if (d && !dvdii(b, d)) return NULL;
    1468      797090 :     return Fp_mul(b, U, C);
    1469             :   }
    1470     2210444 :   e = subii(b,a);
    1471     2210444 :   if (d && !dvdii(e, d)) return NULL;
    1472     2210444 :   return modii(addii(a, mulii(U, e)), C);
    1473             : }
    1474             : static ulong
    1475     1587244 : u_chinese_post(ulong a, ulong b, ulong C, ulong U)
    1476             : {
    1477     1587244 :   if (!a) return Fl_mul(b, U, C);
    1478     1587244 :   return Fl_add(a, Fl_mul(U, Fl_sub(b,a,C), C), C);
    1479             : }
    1480             : 
    1481             : GEN
    1482        2142 : Z_chinese(GEN a, GEN b, GEN A, GEN B)
    1483             : {
    1484        2142 :   pari_sp av = avma;
    1485        2142 :   GEN C, U; Z_chinese_pre(A, B, &C, &U, NULL);
    1486        2142 :   return gc_INT(av, Z_chinese_post(a,b, C, U, NULL));
    1487             : }
    1488             : GEN
    1489      267622 : Z_chinese_all(GEN a, GEN b, GEN A, GEN B, GEN *pC)
    1490             : {
    1491      267622 :   GEN U; Z_chinese_pre(A, B, pC, &U, NULL);
    1492      267617 :   return Z_chinese_post(a,b, *pC, U, NULL);
    1493             : }
    1494             : 
    1495             : /* return lift(chinese(a mod A, b mod B))
    1496             :  * assume(A,B)=1, a,b,A,B integers and C = A*B */
    1497             : GEN
    1498      544156 : Z_chinese_coprime(GEN a, GEN b, GEN A, GEN B, GEN C)
    1499             : {
    1500      544156 :   pari_sp av = avma;
    1501      544156 :   GEN U = mulii(Fp_inv(A,B), A);
    1502      544156 :   return gc_INT(av, Z_chinese_post(a,b,C,U, NULL));
    1503             : }
    1504             : ulong
    1505     1587247 : u_chinese_coprime(ulong a, ulong b, ulong A, ulong B, ulong C)
    1506     1587247 : { return u_chinese_post(a,b,C, A * Fl_inv(A % B,B)); }
    1507             : 
    1508             : /* chinese1 for coprime moduli in Z */
    1509             : static GEN
    1510     2191779 : chinese1_coprime_Z_aux(GEN x, GEN y)
    1511             : {
    1512     2191779 :   GEN z = cgetg(3, t_INTMOD);
    1513     2191779 :   GEN A = gel(x,1), a = gel(x, 2);
    1514     2191779 :   GEN B = gel(y,1), b = gel(y, 2), C = mulii(A,B);
    1515     2191779 :   pari_sp av = avma;
    1516     2191779 :   GEN U = mulii(Fp_inv(A,B), A);
    1517     2191779 :   gel(z,2) = gc_INT(av, Z_chinese_post(a,b,C,U, NULL));
    1518     2191779 :   gel(z,1) = C; return z;
    1519             : }
    1520             : GEN
    1521     2413838 : chinese1_coprime_Z(GEN x) {return gen_chinese(x,chinese1_coprime_Z_aux);}
    1522             : 
    1523             : /*********************************************************************/
    1524             : /**                    MODULAR EXPONENTIATION                       **/
    1525             : /*********************************************************************/
    1526             : /* xa ZV or nv */
    1527             : GEN
    1528     2603613 : ZV_producttree(GEN xa)
    1529             : {
    1530     2603613 :   long n = lg(xa)-1;
    1531     2603613 :   long m = n==1 ? 1: expu(n-1)+1;
    1532     2603598 :   GEN T = cgetg(m+1, t_VEC), t;
    1533             :   long i, j, k;
    1534     2603564 :   t = cgetg(((n+1)>>1)+1, t_VEC);
    1535     2603522 :   if (typ(xa)==t_VECSMALL)
    1536             :   {
    1537     3477603 :     for (j=1, k=1; k<n; j++, k+=2)
    1538     2242405 :       gel(t, j) = muluu(xa[k], xa[k+1]);
    1539     1235198 :     if (k==n) gel(t, j) = utoi(xa[k]);
    1540             :   } else {
    1541     2833057 :     for (j=1, k=1; k<n; j++, k+=2)
    1542     1464745 :       gel(t, j) = mulii(gel(xa,k), gel(xa,k+1));
    1543     1368312 :     if (k==n) gel(t, j) = icopy(gel(xa,k));
    1544             :   }
    1545     2603504 :   gel(T,1) = t;
    1546     4152803 :   for (i=2; i<=m; i++)
    1547             :   {
    1548     1549306 :     GEN u = gel(T, i-1);
    1549     1549306 :     long n = lg(u)-1;
    1550     1549306 :     t = cgetg(((n+1)>>1)+1, t_VEC);
    1551     3484230 :     for (j=1, k=1; k<n; j++, k+=2)
    1552     1934931 :       gel(t, j) = mulii(gel(u, k), gel(u, k+1));
    1553     1549299 :     if (k==n) gel(t, j) = gel(u, k);
    1554     1549299 :     gel(T, i) = t;
    1555             :   }
    1556     2603497 :   return T;
    1557             : }
    1558             : 
    1559             : GEN
    1560           0 : ZMV_producttree(GEN xa)
    1561             : {
    1562           0 :   long n = lg(xa)-1;
    1563           0 :   long m = n==1 ? 1: expu(n-1)+1;
    1564           0 :   GEN T = cgetg(m+1, t_VEC), t;
    1565             :   long i, j, k;
    1566           0 :   t = cgetg(((n+1)>>1)+1, t_VEC);
    1567           0 :   for (j=1, k=1; k<n; j++, k+=2)
    1568           0 :     gel(t, j) = ZM_mul(gel(xa,k+1), gel(xa,k));
    1569           0 :   if (k==n) gel(t, j) = ZM_copy(gel(xa,k));
    1570           0 :   gel(T,1) = t;
    1571           0 :   for (i=2; i<=m; i++)
    1572             :   {
    1573           0 :     GEN u = gel(T, i-1);
    1574           0 :     long n = lg(u)-1;
    1575           0 :     t = cgetg(((n+1)>>1)+1, t_VEC);
    1576           0 :     for (j=1, k=1; k<n; j++, k+=2)
    1577           0 :       gel(t, j) = ZM_mul(gel(u, k+1), gel(u, k));
    1578           0 :     if (k==n) gel(t, j) = gel(u, k);
    1579           0 :     gel(T, i) = t;
    1580             :   }
    1581           0 :   return T;
    1582             : }
    1583             : 
    1584             : /* return [A mod P[i], i=1..#P], T = ZV_producttree(P) */
    1585             : GEN
    1586    57227991 : Z_ZV_mod_tree(GEN A, GEN P, GEN T)
    1587             : {
    1588             :   long i,j,k;
    1589    57227991 :   long m = lg(T)-1, n = lg(P)-1;
    1590             :   GEN t;
    1591    57227991 :   GEN Tp = cgetg(m+1, t_VEC);
    1592    57211115 :   gel(Tp, m) = mkvec(modii(A, gmael(T,m,1)));
    1593   119758758 :   for (i=m-1; i>=1; i--)
    1594             :   {
    1595    62572852 :     GEN u = gel(T, i);
    1596    62572852 :     GEN v = gel(Tp, i+1);
    1597    62572852 :     long n = lg(u)-1;
    1598    62572852 :     t = cgetg(n+1, t_VEC);
    1599   150359604 :     for (j=1, k=1; k<n; j++, k+=2)
    1600             :     {
    1601    87856070 :       gel(t, k)   = modii(gel(v, j), gel(u, k));
    1602    87898219 :       gel(t, k+1) = modii(gel(v, j), gel(u, k+1));
    1603             :     }
    1604    62503534 :     if (k==n) gel(t, k) = gel(v, j);
    1605    62503534 :     gel(Tp, i) = t;
    1606             :   }
    1607             :   {
    1608    57185906 :     GEN u = gel(T, i+1);
    1609    57185906 :     GEN v = gel(Tp, i+1);
    1610    57185906 :     long l = lg(u)-1;
    1611    57185906 :     if (typ(P)==t_VECSMALL)
    1612             :     {
    1613    54589780 :       GEN R = cgetg(n+1, t_VECSMALL);
    1614   195548665 :       for (j=1, k=1; j<=l; j++, k+=2)
    1615             :       {
    1616   140928380 :         uel(R,k) = umodiu(gel(v, j), P[k]);
    1617   140870689 :         if (k < n)
    1618   111236972 :           uel(R,k+1) = umodiu(gel(v, j), P[k+1]);
    1619             :       }
    1620    54620285 :       return R;
    1621             :     }
    1622             :     else
    1623             :     {
    1624     2596126 :       GEN R = cgetg(n+1, t_VEC);
    1625     7138746 :       for (j=1, k=1; j<=l; j++, k+=2)
    1626             :       {
    1627     4535478 :         gel(R,k) = modii(gel(v, j), gel(P,k));
    1628     4535471 :         if (k < n)
    1629     3704296 :           gel(R,k+1) = modii(gel(v, j), gel(P,k+1));
    1630             :       }
    1631     2603268 :       return R;
    1632             :     }
    1633             :   }
    1634             : }
    1635             : 
    1636             : /* T = ZV_producttree(P), R = ZV_chinesetree(P,T) */
    1637             : GEN
    1638    39811197 : ZV_chinese_tree(GEN A, GEN P, GEN T, GEN R)
    1639             : {
    1640    39811197 :   long m = lg(T)-1, n = lg(A)-1;
    1641             :   long i,j,k;
    1642    39811197 :   GEN Tp = cgetg(m+1, t_VEC);
    1643    39796807 :   GEN M = gel(T, 1);
    1644    39796807 :   GEN t = cgetg(lg(M), t_VEC);
    1645    39758243 :   if (typ(P)==t_VECSMALL)
    1646             :   {
    1647    84376805 :     for (j=1, k=1; k<n; j++, k+=2)
    1648             :     {
    1649    61348642 :       pari_sp av = avma;
    1650    61348642 :       GEN a = mului(A[k], gel(R,k)), b = mului(A[k+1], gel(R,k+1));
    1651    61296619 :       GEN tj = modii(addii(mului(P[k],b), mului(P[k+1],a)), gel(M,j));
    1652    61375455 :       gel(t, j) = gc_INT(av, tj);
    1653             :     }
    1654    23028163 :     if (k==n) gel(t, j) = modii(mului(A[k], gel(R,k)), gel(M, j));
    1655             :   } else
    1656             :   {
    1657    35573279 :     for (j=1, k=1; k<n; j++, k+=2)
    1658             :     {
    1659    18806400 :       pari_sp av = avma;
    1660    18806400 :       GEN a = mulii(gel(A,k), gel(R,k)), b = mulii(gel(A,k+1), gel(R,k+1));
    1661    18819037 :       GEN tj = modii(addii(mulii(gel(P,k),b), mulii(gel(P,k+1),a)), gel(M,j));
    1662    18856224 :       gel(t, j) = gc_INT(av, tj);
    1663             :     }
    1664    16766879 :     if (k==n) gel(t, j) = modii(mulii(gel(A,k), gel(R,k)), gel(M, j));
    1665             :   }
    1666    39798144 :   gel(Tp, 1) = t;
    1667    74234331 :   for (i=2; i<=m; i++)
    1668             :   {
    1669    34453196 :     GEN u = gel(T, i-1), M = gel(T, i);
    1670    34453196 :     GEN t = cgetg(lg(M), t_VEC);
    1671    34454316 :     GEN v = gel(Tp, i-1);
    1672    34454316 :     long n = lg(v)-1;
    1673    90410133 :     for (j=1, k=1; k<n; j++, k+=2)
    1674             :     {
    1675    55973946 :       pari_sp av = avma;
    1676    55974111 :       gel(t, j) = gc_INT(av, modii(addii(mulii(gel(u, k), gel(v, k+1)),
    1677    55973946 :             mulii(gel(u, k+1), gel(v, k))), gel(M, j)));
    1678             :     }
    1679    34436187 :     if (k==n) gel(t, j) = gel(v, k);
    1680    34436187 :     gel(Tp, i) = t;
    1681             :   }
    1682    39781135 :   return gmael(Tp,m,1);
    1683             : }
    1684             : 
    1685             : static GEN
    1686     1526320 : ncV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)
    1687             : {
    1688     1526320 :   long i, l = lg(gel(vA,1)), n = lg(P);
    1689     1526320 :   GEN mod = gmael(T, lg(T)-1, 1), V = cgetg(l, t_COL);
    1690    33984501 :   for (i=1; i < l; i++)
    1691             :   {
    1692    32458349 :     pari_sp av = avma;
    1693    32458349 :     GEN c, A = cgetg(n, typ(P));
    1694             :     long j;
    1695   186730177 :     for (j=1; j < n; j++) A[j] = mael(vA,j,i);
    1696    32434943 :     c = Fp_center(ZV_chinese_tree(A, P, T, R), mod, m2);
    1697    32463139 :     gel(V,i) = gc_INT(av, c);
    1698             :   }
    1699     1526152 :   return V;
    1700             : }
    1701             : 
    1702             : static GEN
    1703      741147 : nxV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)
    1704             : {
    1705      741147 :   long i, j, l, n = lg(P);
    1706      741147 :   GEN mod = gmael(T, lg(T)-1, 1), V, w;
    1707      741147 :   w = cgetg(n, t_VECSMALL);
    1708     2619673 :   for(j=1; j<n; j++) w[j] = lg(gel(vA,j));
    1709      741133 :   l = vecsmall_max(w);
    1710      741143 :   V = cgetg(l, t_POL);
    1711      741097 :   V[1] = mael(vA,1,1);
    1712     5367026 :   for (i=2; i < l; i++)
    1713             :   {
    1714     4625877 :     pari_sp av = avma;
    1715     4625877 :     GEN c, A = cgetg(n, typ(P));
    1716     4625419 :     if (typ(P)==t_VECSMALL)
    1717    12256167 :       for (j=1; j < n; j++) A[j] = i < w[j] ? mael(vA,j,i): 0;
    1718             :     else
    1719     5855660 :       for (j=1; j < n; j++) gel(A,j) = i < w[j] ? gmael(vA,j,i): gen_0;
    1720     4625419 :     c = Fp_center(ZV_chinese_tree(A, P, T, R), mod, m2);
    1721     4625993 :     gel(V,i) = gc_INT(av, c);
    1722             :   }
    1723      741149 :   return ZX_renormalize(V, l);
    1724             : }
    1725             : 
    1726             : static GEN
    1727        5190 : nxCV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)
    1728             : {
    1729        5190 :   long i, j, l = lg(gel(vA,1)), n = lg(P);
    1730        5190 :   GEN A = cgetg(n, t_VEC);
    1731        5190 :   GEN V = cgetg(l, t_COL);
    1732      104310 :   for (i=1; i < l; i++)
    1733             :   {
    1734      379971 :     for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);
    1735       99120 :     gel(V,i) = nxV_polint_center_tree(A, P, T, R, m2);
    1736             :   }
    1737        5190 :   return V;
    1738             : }
    1739             : 
    1740             : static GEN
    1741      420893 : polint_chinese(GEN worker, GEN mA, GEN P)
    1742             : {
    1743      420893 :   long cnt, pending, n, i, j, l = lg(gel(mA,1));
    1744             :   struct pari_mt pt;
    1745             :   GEN done, va, M, A;
    1746             :   pari_timer ti;
    1747             : 
    1748      420893 :   if (l == 1) return cgetg(1, t_MAT);
    1749      391841 :   cnt = pending = 0;
    1750      391841 :   n = lg(P);
    1751      391841 :   A = cgetg(n, t_VEC);
    1752      391841 :   va = mkvec(A);
    1753      391841 :   M = cgetg(l, t_MAT);
    1754      391841 :   if (DEBUGLEVEL>4) timer_start(&ti);
    1755      391841 :   if (DEBUGLEVEL>5) err_printf("Start parallel Chinese remainder: ");
    1756      391841 :   mt_queue_start_lim(&pt, worker, l-1);
    1757     1423365 :   for (i=1; i<l || pending; i++)
    1758             :   {
    1759             :     long workid;
    1760     3865926 :     for(j=1; j < n; j++) gel(A,j) = gmael(mA,j,i);
    1761     1031524 :     mt_queue_submit(&pt, i, i<l? va: NULL);
    1762     1031524 :     done = mt_queue_get(&pt, &workid, &pending);
    1763     1031524 :     if (done)
    1764             :     {
    1765      991611 :       gel(M,workid) = done;
    1766      991611 :       if (DEBUGLEVEL>5) err_printf("%ld%% ",(++cnt)*100/(l-1));
    1767             :     }
    1768             :   }
    1769      391841 :   if (DEBUGLEVEL>5) err_printf("\n");
    1770      391841 :   if (DEBUGLEVEL>4) timer_printf(&ti, "nmV_chinese_center");
    1771      391841 :   mt_queue_end(&pt);
    1772      391841 :   return M;
    1773             : }
    1774             : 
    1775             : GEN
    1776        1008 : nxMV_polint_center_tree_worker(GEN vA, GEN T, GEN R, GEN P, GEN m2)
    1777             : {
    1778        1008 :   return nxCV_polint_center_tree(vA, P, T, R, m2);
    1779             : }
    1780             : 
    1781             : static GEN
    1782         453 : nxMV_polint_center_tree_seq(GEN vA, GEN P, GEN T, GEN R, GEN m2)
    1783             : {
    1784         453 :   long i, j, l = lg(gel(vA,1)), n = lg(P);
    1785         453 :   GEN A = cgetg(n, t_VEC);
    1786         453 :   GEN V = cgetg(l, t_MAT);
    1787        4635 :   for (i=1; i < l; i++)
    1788             :   {
    1789       16769 :     for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);
    1790        4182 :     gel(V,i) = nxCV_polint_center_tree(A, P, T, R, m2);
    1791             :   }
    1792         453 :   return V;
    1793             : }
    1794             : 
    1795             : static GEN
    1796          97 : nxMV_polint_center_tree(GEN mA, GEN P, GEN T, GEN R, GEN m2)
    1797             : {
    1798          97 :   GEN worker = snm_closure(is_entry("_nxMV_polint_worker"), mkvec4(T, R, P, m2));
    1799          97 :   return polint_chinese(worker, mA, P);
    1800             : }
    1801             : 
    1802             : static GEN
    1803      142015 : nmV_polint_center_tree_seq(GEN vA, GEN P, GEN T, GEN R, GEN m2)
    1804             : {
    1805      142015 :   long i, j, l = lg(gel(vA,1)), n = lg(P);
    1806      142015 :   GEN A = cgetg(n, t_VEC);
    1807      142012 :   GEN V = cgetg(l, t_MAT);
    1808      662132 :   for (i=1; i < l; i++)
    1809             :   {
    1810     2983018 :     for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);
    1811      520123 :     gel(V,i) = ncV_polint_center_tree(A, P, T, R, m2);
    1812             :   }
    1813      142009 :   return V;
    1814             : }
    1815             : 
    1816             : GEN
    1817      990527 : nmV_polint_center_tree_worker(GEN vA, GEN T, GEN R, GEN P, GEN m2)
    1818             : {
    1819      990527 :   return ncV_polint_center_tree(vA, P, T, R, m2);
    1820             : }
    1821             : 
    1822             : static GEN
    1823      420796 : nmV_polint_center_tree(GEN mA, GEN P, GEN T, GEN R, GEN m2)
    1824             : {
    1825      420796 :   GEN worker = snm_closure(is_entry("_polint_worker"), mkvec4(T, R, P, m2));
    1826      420796 :   return polint_chinese(worker, mA, P);
    1827             : }
    1828             : 
    1829             : /* return [A mod P[i], i=1..#P] */
    1830             : GEN
    1831           0 : Z_ZV_mod(GEN A, GEN P)
    1832             : {
    1833           0 :   pari_sp av = avma;
    1834           0 :   return gc_GEN(av, Z_ZV_mod_tree(A, P, ZV_producttree(P)));
    1835             : }
    1836             : /* P a t_VECSMALL */
    1837             : GEN
    1838           0 : Z_nv_mod(GEN A, GEN P)
    1839             : {
    1840           0 :   pari_sp av = avma;
    1841           0 :   return gc_uptoleaf(av, Z_ZV_mod_tree(A, P, ZV_producttree(P)));
    1842             : }
    1843             : /* B a ZX, T = ZV_producttree(P) */
    1844             : GEN
    1845     2413145 : ZX_nv_mod_tree(GEN B, GEN A, GEN T)
    1846             : {
    1847             :   pari_sp av;
    1848     2413145 :   long i, j, l = lg(B), n = lg(A)-1;
    1849     2413145 :   GEN V = cgetg(n+1, t_VEC);
    1850    11455998 :   for (j=1; j <= n; j++)
    1851             :   {
    1852     9043636 :     gel(V, j) = cgetg(l, t_VECSMALL);
    1853     9042955 :     mael(V, j, 1) = B[1]&VARNBITS;
    1854             :   }
    1855     2412362 :   av = avma;
    1856    15712507 :   for (i=2; i < l; i++)
    1857             :   {
    1858    13300420 :     GEN v = Z_ZV_mod_tree(gel(B, i), A, T);
    1859    88059329 :     for (j=1; j <= n; j++)
    1860    74763247 :       mael(V, j, i) = v[j];
    1861    13296082 :     set_avma(av);
    1862             :   }
    1863    11457590 :   for (j=1; j <= n; j++)
    1864     9045639 :     (void) Flx_renormalize(gel(V, j), l);
    1865     2411951 :   return V;
    1866             : }
    1867             : 
    1868             : static GEN
    1869     1201624 : to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; }
    1870             : 
    1871             : GEN
    1872       86830 : ZXX_nv_mod_tree(GEN P, GEN xa, GEN T, long w)
    1873             : {
    1874       86830 :   pari_sp av = avma;
    1875       86830 :   long i, j, l = lg(P), n = lg(xa)-1;
    1876       86830 :   GEN V = cgetg(n+1, t_VEC);
    1877      374794 :   for (j=1; j <= n; j++)
    1878             :   {
    1879      287971 :     gel(V, j) = cgetg(l, t_POL);
    1880      287968 :     mael(V, j, 1) = P[1]&VARNBITS;
    1881             :   }
    1882     1198447 :   for (i=2; i < l; i++)
    1883             :   {
    1884     1111603 :     GEN v = ZX_nv_mod_tree(to_ZX(gel(P, i), w), xa, T);
    1885     4850069 :     for (j=1; j <= n; j++)
    1886     3738445 :       gmael(V, j, i) = gel(v,j);
    1887             :   }
    1888      374895 :   for (j=1; j <= n; j++)
    1889      288058 :     (void) FlxX_renormalize(gel(V, j), l);
    1890       86837 :   return gc_GEN(av, V);
    1891             : }
    1892             : 
    1893             : GEN
    1894        4456 : ZXC_nv_mod_tree(GEN C, GEN xa, GEN T, long w)
    1895             : {
    1896        4456 :   pari_sp av = avma;
    1897        4456 :   long i, j, l = lg(C), n = lg(xa)-1;
    1898        4456 :   GEN V = cgetg(n+1, t_VEC);
    1899       18422 :   for (j = 1; j <= n; j++)
    1900       13966 :     gel(V, j) = cgetg(l, t_COL);
    1901       94471 :   for (i = 1; i < l; i++)
    1902             :   {
    1903       90016 :     GEN v = ZX_nv_mod_tree(to_ZX(gel(C, i), w), xa, T);
    1904      391747 :     for (j = 1; j <= n; j++)
    1905      301732 :       gmael(V, j, i) = gel(v,j);
    1906             :   }
    1907        4455 :   return gc_GEN(av, V);
    1908             : }
    1909             : 
    1910             : GEN
    1911         453 : ZXM_nv_mod_tree(GEN M, GEN xa, GEN T, long w)
    1912             : {
    1913         453 :   pari_sp av = avma;
    1914         453 :   long i, j, l = lg(M), n = lg(xa)-1;
    1915         453 :   GEN V = cgetg(n+1, t_VEC);
    1916        2163 :   for (j=1; j <= n; j++)
    1917        1710 :     gel(V, j) = cgetg(l, t_MAT);
    1918        4635 :   for (i=1; i < l; i++)
    1919             :   {
    1920        4182 :     GEN v = ZXC_nv_mod_tree(gel(M, i), xa, T, w);
    1921       16769 :     for (j=1; j <= n; j++)
    1922       12587 :       gmael(V, j, i) = gel(v,j);
    1923             :   }
    1924         453 :   return gc_GEN(av, V);
    1925             : }
    1926             : 
    1927             : GEN
    1928     1273567 : ZV_nv_mod_tree(GEN B, GEN A, GEN T)
    1929             : {
    1930             :   pari_sp av;
    1931     1273567 :   long i, j, l = lg(B), n = lg(A)-1;
    1932     1273567 :   GEN V = cgetg(n+1, t_VEC);
    1933     6531930 :   for (j=1; j <= n; j++) gel(V, j) = cgetg(l, t_VECSMALL);
    1934     1273430 :   av = avma;
    1935    42544789 :   for (i=1; i < l; i++)
    1936             :   {
    1937    41274387 :     GEN v = Z_ZV_mod_tree(gel(B, i), A, T);
    1938   219538103 :     for (j=1; j <= n; j++) mael(V, j, i) = v[j];
    1939    41244133 :     set_avma(av);
    1940             :   }
    1941     1270402 :   return V;
    1942             : }
    1943             : 
    1944             : static GEN
    1945      242161 : ZM_nv_mod_tree_t(GEN M, GEN xa, GEN T, long t)
    1946             : {
    1947      242161 :   pari_sp av = avma;
    1948      242161 :   long i, j, l = lg(M), n = lg(xa)-1;
    1949      242161 :   GEN V = cgetg(n+1, t_VEC);
    1950     1324543 :   for (j=1; j <= n; j++) gel(V, j) = cgetg(l, t);
    1951     1515470 :   for (i=1; i < l; i++)
    1952             :   {
    1953     1273337 :     GEN v = ZV_nv_mod_tree(gel(M, i), xa, T);
    1954     6531306 :     for (j=1; j <= n; j++) gmael(V, j, i) = gel(v,j);
    1955             :   }
    1956      242133 :   return gc_GEN(av, V);
    1957             : }
    1958             : 
    1959             : GEN
    1960      236701 : ZM_nv_mod_tree(GEN M, GEN xa, GEN T)
    1961      236701 : { return ZM_nv_mod_tree_t(M, xa, T, t_MAT); }
    1962             : 
    1963             : GEN
    1964        5457 : ZVV_nv_mod_tree(GEN M, GEN xa, GEN T)
    1965        5457 : { return ZM_nv_mod_tree_t(M, xa, T, t_VEC); }
    1966             : 
    1967             : static GEN
    1968     2599776 : ZV_sqr(GEN z)
    1969             : {
    1970     2599776 :   long i,l = lg(z);
    1971     2599776 :   GEN x = cgetg(l, t_VEC);
    1972     2599771 :   if (typ(z)==t_VECSMALL)
    1973     6172905 :     for (i=1; i<l; i++) gel(x,i) = sqru(z[i]);
    1974             :   else
    1975     4643026 :     for (i=1; i<l; i++) gel(x,i) = sqri(gel(z,i));
    1976     2599744 :   return x;
    1977             : }
    1978             : 
    1979             : static GEN
    1980    13440983 : ZT_sqr(GEN x)
    1981             : {
    1982    13440983 :   if (typ(x) == t_INT) return sqri(x);
    1983    17584129 :   pari_APPLY_type(t_VEC, ZT_sqr(gel(x,i)))
    1984             : }
    1985             : 
    1986             : static GEN
    1987     2599753 : ZV_invdivexact(GEN y, GEN x)
    1988             : {
    1989     2599753 :   long i, l = lg(y);
    1990     2599753 :   GEN z = cgetg(l,t_VEC);
    1991     2599738 :   if (typ(x)==t_VECSMALL)
    1992     6172341 :     for (i=1; i<l; i++)
    1993             :     {
    1994     4937444 :       pari_sp av = avma;
    1995     4937444 :       ulong a = Fl_inv(umodiu(diviuexact(gel(y,i),x[i]), x[i]), x[i]);
    1996     4938020 :       set_avma(av); gel(z,i) = utoi(a);
    1997             :     }
    1998             :   else
    1999     4643064 :     for (i=1; i<l; i++)
    2000     3278224 :       gel(z,i) = Fp_inv(diviiexact(gel(y,i), gel(x,i)), gel(x,i));
    2001     2599737 :   return z;
    2002             : }
    2003             : 
    2004             : /* P t_VECSMALL or t_VEC of t_INT  */
    2005             : GEN
    2006     2599757 : ZV_chinesetree(GEN P, GEN T)
    2007             : {
    2008     2599757 :   GEN T2 = ZT_sqr(T), P2 = ZV_sqr(P);
    2009     2599758 :   GEN mod = gmael(T,lg(T)-1,1);
    2010     2599758 :   return ZV_invdivexact(Z_ZV_mod_tree(mod, P2, T2), P);
    2011             : }
    2012             : 
    2013             : static GEN
    2014     1015411 : gc_chinese(pari_sp av, GEN T, GEN a, GEN *pt_mod)
    2015             : {
    2016     1015411 :   if (!pt_mod)
    2017       12293 :     return gc_upto(av, a);
    2018             :   else
    2019             :   {
    2020     1003118 :     GEN mod = gmael(T, lg(T)-1, 1);
    2021     1003118 :     (void)gc_all(av, 2, &a, &mod);
    2022     1003119 :     *pt_mod = mod;
    2023     1003119 :     return a;
    2024             :   }
    2025             : }
    2026             : 
    2027             : GEN
    2028      157230 : ZV_chinese_center(GEN A, GEN P, GEN *pt_mod)
    2029             : {
    2030      157230 :   pari_sp av = avma;
    2031      157230 :   GEN T = ZV_producttree(P);
    2032      157230 :   GEN R = ZV_chinesetree(P, T);
    2033      157230 :   GEN a = ZV_chinese_tree(A, P, T, R);
    2034      157230 :   GEN mod = gmael(T, lg(T)-1, 1);
    2035      157230 :   GEN ca = Fp_center(a, mod, shifti(mod,-1));
    2036      157230 :   return gc_chinese(av, T, ca, pt_mod);
    2037             : }
    2038             : 
    2039             : GEN
    2040        5141 : ZV_chinese(GEN A, GEN P, GEN *pt_mod)
    2041             : {
    2042        5141 :   pari_sp av = avma;
    2043        5141 :   GEN T = ZV_producttree(P);
    2044        5141 :   GEN R = ZV_chinesetree(P, T);
    2045        5141 :   GEN a = ZV_chinese_tree(A, P, T, R);
    2046        5141 :   return gc_chinese(av, T, a, pt_mod);
    2047             : }
    2048             : 
    2049             : GEN
    2050      220065 : nxV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)
    2051             : {
    2052      220065 :   pari_sp av = avma;
    2053      220065 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2054      220060 :   GEN a = nxV_polint_center_tree(A, P, T, R, m2);
    2055      220067 :   return gc_upto(av, a);
    2056             : }
    2057             : 
    2058             : GEN
    2059      421948 : nxV_chinese_center(GEN A, GEN P, GEN *pt_mod)
    2060             : {
    2061      421948 :   pari_sp av = avma;
    2062      421948 :   GEN T = ZV_producttree(P);
    2063      421948 :   GEN R = ZV_chinesetree(P, T);
    2064      421948 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2065      421948 :   GEN a = nxV_polint_center_tree(A, P, T, R, m2);
    2066      421948 :   return gc_chinese(av, T, a, pt_mod);
    2067             : }
    2068             : 
    2069             : GEN
    2070       10200 : ncV_chinese_center(GEN A, GEN P, GEN *pt_mod)
    2071             : {
    2072       10200 :   pari_sp av = avma;
    2073       10200 :   GEN T = ZV_producttree(P);
    2074       10200 :   GEN R = ZV_chinesetree(P, T);
    2075       10200 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2076       10200 :   GEN a = ncV_polint_center_tree(A, P, T, R, m2);
    2077       10200 :   return gc_chinese(av, T, a, pt_mod);
    2078             : }
    2079             : 
    2080             : GEN
    2081        5457 : ncV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)
    2082             : {
    2083        5457 :   pari_sp av = avma;
    2084        5457 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2085        5457 :   GEN a = ncV_polint_center_tree(A, P, T, R, m2);
    2086        5457 :   return gc_upto(av, a);
    2087             : }
    2088             : 
    2089             : GEN
    2090           0 : nmV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)
    2091             : {
    2092           0 :   pari_sp av = avma;
    2093           0 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2094           0 :   GEN a = nmV_polint_center_tree(A, P, T, R, m2);
    2095           0 :   return gc_upto(av, a);
    2096             : }
    2097             : 
    2098             : GEN
    2099      142018 : nmV_chinese_center_tree_seq(GEN A, GEN P, GEN T, GEN R)
    2100             : {
    2101      142018 :   pari_sp av = avma;
    2102      142018 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2103      142014 :   GEN a = nmV_polint_center_tree_seq(A, P, T, R, m2);
    2104      142009 :   return gc_upto(av, a);
    2105             : }
    2106             : 
    2107             : GEN
    2108      420796 : nmV_chinese_center(GEN A, GEN P, GEN *pt_mod)
    2109             : {
    2110      420796 :   pari_sp av = avma;
    2111      420796 :   GEN T = ZV_producttree(P);
    2112      420796 :   GEN R = ZV_chinesetree(P, T);
    2113      420796 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2114      420796 :   GEN a = nmV_polint_center_tree(A, P, T, R, m2);
    2115      420796 :   return gc_chinese(av, T, a, pt_mod);
    2116             : }
    2117             : 
    2118             : GEN
    2119           0 : nxCV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)
    2120             : {
    2121           0 :   pari_sp av = avma;
    2122           0 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2123           0 :   GEN a = nxCV_polint_center_tree(A, P, T, R, m2);
    2124           0 :   return gc_upto(av, a);
    2125             : }
    2126             : 
    2127             : GEN
    2128           0 : nxCV_chinese_center(GEN A, GEN P, GEN *pt_mod)
    2129             : {
    2130           0 :   pari_sp av = avma;
    2131           0 :   GEN T = ZV_producttree(P);
    2132           0 :   GEN R = ZV_chinesetree(P, T);
    2133           0 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2134           0 :   GEN a = nxCV_polint_center_tree(A, P, T, R, m2);
    2135           0 :   return gc_chinese(av, T, a, pt_mod);
    2136             : }
    2137             : 
    2138             : GEN
    2139         453 : nxMV_chinese_center_tree_seq(GEN A, GEN P, GEN T, GEN R)
    2140             : {
    2141         453 :   pari_sp av = avma;
    2142         453 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2143         453 :   GEN a = nxMV_polint_center_tree_seq(A, P, T, R, m2);
    2144         453 :   return gc_upto(av, a);
    2145             : }
    2146             : 
    2147             : GEN
    2148          97 : nxMV_chinese_center(GEN A, GEN P, GEN *pt_mod)
    2149             : {
    2150          97 :   pari_sp av = avma;
    2151          97 :   GEN T = ZV_producttree(P);
    2152          97 :   GEN R = ZV_chinesetree(P, T);
    2153          97 :   GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
    2154          97 :   GEN a = nxMV_polint_center_tree(A, P, T, R, m2);
    2155          97 :   return gc_chinese(av, T, a, pt_mod);
    2156             : }
    2157             : 
    2158             : /**********************************************************************
    2159             :  **                    Powering  over (Z/NZ)^*, small N              **
    2160             :  **********************************************************************/
    2161             : 
    2162             : /* 2^n mod p; assume n > 1 */
    2163             : static ulong
    2164    12384426 : Fl_2powu_pre(ulong n, ulong p, ulong pi)
    2165             : {
    2166    12384426 :   ulong y = 2;
    2167    12384426 :   int j = 1+bfffo(n);
    2168             :   /* normalize, i.e set highest bit to 1 (we know n != 0) */
    2169    12384426 :   n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */
    2170   564081355 :   for (; j; n<<=1,j--)
    2171             :   {
    2172   551755397 :     y = Fl_sqr_pre(y,p,pi);
    2173   551256121 :     if (n & HIGHBIT) y = Fl_double(y, p);
    2174             :   }
    2175    12325958 :   return y;
    2176             : }
    2177             : 
    2178             : /* 2^n mod p; assume n > 1 and !(p & HIGHMASK) */
    2179             : static ulong
    2180     4288031 : Fl_2powu(ulong n, ulong p)
    2181             : {
    2182     4288031 :   ulong y = 2;
    2183     4288031 :   int j = 1+bfffo(n);
    2184             :   /* normalize, i.e set highest bit to 1 (we know n != 0) */
    2185     4288031 :   n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */
    2186    25400209 :   for (; j; n<<=1,j--)
    2187             :   {
    2188    21112141 :     y = (y*y) % p;
    2189    21112141 :     if (n & HIGHBIT) y = Fl_double(y, p);
    2190             :   }
    2191     4288068 :   return y;
    2192             : }
    2193             : 
    2194             : /* allow pi = 0 */
    2195             : ulong
    2196   151955777 : Fl_powu_pre(ulong x, ulong n0, ulong p, ulong pi)
    2197             : {
    2198             :   ulong y, z, n;
    2199   151955777 :   if (!pi) return Fl_powu(x, n0, p);
    2200   149510519 :   if (n0 <= 1)
    2201             :   { /* frequent special cases */
    2202    10089493 :     if (n0 == 1) return x;
    2203      105614 :     if (n0 == 0) return 1;
    2204             :   }
    2205   139421023 :   if (x <= 2)
    2206             :   {
    2207    12652203 :     if (x == 2) return Fl_2powu_pre(n0, p, pi);
    2208      264382 :     return x; /* 0 or 1 */
    2209             :   }
    2210   126768820 :   y = 1; z = x; n = n0;
    2211             :   for(;;)
    2212             :   {
    2213   652398395 :     if (n&1) y = Fl_mul_pre(y,z,p,pi);
    2214   653209737 :     n>>=1; if (!n) return y;
    2215   526268930 :     z = Fl_sqr_pre(z,p,pi);
    2216             :   }
    2217             : }
    2218             : 
    2219             : ulong
    2220   140623386 : Fl_powu(ulong x, ulong n0, ulong p)
    2221             : {
    2222             :   ulong y, z, n;
    2223   140623386 :   if (n0 <= 2)
    2224             :   { /* frequent special cases */
    2225    66143185 :     if (n0 == 2) return Fl_sqr(x,p);
    2226    32504798 :     if (n0 == 1) return x;
    2227     1982680 :     if (n0 == 0) return 1;
    2228             :   }
    2229    74462000 :   if (x <= 1) return x; /* 0 or 1 */
    2230    74021853 :   if (p & HIGHMASK)
    2231     7904011 :     return Fl_powu_pre(x, n0, p, get_Fl_red(p));
    2232    66117842 :   if (x == 2) return Fl_2powu(n0, p);
    2233    61829809 :   y = 1; z = x; n = n0;
    2234             :   for(;;)
    2235             :   {
    2236   263844422 :     if (n&1) y = (y*z) % p;
    2237   263844422 :     n>>=1; if (!n) return y;
    2238   202014613 :     z = (z*z) % p;
    2239             :   }
    2240             : }
    2241             : 
    2242             : /* Reduce data dependency to maximize internal parallelism; allow pi = 0 */
    2243             : GEN
    2244    12813862 : Fl_powers_pre(ulong x, long n, ulong p, ulong pi)
    2245             : {
    2246             :   long i, k;
    2247    12813862 :   GEN z = cgetg(n + 2, t_VECSMALL);
    2248    12812527 :   z[1] = 1; if (n == 0) return z;
    2249    12812527 :   z[2] = x;
    2250    12812527 :   if (pi)
    2251             :   {
    2252    90289841 :     for (i = 3, k=2; i <= n; i+=2, k++)
    2253             :     {
    2254    77683314 :       z[i] = Fl_sqr_pre(z[k], p, pi);
    2255    77688974 :       z[i+1] = Fl_mul_pre(z[k], z[k+1], p, pi);
    2256             :     }
    2257    12606527 :     if (i==n+1) z[i] = Fl_sqr_pre(z[k], p, pi);
    2258             :   }
    2259      212709 :   else if (p & HIGHMASK)
    2260             :   {
    2261           0 :     for (i = 3, k=2; i <= n; i+=2, k++)
    2262             :     {
    2263           0 :       z[i] = Fl_sqr(z[k], p);
    2264           0 :       z[i+1] = Fl_mul(z[k], z[k+1], p);
    2265             :     }
    2266           0 :     if (i==n+1) z[i] = Fl_sqr(z[k], p);
    2267             :   }
    2268             :   else
    2269   400536257 :     for (i = 2; i <= n; i++) z[i+1] = (z[i] * x) % p;
    2270    12820715 :   return z;
    2271             : }
    2272             : 
    2273             : GEN
    2274      296050 : Fl_powers(ulong x, long n, ulong p)
    2275             : {
    2276      296050 :   return Fl_powers_pre(x, n, p, (p & HIGHMASK)? get_Fl_red(p): 0);
    2277             : }
    2278             : 
    2279             : /**********************************************************************
    2280             :  **                    Powering  over (Z/NZ)^*, large N              **
    2281             :  **********************************************************************/
    2282             : typedef struct muldata {
    2283             :   GEN (*sqr)(void * E, GEN x);
    2284             :   GEN (*mul)(void * E, GEN x, GEN y);
    2285             :   GEN (*mul2)(void * E, GEN x);
    2286             : } muldata;
    2287             : 
    2288             : /* modified Barrett reduction with one fold */
    2289             : /* See Fast Modular Reduction, W. Hasenplaugh, G. Gaubatz, V. Gopal, ARITH 18 */
    2290             : 
    2291             : static GEN
    2292       14069 : Fp_invmBarrett(GEN p, long s)
    2293             : {
    2294       14069 :   GEN R, Q = dvmdii(int2n(3*s),p,&R);
    2295       14069 :   return mkvec2(Q,R);
    2296             : }
    2297             : 
    2298             : /* a <= (N-1)^2, 2^(2s-2) <= N < 2^(2s). Return 0 <= r < N such that
    2299             :  * a = r (mod N) */
    2300             : static GEN
    2301     8459526 : Fp_rem_mBarrett(GEN a, GEN B, long s, GEN N)
    2302             : {
    2303     8459526 :   pari_sp av = avma;
    2304     8459526 :   GEN P = gel(B, 1), Q = gel(B, 2); /* 2^(3s) = P N + Q, 0 <= Q < N */
    2305     8459526 :   long t = expi(P)+1; /* 2^(t-1) <= P < 2^t */
    2306     8459526 :   GEN u = shifti(a, -3*s), v = remi2n(a, 3*s); /* a = 2^(3s)u + v */
    2307     8459526 :   GEN A = addii(v, mulii(Q,u)); /* 0 <= A < 2^(3s+1) */
    2308     8459526 :   GEN q = shifti(mulii(shifti(A, t-3*s), P), -t); /* A/N - 4 < q <= A/N */
    2309     8459526 :   GEN r = subii(A, mulii(q, N));
    2310     8459526 :   GEN sr= subii(r,N);     /* 0 <= r < 4*N */
    2311     8459526 :   if (signe(sr)<0) return gc_INT(av, r);
    2312     4567614 :   r=sr; sr = subii(r,N);  /* 0 <= r < 3*N */
    2313     4567614 :   if (signe(sr)<0) return gc_INT(av, r);
    2314      157455 :   r=sr; sr = subii(r,N);  /* 0 <= r < 2*N */
    2315      157455 :   return gc_INT(av, signe(sr)>=0 ? sr:r);
    2316             : }
    2317             : 
    2318             : /* Montgomery reduction */
    2319             : 
    2320             : INLINE ulong
    2321      661022 : init_montdata(GEN N) { return (ulong) -invmod2BIL(mod2BIL(N)); }
    2322             : 
    2323             : struct montred
    2324             : {
    2325             :   GEN N;
    2326             :   ulong inv;
    2327             : };
    2328             : 
    2329             : /* Montgomery reduction */
    2330             : static GEN
    2331    63078157 : _sqr_montred(void * E, GEN x)
    2332             : {
    2333    63078157 :   struct montred * D = (struct montred *) E;
    2334    63078157 :   return red_montgomery(sqri(x), D->N, D->inv);
    2335             : }
    2336             : 
    2337             : /* Montgomery reduction */
    2338             : static GEN
    2339     6608380 : _mul_montred(void * E, GEN x, GEN y)
    2340             : {
    2341     6608380 :   struct montred * D = (struct montred *) E;
    2342     6608380 :   return red_montgomery(mulii(x, y), D->N, D->inv);
    2343             : }
    2344             : 
    2345             : static GEN
    2346     9448551 : _mul2_montred(void * E, GEN x)
    2347             : {
    2348     9448551 :   struct montred * D = (struct montred *) E;
    2349     9448551 :   GEN z = shifti(_sqr_montred(E, x), 1);
    2350     9446538 :   long l = lgefint(D->N);
    2351     9958631 :   while (lgefint(z) > l) z = subii(z, D->N);
    2352     9446711 :   return z;
    2353             : }
    2354             : 
    2355             : static GEN
    2356    24816103 : _sqr_remii(void* N, GEN x)
    2357    24816103 : { return remii(sqri(x), (GEN) N); }
    2358             : 
    2359             : static GEN
    2360     1633959 : _mul_remii(void* N, GEN x, GEN y)
    2361     1633959 : { return remii(mulii(x, y), (GEN) N); }
    2362             : 
    2363             : static GEN
    2364     3771600 : _mul2_remii(void* N, GEN x)
    2365     3771600 : { return Fp_double(_sqr_remii(N, x), (GEN)N); }
    2366             : 
    2367             : struct redbarrett
    2368             : {
    2369             :   GEN iM, N;
    2370             :   long s;
    2371             : };
    2372             : 
    2373             : static GEN
    2374     7728047 : _sqr_remiibar(void *E, GEN x)
    2375             : {
    2376     7728047 :   struct redbarrett * D = (struct redbarrett *) E;
    2377     7728047 :   return Fp_rem_mBarrett(sqri(x), D->iM, D->s, D->N);
    2378             : }
    2379             : 
    2380             : static GEN
    2381      731479 : _mul_remiibar(void *E, GEN x, GEN y)
    2382             : {
    2383      731479 :   struct redbarrett * D = (struct redbarrett *) E;
    2384      731479 :   return Fp_rem_mBarrett(mulii(x, y), D->iM, D->s, D->N);
    2385             : }
    2386             : 
    2387             : static GEN
    2388     1835592 : _mul2_remiibar(void *E, GEN x)
    2389             : {
    2390     1835592 :   struct redbarrett * D = (struct redbarrett *) E;
    2391     1835592 :   return Fp_double(_sqr_remiibar(E, x), D->N);
    2392             : }
    2393             : 
    2394             : static long
    2395      870059 : Fp_select_red(GEN *y, ulong k, GEN N, long lN, muldata *D, void **pt_E)
    2396             : {
    2397      870059 :   if (lN >= Fp_POW_BARRETT_LIMIT && (k==0 || ((double)k)*expi(*y) > 2 + expi(N)))
    2398             :   {
    2399       14069 :     struct redbarrett * E = (struct redbarrett *) stack_malloc(sizeof(struct redbarrett));
    2400       14069 :     D->sqr = &_sqr_remiibar;
    2401       14069 :     D->mul = &_mul_remiibar;
    2402       14069 :     D->mul2 = &_mul2_remiibar;
    2403       14069 :     E->N = N;
    2404       14069 :     E->s = 1+(expi(N)>>1);
    2405       14069 :     E->iM = Fp_invmBarrett(N, E->s);
    2406       14069 :     *pt_E = (void*) E;
    2407       14069 :     return 0;
    2408             :   }
    2409      855990 :   else if (mod2(N) && lN < Fp_POW_REDC_LIMIT)
    2410             :   {
    2411      660999 :     struct montred * E = (struct montred *) stack_malloc(sizeof(struct montred));
    2412      661006 :     *y = remii(shifti(*y, bit_accuracy(lN)), N);
    2413      661023 :     D->sqr = &_sqr_montred;
    2414      661023 :     D->mul = &_mul_montred;
    2415      661023 :     D->mul2 = &_mul2_montred;
    2416      661023 :     E->N = N;
    2417      661023 :     E->inv = init_montdata(N);
    2418      661017 :     *pt_E = (void*) E;
    2419      661017 :     return 1;
    2420             :   }
    2421             :   else
    2422             :   {
    2423      194991 :     D->sqr = &_sqr_remii;
    2424      194991 :     D->mul = &_mul_remii;
    2425      194991 :     D->mul2 = &_mul2_remii;
    2426      194991 :     *pt_E = (void*) N;
    2427      194991 :     return 0;
    2428             :   }
    2429             : }
    2430             : 
    2431             : GEN
    2432     1752623 : Fp_powu(GEN A, ulong k, GEN N)
    2433             : {
    2434     1752623 :   long lN = lgefint(N);
    2435             :   int base_is_2, use_montgomery;
    2436             :   muldata D;
    2437             :   void *E;
    2438             :   pari_sp av;
    2439             : 
    2440     1752623 :   if (lN == 3) {
    2441      309843 :     ulong n = uel(N,2);
    2442      309843 :     return utoi( Fl_powu(umodiu(A, n), k, n) );
    2443             :   }
    2444     1442780 :   if (k <= 2)
    2445             :   { /* frequent special cases */
    2446      844491 :     if (k == 2) return Fp_sqr(A,N);
    2447      293807 :     if (k == 1) return A;
    2448           0 :     if (k == 0) return gen_1;
    2449             :   }
    2450      598289 :   av = avma; A = modii(A,N);
    2451      598289 :   base_is_2 = 0;
    2452      598289 :   if (lgefint(A) == 3) switch(A[2])
    2453             :   {
    2454        1055 :     case 1: set_avma(av); return gen_1;
    2455       34225 :     case 2:  base_is_2 = 1; break;
    2456             :   }
    2457             : 
    2458             :   /* TODO: Move this out of here and use for general modular computations */
    2459      597234 :   use_montgomery = Fp_select_red(&A, k, N, lN, &D, &E);
    2460      597234 :   if (base_is_2)
    2461       34225 :     A = gen_powu_fold_i(A, k, E, D.sqr, D.mul2);
    2462             :   else
    2463      563009 :     A = gen_powu_i(A, k, E, D.sqr, D.mul);
    2464      597234 :   if (use_montgomery)
    2465             :   {
    2466      499152 :     A = red_montgomery(A, N, ((struct montred *) E)->inv);
    2467      499152 :     if (cmpii(A, N) >= 0) A = subii(A,N);
    2468             :   }
    2469      597234 :   return gc_INT(av, A);
    2470             : }
    2471             : 
    2472             : GEN
    2473     1346207 : Fp_pows(GEN A, long k, GEN N)
    2474             : {
    2475     1346207 :   if (lgefint(N) == 3) {
    2476     1322330 :     ulong n = N[2];
    2477     1322330 :     ulong a = umodiu(A, n);
    2478     1322330 :     if (k < 0) {
    2479       58634 :       a = Fl_inv(a, n);
    2480       58634 :       k = -k;
    2481             :     }
    2482     1322330 :     return utoi( Fl_powu(a, (ulong)k, n) );
    2483             :   }
    2484       23877 :   if (k < 0) { A = Fp_inv(A, N); k = -k; };
    2485       23877 :   return Fp_powu(A, (ulong)k, N);
    2486             : }
    2487             : 
    2488             : /* A^K mod N */
    2489             : GEN
    2490    36219353 : Fp_pow(GEN A, GEN K, GEN N)
    2491             : {
    2492             :   pari_sp av;
    2493    36219353 :   long s, lN = lgefint(N), sA, sy;
    2494             :   int base_is_2, use_montgomery;
    2495             :   GEN y;
    2496             :   muldata D;
    2497             :   void *E;
    2498             : 
    2499    36219353 :   s = signe(K);
    2500    36219353 :   if (!s) return dvdii(A,N)? gen_0: gen_1;
    2501    35188292 :   if (lN == 3 && lgefint(K) == 3)
    2502             :   {
    2503    34468118 :     ulong n = N[2], a = umodiu(A, n);
    2504    34468240 :     if (s < 0) a = Fl_inv(a, n);
    2505    34468316 :     if (a <= 1) return utoi(a); /* 0 or 1 */
    2506    30933429 :     return utoi(Fl_powu(a, uel(K,2), n));
    2507             :   }
    2508             : 
    2509      720174 :   av = avma;
    2510      720174 :   if (s < 0) y = Fp_inv(A,N);
    2511             :   else
    2512             :   {
    2513      718241 :     y = modii(A,N);
    2514      718351 :     if (!signe(y)) { set_avma(av); return gen_0; }
    2515             :   }
    2516      720296 :   if (lgefint(K) == 3) return gc_INT(av, Fp_powu(y, K[2], N));
    2517             : 
    2518      273049 :   base_is_2 = 0;
    2519      273049 :   sy = abscmpii(y, shifti(N,-1)) > 0;
    2520      273031 :   if (sy) y = subii(N,y);
    2521      273033 :   sA = sy && mod2(K);
    2522      273033 :   if (lgefint(y) == 3) switch(y[2])
    2523             :   {
    2524         220 :     case 1:  set_avma(av); return sA ? subis(N,1): gen_1;
    2525      152575 :     case 2:  base_is_2 = 1; break;
    2526             :   }
    2527             : 
    2528             :   /* TODO: Move this out of here and use for general modular computations */
    2529      272813 :   use_montgomery = Fp_select_red(&y, 0UL, N, lN, &D, &E);
    2530      272889 :   if (base_is_2)
    2531      152647 :     y = gen_pow_fold_i(y, K, E, D.sqr, D.mul2);
    2532             :   else
    2533      120242 :     y = gen_pow_i(y, K, E, D.sqr, D.mul);
    2534      272968 :   if (use_montgomery)
    2535             :   {
    2536      161894 :     y = red_montgomery(y, N, ((struct montred *) E)->inv);
    2537      161892 :     if (cmpii(y,N) >= 0) y = subii(y,N);
    2538             :   }
    2539      272966 :   if (sA) y = subii(N, y);
    2540      272966 :   return gc_INT(av,y);
    2541             : }
    2542             : 
    2543             : static GEN
    2544    14130063 : _Fp_mul(void *E, GEN x, GEN y) { return Fp_mul(x,y,(GEN)E); }
    2545             : static GEN
    2546     8134253 : _Fp_sqr(void *E, GEN x) { return Fp_sqr(x,(GEN)E); }
    2547             : static GEN
    2548       47162 : _Fp_one(void *E) { (void) E; return gen_1; }
    2549             : 
    2550             : GEN
    2551         105 : Fp_pow_init(GEN x, GEN n, long k, GEN p)
    2552         105 : { return gen_pow_init(x, n, k, (void*)p, &_Fp_sqr, &_Fp_mul); }
    2553             : 
    2554             : GEN
    2555       43694 : Fp_pow_table(GEN R, GEN n, GEN p)
    2556       43694 : { return gen_pow_table(R, n, (void*)p, &_Fp_one, &_Fp_mul); }
    2557             : 
    2558             : GEN
    2559        5931 : Fp_powers(GEN x, long n, GEN p)
    2560             : {
    2561        5931 :   if (lgefint(p) == 3)
    2562        2463 :     return Flv_to_ZV(Fl_powers(umodiu(x, uel(p, 2)), n, uel(p, 2)));
    2563        3468 :   return gen_powers(x, n, 1, (void*)p, _Fp_sqr, _Fp_mul, _Fp_one);
    2564             : }
    2565             : 
    2566             : GEN
    2567         497 : FpV_prod(GEN V, GEN p) { return gen_product(V, (void *)p, &_Fp_mul); }
    2568             : 
    2569             : static GEN
    2570    27873912 : _Fp_pow(void *E, GEN x, GEN n) { return Fp_pow(x,n,(GEN)E); }
    2571             : static GEN
    2572         160 : _Fp_rand(void *E) { return addiu(randomi(subiu((GEN)E,1)),1); }
    2573             : 
    2574             : static GEN Fp_easylog(void *E, GEN a, GEN g, GEN ord);
    2575             : static const struct bb_group Fp_star={_Fp_mul,_Fp_pow,_Fp_rand,hash_GEN,
    2576             :                                       equalii,equali1,Fp_easylog};
    2577             : 
    2578             : static GEN
    2579      889913 : _Fp_red(void *E, GEN x) { return Fp_red(x, (GEN)E); }
    2580             : static GEN
    2581     1175565 : _Fp_add(void *E, GEN x, GEN y) { (void) E; return addii(x,y); }
    2582             : static GEN
    2583     1086846 : _Fp_neg(void *E, GEN x) { (void) E; return negi(x); }
    2584             : static GEN
    2585      575346 : _Fp_rmul(void *E, GEN x, GEN y) { (void) E; return mulii(x,y); }
    2586             : static GEN
    2587       34307 : _Fp_inv(void *E, GEN x) { return Fp_inv(x,(GEN)E); }
    2588             : static int
    2589      260724 : _Fp_equal0(GEN x) { return signe(x)==0; }
    2590             : static GEN
    2591       19075 : _Fp_s(void *E, long x) { (void) E; return stoi(x); }
    2592             : 
    2593             : static const struct bb_field Fp_field={_Fp_red,_Fp_add,_Fp_rmul,_Fp_neg,
    2594             :                                         _Fp_inv,_Fp_equal0,_Fp_s};
    2595             : 
    2596        6963 : const struct bb_field *get_Fp_field(void **E, GEN p)
    2597        6963 : { *E = (void*)p; return &Fp_field; }
    2598             : 
    2599             : /*********************************************************************/
    2600             : /**               ORDER of INTEGERMOD x  in  (Z/nZ)*                **/
    2601             : /*********************************************************************/
    2602             : ulong
    2603      542733 : Fl_order(ulong a, ulong o, ulong p)
    2604             : {
    2605      542733 :   pari_sp av = avma;
    2606             :   GEN m, P, E;
    2607             :   long i;
    2608      542733 :   if (a==1) return 1;
    2609      445075 :   if (!o) o = p-1;
    2610      445075 :   m = factoru(o);
    2611      445075 :   P = gel(m,1);
    2612      445075 :   E = gel(m,2);
    2613     1265106 :   for (i = lg(P)-1; i; i--)
    2614             :   {
    2615      820031 :     ulong j, l = P[i], e = E[i], t = o / upowuu(l,e), y = Fl_powu(a, t, p);
    2616      820031 :     if (y == 1) o = t;
    2617      780413 :     else for (j = 1; j < e; j++)
    2618             :     {
    2619      386772 :       y = Fl_powu(y, l, p);
    2620      386772 :       if (y == 1) { o = t *  upowuu(l, j); break; }
    2621             :     }
    2622             :   }
    2623      445075 :   return gc_ulong(av, o);
    2624             : }
    2625             : 
    2626             : /*Find the exact order of a assuming a^o==1*/
    2627             : GEN
    2628      132160 : Fp_order(GEN a, GEN o, GEN p) {
    2629      132160 :   if (lgefint(p) == 3 && (!o || typ(o) == t_INT))
    2630             :   {
    2631       59266 :     ulong pp = p[2], oo = (o && lgefint(o)==3)? uel(o,2): pp-1;
    2632       59266 :     return utoi( Fl_order(umodiu(a, pp), oo, pp) );
    2633             :   }
    2634       72894 :   return gen_order(a, o, (void*)p, &Fp_star);
    2635             : }
    2636             : GEN
    2637          70 : Fp_factored_order(GEN a, GEN o, GEN p)
    2638          70 : { return gen_factored_order(a, o, (void*)p, &Fp_star); }
    2639             : 
    2640             : /* return order of a mod p^e, e > 0, pe = p^e */
    2641             : static GEN
    2642          70 : Zp_order(GEN a, GEN p, long e, GEN pe)
    2643             : {
    2644             :   GEN ap, op;
    2645          70 :   if (absequaliu(p, 2))
    2646             :   {
    2647          56 :     if (e == 1) return gen_1;
    2648          56 :     if (e == 2) return mod4(a) == 1? gen_1: gen_2;
    2649          49 :     if (mod4(a) == 1) op = gen_1; else { op = gen_2; a = Fp_sqr(a, pe); }
    2650             :   } else {
    2651          14 :     ap = (e == 1)? a: remii(a,p);
    2652          14 :     op = Fp_order(ap, subiu(p,1), p);
    2653          14 :     if (e == 1) return op;
    2654           0 :     a = Fp_pow(a, op, pe); /* 1 mod p */
    2655             :   }
    2656          49 :   if (equali1(a)) return op;
    2657           7 :   return mulii(op, powiu(p, e - Z_pval(subiu(a,1), p)));
    2658             : }
    2659             : 
    2660             : GEN
    2661          63 : znorder(GEN x, GEN o)
    2662             : {
    2663          63 :   pari_sp av = avma;
    2664             :   GEN b, a;
    2665             : 
    2666          63 :   if (typ(x) != t_INTMOD) pari_err_TYPE("znorder [t_INTMOD expected]",x);
    2667          56 :   b = gel(x,1); a = gel(x,2);
    2668          56 :   if (!equali1(gcdii(a,b))) pari_err_COPRIME("znorder", a,b);
    2669          49 :   if (!o)
    2670             :   {
    2671          35 :     GEN fa = Z_factor(b), P = gel(fa,1), E = gel(fa,2);
    2672          35 :     long i, l = lg(P);
    2673          35 :     o = gen_1;
    2674          70 :     for (i = 1; i < l; i++)
    2675             :     {
    2676          35 :       GEN p = gel(P,i);
    2677          35 :       long e = itos(gel(E,i));
    2678             : 
    2679          35 :       if (l == 2)
    2680          35 :         o = Zp_order(a, p, e, b);
    2681             :       else {
    2682           0 :         GEN pe = powiu(p,e);
    2683           0 :         o = lcmii(o, Zp_order(remii(a,pe), p, e, pe));
    2684             :       }
    2685             :     }
    2686          35 :     return gc_INT(av, o);
    2687             :   }
    2688          14 :   return Fp_order(a, o, b);
    2689             : }
    2690             : 
    2691             : /*********************************************************************/
    2692             : /**               DISCRETE LOGARITHM  in  (Z/nZ)*                   **/
    2693             : /*********************************************************************/
    2694             : static GEN
    2695       56551 : Fp_log_halfgcd(ulong bnd, GEN C, GEN g, GEN p)
    2696             : {
    2697       56551 :   pari_sp av = avma;
    2698             :   GEN h1, h2, F, G;
    2699       56551 :   if (!Fp_ratlift(g,p,C,shifti(C,-1),&h1,&h2)) return gc_NULL(av);
    2700       34005 :   if ((F = Z_issmooth_fact(h1, bnd)) && (G = Z_issmooth_fact(h2, bnd)))
    2701             :   {
    2702         126 :     GEN M = cgetg(3, t_MAT);
    2703         126 :     gel(M,1) = vecsmall_concat(gel(F, 1),gel(G, 1));
    2704         126 :     gel(M,2) = vecsmall_concat(gel(F, 2),zv_neg_inplace(gel(G, 2)));
    2705         126 :     return gc_upto(av, M);
    2706             :   }
    2707       33879 :   return gc_NULL(av);
    2708             : }
    2709             : 
    2710             : static GEN
    2711       56551 : Fp_log_find_rel(GEN b, ulong bnd, GEN C, GEN p, GEN *g, long *e)
    2712             : {
    2713             :   GEN rel;
    2714       56551 :   do { (*e)++; *g = Fp_mul(*g, b, p); rel = Fp_log_halfgcd(bnd, C, *g, p); }
    2715       56551 :   while (!rel);
    2716         126 :   return rel;
    2717             : }
    2718             : 
    2719             : struct Fp_log_rel
    2720             : {
    2721             :   GEN rel;
    2722             :   ulong prmax;
    2723             :   long nbrel, nbmax, nbgen;
    2724             : };
    2725             : 
    2726             : static long
    2727       59731 : tr(long i) { return odd(i) ? (i+1)>>1: -(i>>1); }
    2728             : 
    2729             : static long
    2730      169813 : rt(long i) { return i>0 ? 2*i-1: -2*i; }
    2731             : 
    2732             : /* add u^e */
    2733             : static void
    2734        2163 : addifsmooth1(struct Fp_log_rel *r, GEN z, long u, long e)
    2735             : {
    2736        2163 :   pari_sp av = avma;
    2737        2163 :   long off = r->prmax+1;
    2738        2163 :   GEN F = cgetg(3, t_MAT);
    2739        2163 :   gel(F,1) = vecsmall_append(gel(z,1), off+rt(u));
    2740        2163 :   gel(F,2) = vecsmall_append(gel(z,2), e);
    2741        2163 :   gel(r->rel,++r->nbrel) = gc_upto(av, F);
    2742        2163 : }
    2743             : 
    2744             : /* add u^-1 v^-1 */
    2745             : static void
    2746       83825 : addifsmooth2(struct Fp_log_rel *r, GEN z, long u, long v)
    2747             : {
    2748       83825 :   pari_sp av = avma;
    2749       83825 :   long off = r->prmax+1;
    2750       83825 :   GEN P = mkvecsmall2(off+rt(u),off+rt(v)), E = mkvecsmall2(-1,-1);
    2751       83825 :   GEN F = cgetg(3, t_MAT);
    2752       83825 :   gel(F,1) = vecsmall_concat(gel(z,1), P);
    2753       83825 :   gel(F,2) = vecsmall_concat(gel(z,2), E);
    2754       83825 :   gel(r->rel,++r->nbrel) = gc_upto(av, F);
    2755       83825 : }
    2756             : 
    2757             : /* Let p=C^2+c
    2758             :  * Solve h = (C+x)*(C+a)-p = 0 [mod l]
    2759             :  * h= -c+x*(C+a)+C*a = 0  [mod l]
    2760             :  * x = (c-C*a)/(C+a) [mod l]
    2761             :  * h = -c+C*(x+a)+a*x */
    2762             : GEN
    2763       30245 : Fp_log_sieve_worker(long a, long prmax, GEN C, GEN c, GEN Ci, GEN ci, GEN pi, GEN sz)
    2764             : {
    2765       30245 :   pari_sp ltop = avma;
    2766       30245 :   long i, j, th, n = lg(pi)-1, rel = 1, ab = labs(a), ae;
    2767       30245 :   GEN sieve = zero_zv(2*ab+2)+1+ab;
    2768       30258 :   GEN L = cgetg(1+2*ab+2, t_VEC);
    2769       30251 :   pari_sp av = avma;
    2770       30251 :   GEN z, h = addis(C,a);
    2771       30250 :   if ((z = Z_issmooth_fact(h, prmax)))
    2772             :   {
    2773        2169 :     gel(L, rel++) = mkvec2(z, mkvecsmall3(1, a, -1));
    2774        2169 :     av = avma;
    2775             :   }
    2776    12893039 :   for (i=1; i<=n; i++)
    2777             :   {
    2778    12868222 :     ulong li = pi[i], s = sz[i], al = smodss(a,li);
    2779    12842002 :     ulong iv = Fl_invsafe(Fl_add(Ci[i],al,li),li);
    2780             :     long u;
    2781    13123586 :     if (!iv) continue;
    2782    12807357 :     u = Fl_add(Fl_mul(Fl_sub(ci[i],Fl_mul(Ci[i],al,li),li), iv ,li),ab%li,li)-ab;
    2783    47678200 :     for(j = u; j<=ab; j+=li) sieve[j] += s;
    2784             :   }
    2785       25938 :   if (a)
    2786             :   {
    2787       30173 :     long e = expi(mulis(C,a));
    2788       30180 :     th = e - expu(e) - 1;
    2789          54 :   } else th = -1;
    2790       30251 :   ae = a>=0 ? ab-1: ab;
    2791    15525385 :   for (j = 1-ab; j <= ae; j++)
    2792    15495312 :     if (sieve[j]>=th)
    2793             :     {
    2794      108965 :       GEN h = absi(addis(subii(mulis(C,a+j),c), a*j));
    2795      108848 :       if ((z = Z_issmooth_fact(h, prmax)))
    2796             :       {
    2797      106622 :         gel(L, rel++) = mkvec2(z, mkvecsmall3(2, a, j));
    2798      106624 :         av = avma;
    2799        2295 :       } else set_avma(av);
    2800             :     }
    2801             :   /* j = a */
    2802       30073 :   if (sieve[a]>=th)
    2803             :   {
    2804         448 :     GEN h = absi(addiu(subii(mulis(C,2*a),c), a*a));
    2805         448 :     if ((z = Z_issmooth_fact(h, prmax)))
    2806         364 :       gel(L, rel++) = mkvec2(z, mkvecsmall3(1, a, -2));
    2807             :   }
    2808       30073 :   setlg(L, rel); return gc_GEN(ltop, L);
    2809             : }
    2810             : 
    2811             : static long
    2812          63 : Fp_log_sieve(struct Fp_log_rel *r, GEN C, GEN c, GEN Ci, GEN ci, GEN pi, GEN sz)
    2813             : {
    2814             :   struct pari_mt pt;
    2815          63 :   long i, j, nb = 0;
    2816          63 :   GEN worker = snm_closure(is_entry("_Fp_log_sieve_worker"),
    2817             :                mkvecn(7, utoi(r->prmax), C, c, Ci, ci, pi, sz));
    2818          63 :   long running, pending = 0;
    2819          63 :   GEN W = zerovec(r->nbgen);
    2820          63 :   mt_queue_start_lim(&pt, worker, r->nbgen);
    2821       30459 :   for (i = 0; (running = (i < r->nbgen)) || pending; i++)
    2822             :   {
    2823             :     GEN done;
    2824             :     long idx;
    2825       30396 :     mt_queue_submit(&pt, i, running ? mkvec(stoi(tr(i))): NULL);
    2826       30396 :     done = mt_queue_get(&pt, &idx, &pending);
    2827       30396 :     if (!done || lg(done)==1) continue;
    2828       27636 :     gel(W, idx+1) = done;
    2829       27636 :     nb += lg(done)-1;
    2830       27636 :     if (DEBUGLEVEL && (i&127)==0)
    2831           0 :       err_printf("%ld%% ",100*nb/r->nbmax);
    2832             :   }
    2833          63 :   mt_queue_end(&pt);
    2834       26362 :   for(j = 1; j <= r->nbgen && r->nbrel < r->nbmax; j++)
    2835             :   {
    2836             :     long ll, m;
    2837       26299 :     GEN L = gel(W,j);
    2838       26299 :     if (isintzero(L)) continue;
    2839       23681 :     ll = lg(L);
    2840      109669 :     for (m=1; m<ll && r->nbrel < r->nbmax ; m++)
    2841             :     {
    2842       85988 :       GEN Lm = gel(L,m), h = gel(Lm, 1), v = gel(Lm, 2);
    2843       85988 :       if (v[1] == 1)
    2844        2163 :         addifsmooth1(r, h, v[2], v[3]);
    2845             :       else
    2846       83825 :         addifsmooth2(r, h, v[2], v[3]);
    2847             :     }
    2848             :   }
    2849          63 :   return j;
    2850             : }
    2851             : 
    2852             : static GEN
    2853         837 : ECP_psi(GEN x, GEN y)
    2854             : {
    2855         837 :   long prec = realprec(x);
    2856         837 :   GEN lx = glog(x, prec), ly = glog(y, prec);
    2857         837 :   GEN u = gdiv(lx, ly);
    2858         837 :   return gpow(u, gneg(u),prec);
    2859             : }
    2860             : 
    2861             : struct computeG
    2862             : {
    2863             :   GEN C;
    2864             :   long bnd, nbi;
    2865             : };
    2866             : 
    2867             : static GEN
    2868         837 : _computeG(void *E, GEN gen)
    2869             : {
    2870         837 :   struct computeG * d = (struct computeG *) E;
    2871         837 :   GEN ps = ECP_psi(gmul(gen,d->C), stoi(d->bnd));
    2872         837 :   return gsub(gmul(gsqr(gen),ps),gmulgs(gaddgs(gen,d->nbi),3));
    2873             : }
    2874             : 
    2875             : static long
    2876          63 : compute_nbgen(GEN C, long bnd, long nbi)
    2877             : {
    2878             :   struct computeG d;
    2879          63 :   d.C = shifti(C, 1);
    2880          63 :   d.bnd = bnd;
    2881          63 :   d.nbi = nbi;
    2882          63 :   return itos(ground(zbrent((void*)&d, _computeG, gen_2, stoi(bnd), DEFAULTPREC)));
    2883             : }
    2884             : 
    2885             : static GEN
    2886        1714 : _psi(void*E, GEN y)
    2887             : {
    2888        1714 :   GEN lx = (GEN) E;
    2889        1714 :   long prec = realprec(lx);
    2890        1714 :   GEN ly = glog(y, prec);
    2891        1714 :   GEN u = gdiv(lx, ly);
    2892        1714 :   return gsub(gdiv(y ,ly), gpow(u, u, prec));
    2893             : }
    2894             : 
    2895             : static GEN
    2896          63 : opt_param(GEN x, long prec)
    2897             : {
    2898          63 :   return zbrent((void*)glog(x,prec), _psi, gen_2, x, prec);
    2899             : }
    2900             : 
    2901             : static GEN
    2902          63 : check_kernel(long nbg, long N, long prmax, GEN C, GEN M, GEN p, GEN m)
    2903             : {
    2904          63 :   pari_sp av = avma;
    2905          63 :   long lM = lg(M)-1, nbcol = lM;
    2906          63 :   long tbs = maxss(1, expu(nbg/expi(m)));
    2907             :   for (;;)
    2908          42 :   {
    2909         105 :     GEN K = FpMs_leftkernel_elt_col(M, nbcol, N, m);
    2910             :     GEN tab;
    2911         105 :     long i, f=0;
    2912         105 :     long l = lg(K), lm = lgefint(m);
    2913         105 :     GEN idx = diviiexact(subiu(p,1),m), g;
    2914             :     pari_timer ti;
    2915         105 :     if (DEBUGLEVEL) timer_start(&ti);
    2916         210 :     for(i=1; i<l; i++)
    2917         210 :       if (signe(gel(K,i)))
    2918         105 :         break;
    2919         105 :     g = Fp_pow(utoi(i), idx, p);
    2920         105 :     tab = Fp_pow_init(g, p, tbs, p);
    2921         105 :     K = FpC_Fp_mul(K, Fp_inv(gel(K,i), m), m);
    2922      121520 :     for(i=1; i<l; i++)
    2923             :     {
    2924      121415 :       GEN k = gel(K,i);
    2925      121415 :       GEN j = i<=prmax ? utoi(i): addis(C,tr(i-(prmax+1)));
    2926      121415 :       if (signe(k)==0 || !equalii(Fp_pow_table(tab, k, p), Fp_pow(j, idx, p)))
    2927       82369 :         gel(K,i) = cgetineg(lm);
    2928             :       else
    2929       39046 :         f++;
    2930             :     }
    2931         105 :     if (DEBUGLEVEL) timer_printf(&ti,"found %ld/%ld logs", f, nbg);
    2932         105 :     if(f > (nbg>>1)) return gc_upto(av, K);
    2933       10024 :     for(i=1; i<=nbcol; i++)
    2934             :     {
    2935        9982 :       long a = 1+random_Fl(lM);
    2936        9982 :       swap(gel(M,a),gel(M,i));
    2937             :     }
    2938          42 :     if (4*nbcol>5*nbg) nbcol = nbcol*9/10;
    2939             :   }
    2940             : }
    2941             : 
    2942             : static GEN
    2943         126 : Fp_log_find_ind(GEN a, GEN K, long prmax, GEN C, GEN p, GEN m)
    2944             : {
    2945         126 :   pari_sp av=avma;
    2946         126 :   GEN aa = gen_1;
    2947         126 :   long AV = 0;
    2948             :   for(;;)
    2949           0 :   {
    2950         126 :     GEN A = Fp_log_find_rel(a, prmax, C, p, &aa, &AV);
    2951         126 :     GEN F = gel(A,1), E = gel(A,2);
    2952         126 :     GEN Ao = gen_0;
    2953         126 :     long i, l = lg(F);
    2954         807 :     for(i=1; i<l; i++)
    2955             :     {
    2956         681 :       GEN Ki = gel(K,F[i]);
    2957         681 :       if (signe(Ki)<0) break;
    2958         681 :       Ao = addii(Ao, mulis(Ki, E[i]));
    2959             :     }
    2960         126 :     if (i==l) return Fp_divu(Ao, AV, m);
    2961           0 :     aa = gc_INT(av, aa);
    2962             :   }
    2963             : }
    2964             : 
    2965             : static GEN
    2966          63 : Fp_log_index(GEN a, GEN b, GEN m, GEN p)
    2967             : {
    2968          63 :   pari_sp av = avma, av2;
    2969          63 :   long i, j, nbi, nbr = 0, nbrow, nbg;
    2970             :   GEN C, c, Ci, ci, pi, pr, sz, l, Ao, Bo, K, d, p_1;
    2971             :   pari_timer ti;
    2972             :   struct Fp_log_rel r;
    2973          63 :   ulong bnds = itou(roundr_safe(opt_param(sqrti(p),DEFAULTPREC)));
    2974          63 :   ulong bnd = 4*bnds;
    2975          63 :   if (!bnds || cmpii(sqru(bnds),m)>=0) return NULL;
    2976             : 
    2977          63 :   p_1 = subiu(p,1);
    2978          63 :   if (!is_pm1(gcdii(m,diviiexact(p_1,m))))
    2979           0 :     m = diviiexact(p_1, Z_ppo(p_1, m));
    2980          63 :   pr = primes_upto_zv(bnd);
    2981          63 :   nbi = lg(pr)-1;
    2982          63 :   C = sqrtremi(p, &c);
    2983          63 :   av2 = avma;
    2984       12796 :   for (i = 1; i <= nbi; ++i)
    2985             :   {
    2986       12733 :     ulong lp = pr[i];
    2987       26894 :     while (lp <= bnd)
    2988             :     {
    2989       14161 :       nbr++;
    2990       14161 :       lp *= pr[i];
    2991             :     }
    2992             :   }
    2993          63 :   pi = cgetg(nbr+1,t_VECSMALL);
    2994          63 :   Ci = cgetg(nbr+1,t_VECSMALL);
    2995          63 :   ci = cgetg(nbr+1,t_VECSMALL);
    2996          63 :   sz = cgetg(nbr+1,t_VECSMALL);
    2997       12796 :   for (i = 1, j = 1; i <= nbi; ++i)
    2998             :   {
    2999       12733 :     ulong lp = pr[i], sp = expu(2*lp-1);
    3000       26894 :     while (lp <= bnd)
    3001             :     {
    3002       14161 :       pi[j] = lp;
    3003       14161 :       Ci[j] = umodiu(C, lp);
    3004       14161 :       ci[j] = umodiu(c, lp);
    3005       14161 :       sz[j] = sp;
    3006       14161 :       lp *= pr[i];
    3007       14161 :       j++;
    3008             :     }
    3009             :   }
    3010          63 :   r.nbrel = 0;
    3011          63 :   r.nbgen = compute_nbgen(C, bnd, nbi);
    3012          63 :   r.nbmax = 2*(nbi+r.nbgen);
    3013          63 :   r.rel = cgetg(r.nbmax+1,t_VEC);
    3014          63 :   r.prmax = pr[nbi];
    3015          63 :   if (DEBUGLEVEL)
    3016             :   {
    3017           0 :     err_printf("bnd=%lu Size FB=%ld extra gen=%ld \n", bnd, nbi, r.nbgen);
    3018           0 :     timer_start(&ti);
    3019             :   }
    3020          63 :   nbg = Fp_log_sieve(&r, C, c, Ci, ci, pi, sz);
    3021          63 :   nbrow = r.prmax + nbg;
    3022          63 :   if (DEBUGLEVEL)
    3023             :   {
    3024           0 :     err_printf("\n");
    3025           0 :     timer_printf(&ti," %ld relations, %ld generators", r.nbrel, nbi+nbg);
    3026             :   }
    3027          63 :   setlg(r.rel,r.nbrel+1);
    3028          63 :   r.rel = gc_GEN(av2, r.rel);
    3029          63 :   K = check_kernel(nbi+nbrow-r.prmax, nbrow, r.prmax, C, r.rel, p, m);
    3030          63 :   if (DEBUGLEVEL) timer_start(&ti);
    3031          63 :   Ao = Fp_log_find_ind(a, K, r.prmax, C, p, m);
    3032          63 :   if (DEBUGLEVEL) timer_printf(&ti," log element");
    3033          63 :   Bo = Fp_log_find_ind(b, K, r.prmax, C, p, m);
    3034          63 :   if (DEBUGLEVEL) timer_printf(&ti," log generator");
    3035          63 :   d = gcdii(Ao,Bo);
    3036          63 :   l = Fp_div(diviiexact(Ao, d) ,diviiexact(Bo, d), m);
    3037          63 :   if (!equalii(a,Fp_pow(b,l,p))) pari_err_BUG("Fp_log_index");
    3038          63 :   return gc_INT(av, l);
    3039             : }
    3040             : 
    3041             : static int
    3042     4666023 : Fp_log_use_index(long e, long p)
    3043             : {
    3044     4666023 :   return (e >= 27 && 20*(p+6)<=e*e);
    3045             : }
    3046             : 
    3047             : /* Trivial cases a = 1, -1. Return x s.t. g^x = a or [] if no such x exist */
    3048             : static GEN
    3049     8466744 : Fp_easylog(void *E, GEN a, GEN g, GEN ord)
    3050             : {
    3051     8466744 :   pari_sp av = avma;
    3052     8466744 :   GEN p = (GEN)E;
    3053             :   /* assume a reduced mod p, p not necessarily prime */
    3054     8466744 :   if (equali1(a)) return gen_0;
    3055             :   /* p > 2 */
    3056     5442377 :   if (equalii(subiu(p,1), a))  /* -1 */
    3057             :   {
    3058             :     pari_sp av2;
    3059             :     GEN t;
    3060     1324609 :     ord = get_arith_Z(ord);
    3061     1324609 :     if (mpodd(ord)) retgc_const(av, cgetg(1, t_VEC)); /* no solution */
    3062     1324595 :     t = shifti(ord,-1); /* only possible solution */
    3063     1324595 :     av2 = avma;
    3064     1324595 :     if (!equalii(Fp_pow(g, t, p), a)) retgc_const(av, cgetg(1, t_VEC));
    3065     1324567 :     set_avma(av2); return gc_INT(av, t);
    3066             :   }
    3067     4117770 :   if (typ(ord)==t_INT && BPSW_psp(p) && Fp_log_use_index(expi(ord),expi(p)))
    3068          63 :     return Fp_log_index(a, g, ord, p);
    3069     4117707 :   return gc_NULL(av); /* not easy */
    3070             : }
    3071             : 
    3072             : GEN
    3073     3928373 : Fp_log(GEN a, GEN g, GEN ord, GEN p)
    3074             : {
    3075     3928373 :   GEN v = get_arith_ZZM(ord);
    3076     3928347 :   GEN F = gmael(v,2,1);
    3077     3928347 :   long lF = lg(F)-1, lmax;
    3078     3928347 :   if (lF == 0) return equali1(a)? gen_0: cgetg(1, t_VEC);
    3079     3928319 :   lmax = expi(gel(F,lF));
    3080     3928317 :   if (BPSW_psp(p) && Fp_log_use_index(lmax,expi(p)))
    3081          91 :     v = mkvec2(gel(v,1),ZM_famat_limit(gel(v,2),int2n(27)));
    3082     3928312 :   return gen_PH_log(a,g,v,(void*)p,&Fp_star);
    3083             : }
    3084             : 
    3085             : /* assume !(p & HIGHMASK) */
    3086             : static ulong
    3087      132404 : Fl_log_naive(ulong a, ulong g, ulong ord, ulong p)
    3088             : {
    3089      132404 :   ulong i, h=1;
    3090      364416 :   for (i = 0; i < ord; i++, h = (h * g) % p)
    3091      364416 :     if (a==h) return i;
    3092           0 :   return ~0UL;
    3093             : }
    3094             : 
    3095             : static ulong
    3096       26212 : Fl_log_naive_pre(ulong a, ulong g, ulong ord, ulong p, ulong pi)
    3097             : {
    3098       26212 :   ulong i, h=1;
    3099       65611 :   for (i = 0; i < ord; i++, h = Fl_mul_pre(h, g, p, pi))
    3100       65611 :     if (a==h) return i;
    3101           0 :   return ~0UL;
    3102             : }
    3103             : 
    3104             : static ulong
    3105           0 : Fl_log_Fp(ulong a, ulong g, ulong ord, ulong p)
    3106             : {
    3107           0 :   pari_sp av = avma;
    3108           0 :   GEN r = Fp_log(utoi(a),utoi(g),utoi(ord),utoi(p));
    3109           0 :   return gc_ulong(av, typ(r)==t_INT ? itou(r): ~0UL);
    3110             : }
    3111             : 
    3112             : /* allow pi = 0 */
    3113             : ulong
    3114       26610 : Fl_log_pre(ulong a, ulong g, ulong ord, ulong p, ulong pi)
    3115             : {
    3116       26610 :   if (!pi) return Fl_log(a, g, ord, p);
    3117       26212 :   if (ord <= 200) return Fl_log_naive_pre(a, g, ord, p, pi);
    3118           0 :   return Fl_log_Fp(a, g, ord, p);
    3119             : }
    3120             : 
    3121             : ulong
    3122      132404 : Fl_log(ulong a, ulong g, ulong ord, ulong p)
    3123             : {
    3124      132404 :   if (ord <= 200)
    3125           0 :     return (p&HIGHMASK)? Fl_log_naive_pre(a, g, ord, p, get_Fl_red(p))
    3126      132404 :                        : Fl_log_naive(a, g, ord, p);
    3127           0 :   return Fl_log_Fp(a, g, ord, p);
    3128             : }
    3129             : 
    3130             : /* find x such that h = g^x mod N > 1, N = prod_{i <= l} P[i]^E[i], P[i] prime.
    3131             :  * PHI[l] = eulerphi(N / P[l]^E[l]).   Destroys P/E */
    3132             : static GEN
    3133         126 : znlog_rec(GEN h, GEN g, GEN N, GEN P, GEN E, GEN PHI)
    3134             : {
    3135         126 :   long l = lg(P) - 1, e = E[l];
    3136         126 :   GEN p = gel(P, l), phi = gel(PHI,l), pe = e == 1? p: powiu(p, e);
    3137             :   GEN a,b, hp,gp, hpe,gpe, ogpe; /* = order(g mod p^e) | p^(e-1)(p-1) */
    3138             : 
    3139         126 :   if (l == 1) {
    3140          98 :     hpe = h;
    3141          98 :     gpe = g;
    3142             :   } else {
    3143          28 :     hpe = modii(h, pe);
    3144          28 :     gpe = modii(g, pe);
    3145             :   }
    3146         126 :   if (e == 1) {
    3147          42 :     hp = hpe;
    3148          42 :     gp = gpe;
    3149             :   } else {
    3150          84 :     hp = remii(hpe, p);
    3151          84 :     gp = remii(gpe, p);
    3152             :   }
    3153         126 :   if (hp == gen_0 || gp == gen_0) return NULL;
    3154         105 :   if (absequaliu(p, 2))
    3155             :   {
    3156          35 :     GEN n = int2n(e);
    3157          35 :     ogpe = Zp_order(gpe, gen_2, e, n);
    3158          35 :     a = Fp_log(hpe, gpe, ogpe, n);
    3159          35 :     if (typ(a) != t_INT) return NULL;
    3160             :   }
    3161             :   else
    3162             :   { /* Avoid black box groups: (Z/p^2)^* / (Z/p)^* ~ (Z/pZ, +), where DL
    3163             :        is trivial */
    3164             :     /* [order(gp), factor(order(gp))] */
    3165          70 :     GEN v = Fp_factored_order(gp, subiu(p,1), p);
    3166          70 :     GEN ogp = gel(v,1);
    3167          70 :     if (!equali1(Fp_pow(hp, ogp, p))) return NULL;
    3168          70 :     a = Fp_log(hp, gp, v, p);
    3169          70 :     if (typ(a) != t_INT) return NULL;
    3170          70 :     if (e == 1) ogpe = ogp;
    3171             :     else
    3172             :     { /* find a s.t. g^a = h (mod p^e), p odd prime, e > 0, (h,p) = 1 */
    3173             :       /* use p-adic log: O(log p + e) mul*/
    3174             :       long vpogpe, vpohpe;
    3175             : 
    3176          28 :       hpe = Fp_mul(hpe, Fp_pow(gpe, negi(a), pe), pe);
    3177          28 :       gpe = Fp_pow(gpe, ogp, pe);
    3178             :       /* g,h = 1 mod p; compute b s.t. h = g^b */
    3179             : 
    3180             :       /* v_p(order g mod pe) */
    3181          28 :       vpogpe = equali1(gpe)? 0: e - Z_pval(subiu(gpe,1), p);
    3182             :       /* v_p(order h mod pe) */
    3183          28 :       vpohpe = equali1(hpe)? 0: e - Z_pval(subiu(hpe,1), p);
    3184          28 :       if (vpohpe > vpogpe) return NULL;
    3185             : 
    3186          28 :       ogpe = mulii(ogp, powiu(p, vpogpe)); /* order g mod p^e */
    3187          28 :       if (is_pm1(gpe)) return is_pm1(hpe)? a: NULL;
    3188          28 :       b = gdiv(Qp_log(cvtop(hpe, p, e)), Qp_log(cvtop(gpe, p, e)));
    3189          28 :       a = addii(a, mulii(ogp, padic_to_Q(b)));
    3190             :     }
    3191             :   }
    3192             :   /* gp^a = hp => x = a mod ogpe => generalized Pohlig-Hellman strategy */
    3193          91 :   if (l == 1) return a;
    3194             : 
    3195          28 :   N = diviiexact(N, pe); /* make N coprime to p */
    3196          28 :   h = Fp_mul(h, Fp_pow(g, modii(negi(a), phi), N), N);
    3197          28 :   g = Fp_pow(g, modii(ogpe, phi), N);
    3198          28 :   setlg(P, l); /* remove last element */
    3199          28 :   setlg(E, l);
    3200          28 :   b = znlog_rec(h, g, N, P, E, PHI);
    3201          28 :   if (!b) return NULL;
    3202          28 :   return addmulii(a, b, ogpe);
    3203             : }
    3204             : 
    3205             : static GEN
    3206          98 : get_PHI(GEN P, GEN E)
    3207             : {
    3208          98 :   long i, l = lg(P);
    3209          98 :   GEN PHI = cgetg(l, t_VEC);
    3210          98 :   gel(PHI,1) = gen_1;
    3211         126 :   for (i=1; i<l-1; i++)
    3212             :   {
    3213          28 :     GEN t, p = gel(P,i);
    3214          28 :     long e = E[i];
    3215          28 :     t = mulii(powiu(p, e-1), subiu(p,1));
    3216          28 :     if (i > 1) t = mulii(t, gel(PHI,i));
    3217          28 :     gel(PHI,i+1) = t;
    3218             :   }
    3219          98 :   return PHI;
    3220             : }
    3221             : 
    3222             : GEN
    3223         238 : znlog(GEN h, GEN g, GEN o)
    3224             : {
    3225         238 :   pari_sp av = avma;
    3226             :   GEN N, fa, P, E, x;
    3227         238 :   switch (typ(g))
    3228             :   {
    3229          28 :     case t_PADIC:
    3230             :     {
    3231          28 :       GEN p = padic_p(g);
    3232          28 :       long v = valp(g);
    3233          28 :       if (v < 0) pari_err_DIM("znlog");
    3234          28 :       if (v > 0) {
    3235           0 :         long k = gvaluation(h, p);
    3236           0 :         if (k % v) return cgetg(1,t_VEC);
    3237           0 :         k /= v;
    3238           0 :         if (!gequal(h, gpowgs(g,k))) retgc_const(av, cgetg(1, t_VEC));
    3239           0 :         return gc_stoi(av, k);
    3240             :       }
    3241          28 :       N = padic_pd(g);
    3242          28 :       g = Rg_to_Fp(g, N);
    3243          28 :       break;
    3244             :     }
    3245         203 :     case t_INTMOD:
    3246         203 :       N = gel(g,1);
    3247         203 :       g = gel(g,2); break;
    3248           7 :     default: pari_err_TYPE("znlog", g);
    3249             :       return NULL; /* LCOV_EXCL_LINE */
    3250             :   }
    3251         231 :   if (equali1(N)) { set_avma(av); return gen_0; }
    3252         231 :   h = Rg_to_Fp(h, N);
    3253         224 :   if (o) return gc_upto(av, Fp_log(h, g, o, N));
    3254          98 :   fa = Z_factor(N);
    3255          98 :   P = gel(fa,1);
    3256          98 :   E = vec_to_vecsmall(gel(fa,2));
    3257          98 :   x = znlog_rec(h, g, N, P, E, get_PHI(P,E));
    3258          98 :   if (!x) retgc_const(av, cgetg(1, t_VEC));
    3259          63 :   return gc_INT(av, x);
    3260             : }
    3261             : 
    3262             : GEN
    3263      173541 : Fp_sqrtn(GEN a, GEN n, GEN p, GEN *zeta)
    3264             : {
    3265      173541 :   if (lgefint(p)==3)
    3266             :   {
    3267      172921 :     long nn = itos_or_0(n);
    3268      172921 :     if (nn)
    3269             :     {
    3270      172921 :       ulong pp = p[2];
    3271             :       ulong uz;
    3272      172921 :       ulong r = Fl_sqrtn(umodiu(a,pp),nn,pp, zeta ? &uz:NULL);
    3273      172900 :       if (r==ULONG_MAX) return NULL;
    3274      172858 :       if (zeta) *zeta = utoi(uz);
    3275      172858 :       return utoi(r);
    3276             :     }
    3277             :   }
    3278         620 :   a = modii(a,p);
    3279         620 :   if (!signe(a))
    3280             :   {
    3281           0 :     if (zeta) *zeta = gen_1;
    3282           0 :     if (signe(n) < 0) pari_err_INV("Fp_sqrtn", mkintmod(gen_0,p));
    3283           0 :     return gen_0;
    3284             :   }
    3285         620 :   if (absequaliu(n,2))
    3286             :   {
    3287         420 :     if (zeta) *zeta = subiu(p,1);
    3288         420 :     return signe(n) > 0 ? Fp_sqrt(a,p): Fp_sqrt(Fp_inv(a, p),p);
    3289             :   }
    3290         200 :   return gen_Shanks_sqrtn(a,n,subiu(p,1),zeta,(void*)p,&Fp_star);
    3291             : }
    3292             : 
    3293             : /*********************************************************************/
    3294             : /**                              FACTORIAL                          **/
    3295             : /*********************************************************************/
    3296             : GEN
    3297       90631 : mulu_interval_step(ulong a, ulong b, ulong step)
    3298             : {
    3299       90631 :   pari_sp av = avma;
    3300             :   ulong k, l, N, n;
    3301             :   long lx;
    3302             :   GEN x;
    3303             : 
    3304       90631 :   if (!a) return gen_0;
    3305       90631 :   if (step == 1) return mulu_interval(a, b);
    3306       90631 :   n = 1 + (b-a) / step;
    3307       90631 :   b -= (b-a) % step;
    3308       90631 :   if (n < 61)
    3309             :   {
    3310       89255 :     if (n == 1) return utoipos(a);
    3311       68717 :     x = muluu(a,a+step); if (n == 2) return x;
    3312      540850 :     for (k=a+2*step; k<=b; k+=step) x = mului(k,x);
    3313       53949 :     return gc_INT(av, x);
    3314             :   }
    3315             :   /* step | b-a */
    3316        1376 :   lx = 1; x = cgetg(2 + n/2, t_VEC);
    3317        1377 :   N = b + a;
    3318        1377 :   for (k = a;; k += step)
    3319             :   {
    3320      227231 :     l = N - k; if (l <= k) break;
    3321      225854 :     gel(x,lx++) = muluu(k,l);
    3322             :   }
    3323        1377 :   if (l == k) gel(x,lx++) = utoipos(k);
    3324        1377 :   setlg(x, lx);
    3325        1377 :   return gc_INT(av, ZV_prod(x));
    3326             : }
    3327             : /* return a * (a+1) * ... * b. Assume a <= b  [ note: factoring out powers of 2
    3328             :  * first is slower ... ] */
    3329             : GEN
    3330      159094 : mulu_interval(ulong a, ulong b)
    3331             : {
    3332      159094 :   pari_sp av = avma;
    3333             :   ulong k, l, N, n;
    3334             :   long lx;
    3335             :   GEN x;
    3336             : 
    3337      159094 :   if (!a) return gen_0;
    3338      159094 :   n = b - a + 1;
    3339      159094 :   if (n < 61)
    3340             :   {
    3341      158359 :     if (n == 1) return utoipos(a);
    3342      107889 :     x = muluu(a,a+1); if (n == 2) return x;
    3343      405654 :     for (k=a+2; k<b; k++) x = mului(k,x);
    3344             :     /* avoid k <= b: broken if b = ULONG_MAX */
    3345       93791 :     return gc_INT(av, mului(b,x));
    3346             :   }
    3347         735 :   lx = 1; x = cgetg(2 + n/2, t_VEC);
    3348         735 :   N = b + a;
    3349         735 :   for (k = a;; k++)
    3350             :   {
    3351       29974 :     l = N - k; if (l <= k) break;
    3352       29239 :     gel(x,lx++) = muluu(k,l);
    3353             :   }
    3354         735 :   if (l == k) gel(x,lx++) = utoipos(k);
    3355         735 :   setlg(x, lx);
    3356         735 :   return gc_INT(av, ZV_prod(x));
    3357             : }
    3358             : GEN
    3359         623 : muls_interval(long a, long b)
    3360             : {
    3361         623 :   pari_sp av = avma;
    3362         623 :   long lx, k, l, N, n = b - a + 1;
    3363             :   GEN x;
    3364             : 
    3365         623 :   if (a <= 0 && b >= 0) return gen_0;
    3366         350 :   if (n < 61)
    3367             :   {
    3368         350 :     x = stoi(a);
    3369         574 :     for (k=a+1; k<=b; k++) x = mulsi(k,x);
    3370         350 :     return gc_INT(av, x);
    3371             :   }
    3372           0 :   lx = 1; x = cgetg(2 + n/2, t_VEC);
    3373           0 :   N = b + a;
    3374           0 :   for (k = a;; k++)
    3375             :   {
    3376           0 :     l = N - k; if (l <= k) break;
    3377           0 :     gel(x,lx++) = mulss(k,l);
    3378             :   }
    3379           0 :   if (l == k) gel(x,lx++) = stoi(k);
    3380           0 :   setlg(x, lx);
    3381           0 :   return gc_INT(av, ZV_prod(x));
    3382             : }
    3383             : 
    3384             : GEN
    3385         105 : mpprimorial(long n)
    3386             : {
    3387         105 :   pari_sp av = avma;
    3388         105 :   if (n <= 12) switch(n)
    3389             :   {
    3390          14 :     case 0: case 1: return gen_1;
    3391           7 :     case 2: return gen_2;
    3392          14 :     case 3: case 4: return utoipos(6);
    3393          14 :     case 5: case 6: return utoipos(30);
    3394          28 :     case 7: case 8: case 9: case 10: return utoipos(210);
    3395          14 :     case 11: case 12: return utoipos(2310);
    3396           7 :     default: pari_err_DOMAIN("primorial", "argument","<",gen_0,stoi(n));
    3397             :   }
    3398           7 :   return gc_INT(av, zv_prod_Z(primes_upto_zv(n)));
    3399             : }
    3400             : 
    3401             : GEN
    3402      496570 : mpfact(long n)
    3403             : {
    3404      496570 :   pari_sp av = avma;
    3405             :   GEN a, v;
    3406             :   long k;
    3407      496570 :   if (n <= 12) switch(n)
    3408             :   {
    3409      428675 :     case 0: case 1: return gen_1;
    3410       24317 :     case 2: return gen_2;
    3411        3388 :     case 3: return utoipos(6);
    3412        4145 :     case 4: return utoipos(24);
    3413        2887 :     case 5: return utoipos(120);
    3414        2556 :     case 6: return utoipos(720);
    3415        2448 :     case 7: return utoipos(5040);
    3416        2437 :     case 8: return utoipos(40320);
    3417        2458 :     case 9: return utoipos(362880);
    3418        2694 :     case 10:return utoipos(3628800);
    3419        1409 :     case 11:return utoipos(39916800);
    3420         576 :     case 12:return utoipos(479001600);
    3421           0 :     default: pari_err_DOMAIN("factorial", "argument","<",gen_0,stoi(n));
    3422             :   }
    3423       18581 :   v = cgetg(expu(n) + 2, t_VEC);
    3424       18556 :   for (k = 1;; k++)
    3425       86848 :   {
    3426      105404 :     long m = n >> (k-1), l;
    3427      105404 :     if (m <= 2) break;
    3428       86823 :     l = (1 + (n >> k)) | 1;
    3429             :     /* product of odd numbers in ]n / 2^k, n / 2^(k-1)] */
    3430       86823 :     a = mulu_interval_step(l, m, 2);
    3431       86837 :     gel(v,k) = k == 1? a: powiu(a, k);
    3432             :   }
    3433       86860 :   a = gel(v,--k); while (--k) a = mulii(a, gel(v,k));
    3434       18582 :   a = shifti(a, factorial_lval(n, 2));
    3435       18580 :   return gc_INT(av, a);
    3436             : }
    3437             : 
    3438             : ulong
    3439       56843 : factorial_Fl(long n, ulong p)
    3440             : {
    3441             :   long k;
    3442             :   ulong v;
    3443       56843 :   if (p <= (ulong)n) return 0;
    3444       56843 :   v = Fl_powu(2, factorial_lval(n, 2), p);
    3445       56898 :   for (k = 1;; k++)
    3446      142600 :   {
    3447      199498 :     long m = n >> (k-1), l, i;
    3448      199498 :     ulong a = 1;
    3449      199498 :     if (m <= 2) break;
    3450      142612 :     l = (1 + (n >> k)) | 1;
    3451             :     /* product of odd numbers in ]n / 2^k, 2 / 2^(k-1)] */
    3452      781026 :     for (i=l; i<=m; i+=2)
    3453      638422 :       a = Fl_mul(a, i, p);
    3454      142604 :     v = Fl_mul(v, k == 1? a: Fl_powu(a, k, p), p);
    3455             :   }
    3456       56886 :   return v;
    3457             : }
    3458             : 
    3459             : GEN
    3460         382 : factorial_Fp(long n, GEN p)
    3461             : {
    3462         382 :   pari_sp av = avma;
    3463             :   long k;
    3464         382 :   GEN v = Fp_powu(gen_2, factorial_lval(n, 2), p);
    3465         382 :   for (k = 1;; k++)
    3466        1240 :   {
    3467        1622 :     long m = n >> (k-1), l, i;
    3468        1622 :     GEN a = gen_1;
    3469        1622 :     if (m <= 2) break;
    3470        1240 :     l = (1 + (n >> k)) | 1;
    3471             :     /* product of odd numbers in ]n / 2^k, 2 / 2^(k-1)] */
    3472        7570 :     for (i=l; i<=m; i+=2)
    3473        6330 :       a = Fp_mulu(a, i, p);
    3474        1240 :     v = Fp_mul(v, k == 1? a: Fp_powu(a, k, p), p);
    3475        1240 :     v = gc_INT(av, v);
    3476             :   }
    3477         382 :   return v;
    3478             : }
    3479             : 
    3480             : /*******************************************************************/
    3481             : /**                      LUCAS & FIBONACCI                        **/
    3482             : /*******************************************************************/
    3483             : static void
    3484          56 : lucas(ulong n, GEN *a, GEN *b)
    3485             : {
    3486             :   GEN z, t, zt;
    3487          56 :   if (!n) { *a = gen_2; *b = gen_1; return; }
    3488          49 :   lucas(n >> 1, &z, &t); zt = mulii(z, t);
    3489          49 :   switch(n & 3) {
    3490          14 :     case  0: *a = subiu(sqri(z),2); *b = subiu(zt,1); break;
    3491          14 :     case  1: *a = subiu(zt,1);      *b = addiu(sqri(t),2); break;
    3492           7 :     case  2: *a = addiu(sqri(z),2); *b = addiu(zt,1); break;
    3493          14 :     case  3: *a = addiu(zt,1);      *b = subiu(sqri(t),2);
    3494             :   }
    3495             : }
    3496             : 
    3497             : GEN
    3498           7 : fibo(long n)
    3499             : {
    3500           7 :   pari_sp av = avma;
    3501             :   GEN a, b;
    3502           7 :   if (!n) return gen_0;
    3503           7 :   lucas((ulong)(labs(n)-1), &a, &b);
    3504           7 :   a = diviuexact(addii(shifti(a,1),b), 5);
    3505           7 :   if (n < 0 && !odd(n)) setsigne(a, -1);
    3506           7 :   return gc_INT(av, a);
    3507             : }
    3508             : 
    3509             : /*******************************************************************/
    3510             : /*                      CONTINUED FRACTIONS                        */
    3511             : /*******************************************************************/
    3512             : static GEN
    3513     3136994 : icopy_lg(GEN x, long l)
    3514             : {
    3515     3136994 :   long lx = lgefint(x);
    3516             :   GEN y;
    3517             : 
    3518     3136994 :   if (lx >= l) return icopy(x);
    3519          49 :   y = cgeti(l); affii(x, y); return y;
    3520             : }
    3521             : 
    3522             : /* continued fraction of a/b. If y != NULL, stop when partial quotients
    3523             :  * differ from y */
    3524             : static GEN
    3525     3137344 : Qsfcont(GEN a, GEN b, GEN y, ulong k)
    3526             : {
    3527             :   GEN  z, c;
    3528     3137344 :   ulong i, l, ly = lgefint(b);
    3529             : 
    3530             :   /* times 1 / log2( (1+sqrt(5)) / 2 )  */
    3531     3137344 :   l = (ulong)(3 + bit_accuracy_mul(ly, 1.44042009041256));
    3532     3137344 :   if (k > 0 && k+1 > 0 && l > k+1) l = k+1; /* beware overflow */
    3533     3137344 :   if (l > LGBITS) l = LGBITS;
    3534             : 
    3535     3137344 :   z = cgetg(l,t_VEC);
    3536     3137344 :   l--;
    3537     3137344 :   if (y) {
    3538         350 :     pari_sp av = avma;
    3539         350 :     if (l >= (ulong)lg(y)) l = lg(y)-1;
    3540       25209 :     for (i = 1; i <= l; i++)
    3541             :     {
    3542       24985 :       GEN q = gel(y,i);
    3543       24985 :       gel(z,i) = q;
    3544       24985 :       c = b; if (!gequal1(q)) c = mulii(q, b);
    3545       24985 :       c = subii(a, c);
    3546       24985 :       if (signe(c) < 0)
    3547             :       { /* partial quotient too large */
    3548          96 :         c = addii(c, b);
    3549          96 :         if (signe(c) >= 0) i++; /* by 1 */
    3550          96 :         break;
    3551             :       }
    3552       24889 :       if (cmpii(c, b) >= 0)
    3553             :       { /* partial quotient too small */
    3554          30 :         c = subii(c, b);
    3555          30 :         if (cmpii(c, b) < 0) {
    3556             :           /* by 1. If next quotient is 1 in y, add 1 */
    3557          12 :           if (i < l && equali1(gel(y,i+1))) gel(z,i) = addiu(q,1);
    3558          12 :           i++;
    3559             :         }
    3560          30 :         break;
    3561             :       }
    3562       24859 :       if ((i & 0xff) == 0) (void)gc_all(av, 2, &b, &c);
    3563       24859 :       a = b; b = c;
    3564             :     }
    3565             :   } else {
    3566     3136994 :     a = icopy_lg(a, ly);
    3567     3136994 :     b = icopy(b);
    3568    24524282 :     for (i = 1; i <= l; i++)
    3569             :     {
    3570    24523964 :       gel(z,i) = truedvmdii(a,b,&c);
    3571    24523964 :       if (c == gen_0) { i++; break; }
    3572    21387288 :       affii(c, a); cgiv(c); c = a;
    3573    21387288 :       a = b; b = c;
    3574             :     }
    3575             :   }
    3576     3137344 :   i--;
    3577     3137344 :   if (i > 1 && gequal1(gel(z,i)))
    3578             :   {
    3579         101 :     cgiv(gel(z,i)); --i;
    3580         101 :     gel(z,i) = addui(1, gel(z,i)); /* unclean: leave old z[i] on stack */
    3581             :   }
    3582     3137344 :   setlg(z,i+1); return z;
    3583             : }
    3584             : 
    3585             : static GEN
    3586           0 : sersfcont(GEN a, GEN b, long k)
    3587             : {
    3588           0 :   long i, l = typ(a) == t_POL? lg(a): 3;
    3589             :   GEN y, c;
    3590           0 :   if (lg(b) > l) l = lg(b);
    3591           0 :   if (k > 0 && l > k+1) l = k+1;
    3592           0 :   y = cgetg(l,t_VEC);
    3593           0 :   for (i=1; i<l; i++)
    3594             :   {
    3595           0 :     gel(y,i) = poldivrem(a,b,&c);
    3596           0 :     if (gequal0(c)) { i++; break; }
    3597           0 :     a = b; b = c;
    3598             :   }
    3599           0 :   setlg(y, i); return y;
    3600             : }
    3601             : 
    3602             : GEN
    3603     3142307 : gboundcf(GEN x, long k)
    3604             : {
    3605             :   pari_sp av;
    3606     3142307 :   long tx = typ(x), e;
    3607             :   GEN y, a, b, c;
    3608             : 
    3609     3142307 :   if (k < 0) pari_err_DOMAIN("gboundcf","nmax","<",gen_0,stoi(k));
    3610     3142300 :   if (is_scalar_t(tx))
    3611             :   {
    3612     3142300 :     if (gequal0(x)) return mkvec(gen_0);
    3613     3142181 :     switch(tx)
    3614             :     {
    3615        5180 :       case t_INT: return mkveccopy(x);
    3616         357 :       case t_REAL:
    3617         357 :         av = avma;
    3618         357 :         c = mantissa_real(x,&e);
    3619         357 :         if (e < 0) pari_err_PREC("gboundcf");
    3620         350 :         y = int2n(e);
    3621         350 :         a = Qsfcont(c,y, NULL, k);
    3622         350 :         b = addsi(signe(x), c);
    3623         350 :         return gc_GEN(av, Qsfcont(b,y, a, k));
    3624             : 
    3625     3136644 :       case t_FRAC:
    3626     3136644 :         av = avma;
    3627     3136644 :         return gc_upto(av, Qsfcont(gel(x,1),gel(x,2), NULL, k));
    3628             :     }
    3629           0 :     pari_err_TYPE("gboundcf",x);
    3630             :   }
    3631             : 
    3632           0 :   switch(tx)
    3633             :   {
    3634           0 :     case t_POL: return mkveccopy(x);
    3635           0 :     case t_SER:
    3636           0 :       av = avma;
    3637           0 :       return gc_upto(av, gboundcf(ser2rfrac_i(x), k));
    3638           0 :     case t_RFRAC:
    3639           0 :       av = avma;
    3640           0 :       return gc_GEN(av, sersfcont(gel(x,1), gel(x,2), k));
    3641             :   }
    3642           0 :   pari_err_TYPE("gboundcf",x);
    3643             :   return NULL; /* LCOV_EXCL_LINE */
    3644             : }
    3645             : 
    3646             : static GEN
    3647          14 : sfcont2(GEN b, GEN x, long k)
    3648             : {
    3649          14 :   pari_sp av = avma;
    3650          14 :   long lb = lg(b), tx = typ(x), i;
    3651             :   GEN y,p1;
    3652             : 
    3653          14 :   if (k)
    3654             :   {
    3655           7 :     if (k >= lb) pari_err_DIM("contfrac [too few denominators]");
    3656           0 :     lb = k+1;
    3657             :   }
    3658           7 :   y = cgetg(lb,t_VEC);
    3659           7 :   if (lb==1) return y;
    3660           7 :   if (is_scalar_t(tx))
    3661             :   {
    3662           7 :     if (!is_intreal_t(tx) && tx != t_FRAC) pari_err_TYPE("sfcont2",x);
    3663             :   }
    3664           0 :   else if (tx == t_SER) x = ser2rfrac_i(x);
    3665             : 
    3666           7 :   if (!gequal1(gel(b,1))) x = gmul(gel(b,1),x);
    3667           7 :   for (i = 1;;)
    3668             :   {
    3669          35 :     if (tx == t_REAL)
    3670             :     {
    3671          35 :       long e = expo(x);
    3672          35 :       if (e > 0 && nbits2prec(e+1) > realprec(x)) break;
    3673          35 :       gel(y,i) = floorr(x);
    3674          35 :       p1 = subri(x, gel(y,i));
    3675             :     }
    3676             :     else
    3677             :     {
    3678           0 :       gel(y,i) = gfloor(x);
    3679           0 :       p1 = gsub(x, gel(y,i));
    3680             :     }
    3681          35 :     if (++i >= lb) break;
    3682          28 :     if (gequal0(p1)) break;
    3683          28 :     x = gdiv(gel(b,i),p1);
    3684             :   }
    3685           7 :   setlg(y,i);
    3686           7 :   return gc_GEN(av,y);
    3687             : }
    3688             : 
    3689             : GEN
    3690         126 : gcf(GEN x) { return gboundcf(x,0); }
    3691             : GEN
    3692           0 : gcf2(GEN b, GEN x) { return contfrac0(x,b,0); }
    3693             : GEN
    3694          49 : contfrac0(GEN x, GEN b, long nmax)
    3695             : {
    3696             :   long tb;
    3697             : 
    3698          49 :   if (!b) return gboundcf(x,nmax);
    3699          28 :   tb = typ(b);
    3700          28 :   if (tb == t_INT) return gboundcf(x,itos(b));
    3701          21 :   if (! is_vec_t(tb)) pari_err_TYPE("contfrac0",b);
    3702          21 :   if (nmax < 0) pari_err_DOMAIN("contfrac","nmax","<",gen_0,stoi(nmax));
    3703          14 :   return sfcont2(b,x,nmax);
    3704             : }
    3705             : 
    3706             : GEN
    3707         266 : contfracpnqn(GEN x, long n)
    3708             : {
    3709         266 :   pari_sp av = avma;
    3710         266 :   long i, lx = lg(x);
    3711             :   GEN M,A,B, p0,p1, q0,q1;
    3712             : 
    3713         266 :   if (lx == 1)
    3714             :   {
    3715          28 :     if (! is_matvec_t(typ(x))) pari_err_TYPE("pnqn",x);
    3716          21 :     if (n >= 0) return cgetg(1,t_MAT);
    3717           7 :     return matid(2);
    3718             :   }
    3719         238 :   switch(typ(x))
    3720             :   {
    3721         196 :     case t_VEC: case t_COL: A = x; B = NULL; break;
    3722          42 :     case t_MAT:
    3723          42 :       switch(lgcols(x))
    3724             :       {
    3725           0 :         case 2: A = row(x,1); B = NULL; break;
    3726          35 :         case 3: A = row(x,2); B = row(x,1); break;
    3727           7 :         default: pari_err_DIM("pnqn [ nbrows != 1,2 ]");
    3728             :                  return NULL; /*LCOV_EXCL_LINE*/
    3729             :       }
    3730          35 :       break;
    3731           0 :     default: pari_err_TYPE("pnqn",x);
    3732             :       return NULL; /*LCOV_EXCL_LINE*/
    3733             :   }
    3734         231 :   p1 = gel(A,1);
    3735         231 :   q1 = B? gel(B,1): gen_1; /* p[0], q[0] */
    3736         231 :   if (n >= 0)
    3737             :   {
    3738         196 :     lx = minss(lx, n+2);
    3739         196 :     if (lx == 2) return gc_GEN(av, mkmat(mkcol2(p1,q1)));
    3740             :   }
    3741          35 :   else if (lx == 2)
    3742           7 :     return gc_GEN(av, mkmat2(mkcol2(p1,q1), mkcol2(gen_1,gen_0)));
    3743             :   /* lx >= 3 */
    3744         119 :   p0 = gen_1;
    3745         119 :   q0 = gen_0; /* p[-1], q[-1] */
    3746         119 :   M = cgetg(lx, t_MAT);
    3747         119 :   gel(M,1) = mkcol2(p1,q1);
    3748         399 :   for (i=2; i<lx; i++)
    3749             :   {
    3750         280 :     GEN a = gel(A,i), p2,q2;
    3751         280 :     if (B) {
    3752          84 :       GEN b = gel(B,i);
    3753          84 :       p0 = gmul(b,p0);
    3754          84 :       q0 = gmul(b,q0);
    3755             :     }
    3756         280 :     p2 = gadd(gmul(a,p1),p0); p0=p1; p1=p2;
    3757         280 :     q2 = gadd(gmul(a,q1),q0); q0=q1; q1=q2;
    3758         280 :     gel(M,i) = mkcol2(p1,q1);
    3759             :   }
    3760         119 :   if (n < 0) M = mkmat2(gel(M,lx-1), gel(M,lx-2));
    3761         119 :   return gc_GEN(av, M);
    3762             : }
    3763             : GEN
    3764           0 : pnqn(GEN x) { return contfracpnqn(x,-1); }
    3765             : /* x = [a0, ..., an] from gboundcf, n >= 0;
    3766             :  * return [[p0, ..., pn], [q0,...,qn]] */
    3767             : GEN
    3768      894782 : ZV_allpnqn(GEN x)
    3769             : {
    3770      894782 :   long i, lx = lg(x);
    3771      894782 :   GEN p0, p1, q0, q1, p2, q2, P,Q, v = cgetg(3,t_VEC);
    3772             : 
    3773      894782 :   gel(v,1) = P = cgetg(lx, t_VEC);
    3774      894782 :   gel(v,2) = Q = cgetg(lx, t_VEC);
    3775      894782 :   p0 = gen_1; q0 = gen_0;
    3776      894782 :   gel(P, 1) = p1 = gel(x,1); gel(Q, 1) = q1 = gen_1;
    3777     3106138 :   for (i=2; i<lx; i++)
    3778             :   {
    3779     2211356 :     GEN a = gel(x,i);
    3780     2211356 :     gel(P, i) = p2 = addmulii(p0, a, p1); p0 = p1; p1 = p2;
    3781     2211356 :     gel(Q, i) = q2 = addmulii(q0, a, q1); q0 = q1; q1 = q2;
    3782             :   }
    3783      894782 :   return v;
    3784             : }
    3785             : 
    3786             : /* write Mod(x,N) as a/b, gcd(a,b) = 1, b <= B (no condition if B = NULL) */
    3787             : static GEN
    3788          42 : mod_to_frac(GEN x, GEN N, GEN B)
    3789             : {
    3790             :   GEN a, b, A;
    3791          42 :   if (B) A = divii(shifti(N, -1), B);
    3792             :   else
    3793             :   {
    3794          14 :     A = sqrti(shifti(N, -1));
    3795          14 :     B = A;
    3796             :   }
    3797          42 :   if (!Fp_ratlift(x, N, A,B,&a,&b) || !equali1( gcdii(a,b) )) return NULL;
    3798          28 :   return equali1(b)? a: mkfrac(a,b);
    3799             : }
    3800             : 
    3801             : static GEN
    3802         112 : mod_to_rfrac(GEN x, GEN N, long B)
    3803             : {
    3804             :   GEN a, b;
    3805         112 :   long A, d = degpol(N);
    3806         112 :   if (B >= 0) A = d-1 - B;
    3807             :   else
    3808             :   {
    3809          42 :     B = d >> 1;
    3810          42 :     A = odd(d)? B : B-1;
    3811             :   }
    3812         112 :   if (varn(N) != varn(x)) x = scalarpol(x, varn(N));
    3813         112 :   if (!RgXQ_ratlift(x, N, A, B, &a,&b) || degpol(RgX_gcd(a,b)) > 0) return NULL;
    3814          91 :   return gdiv(a,b);
    3815             : }
    3816             : 
    3817             : /* k > 0 t_INT, x a t_FRAC, returns the convergent a/b
    3818             :  * of the continued fraction of x with b <= k maximal */
    3819             : static GEN
    3820           7 : bestappr_frac(GEN x, GEN k)
    3821             : {
    3822             :   pari_sp av;
    3823             :   GEN p0, p1, p, q0, q1, q, a, y;
    3824             : 
    3825           7 :   if (cmpii(gel(x,2),k) <= 0) return gcopy(x);
    3826           0 :   av = avma; y = x;
    3827           0 :   p1 = gen_1; p0 = truedvmdii(gel(x,1), gel(x,2), &a); /* = floor(x) */
    3828           0 :   q1 = gen_0; q0 = gen_1;
    3829           0 :   x = mkfrac(a, gel(x,2)); /* = frac(x); now 0<= x < 1 */
    3830             :   for(;;)
    3831             :   {
    3832           0 :     x = ginv(x); /* > 1 */
    3833           0 :     a = typ(x)==t_INT? x: divii(gel(x,1), gel(x,2));
    3834           0 :     if (cmpii(a,k) > 0)
    3835             :     { /* next partial quotient will overflow limits */
    3836             :       GEN n, d;
    3837           0 :       a = divii(subii(k, q1), q0);
    3838           0 :       p = addii(mulii(a,p0), p1); p1=p0; p0=p;
    3839           0 :       q = addii(mulii(a,q0), q1); q1=q0; q0=q;
    3840             :       /* compare |y-p0/q0|, |y-p1/q1| */
    3841           0 :       n = gel(y,1);
    3842           0 :       d = gel(y,2);
    3843           0 :       if (abscmpii(mulii(q1, subii(mulii(q0,n), mulii(d,p0))),
    3844             :                    mulii(q0, subii(mulii(q1,n), mulii(d,p1)))) < 0)
    3845           0 :                    { p1 = p0; q1 = q0; }
    3846           0 :       break;
    3847             :     }
    3848           0 :     p = addii(mulii(a,p0), p1); p1=p0; p0=p;
    3849           0 :     q = addii(mulii(a,q0), q1); q1=q0; q0=q;
    3850             : 
    3851           0 :     if (cmpii(q0,k) > 0) break;
    3852           0 :     x = gsub(x,a); /* 0 <= x < 1 */
    3853           0 :     if (typ(x) == t_INT) { p1 = p0; q1 = q0; break; } /* x = 0 */
    3854             : 
    3855             :   }
    3856           0 :   return gc_upto(av, gdiv(p1,q1));
    3857             : }
    3858             : /* k > 0 t_INT, x != 0 a t_REAL, returns the convergent a/b
    3859             :  * of the continued fraction of x with b <= k maximal */
    3860             : static GEN
    3861     1248228 : bestappr_real(GEN x, GEN k)
    3862             : {
    3863     1248228 :   pari_sp av = avma;
    3864     1248228 :   GEN kr, p0, p1, p, q0, q1, q, a, y = x;
    3865             : 
    3866     1248228 :   p1 = gen_1; a = p0 = floorr(x);
    3867     1248194 :   q1 = gen_0; q0 = gen_1;
    3868     1248194 :   x = subri(x,a); /* 0 <= x < 1 */
    3869     1248219 :   if (!signe(x)) { cgiv(x); return a; }
    3870     1130901 :   kr = itor(k, realprec(x));
    3871             :   for(;;)
    3872     1213558 :   {
    3873             :     long d;
    3874     2344462 :     x = invr(x); /* > 1 */
    3875     2344414 :     if (cmprr(x,kr) > 0)
    3876             :     { /* next partial quotient will overflow limits */
    3877     1109247 :       a = divii(subii(k, q1), q0);
    3878     1109228 :       p = addii(mulii(a,p0), p1); p1=p0; p0=p;
    3879     1109246 :       q = addii(mulii(a,q0), q1); q1=q0; q0=q;
    3880             :       /* compare |y-p0/q0|, |y-p1/q1| */
    3881     1109225 :       if (abscmprr(mulir(q1, subri(mulir(q0,y), p0)),
    3882             :                    mulir(q0, subri(mulir(q1,y), p1))) < 0)
    3883      125559 :                    { p1 = p0; q1 = q0; }
    3884     1109251 :       break;
    3885             :     }
    3886     1235203 :     d = nbits2prec(expo(x) + 1);
    3887     1235203 :     if (d > realprec(x)) { p1 = p0; q1 = q0; break; } /* original x was ~ 0 */
    3888             : 
    3889     1235013 :     a = truncr(x); /* truncr(x) will NOT raise e_PREC */
    3890     1234994 :     p = addii(mulii(a,p0), p1); p1=p0; p0=p;
    3891     1235005 :     q = addii(mulii(a,q0), q1); q1=q0; q0=q;
    3892             : 
    3893     1234997 :     if (cmpii(q0,k) > 0) break;
    3894     1228741 :     x = subri(x,a); /* 0 <= x < 1 */
    3895     1228745 :     if (!signe(x)) { p1 = p0; q1 = q0; break; }
    3896             :   }
    3897     1130883 :   if (signe(q1) < 0) { togglesign_safe(&p1); togglesign_safe(&q1); }
    3898     1130883 :   return gc_GEN(av, equali1(q1)? p1: mkfrac(p1,q1));
    3899             : }
    3900             : 
    3901             : /* k t_INT or NULL */
    3902             : static GEN
    3903     2245481 : bestappr_Q(GEN x, GEN k)
    3904             : {
    3905     2245481 :   long lx, tx = typ(x), i;
    3906             :   GEN a, y;
    3907             : 
    3908     2245481 :   switch(tx)
    3909             :   {
    3910         154 :     case t_INT: return icopy(x);
    3911           7 :     case t_FRAC: return k? bestappr_frac(x, k): gcopy(x);
    3912     1500431 :     case t_REAL:
    3913     1500431 :       if (!signe(x)) return gen_0;
    3914             :       /* i <= e iff nbits2lg(e+1) > lg(x) iff floorr(x) fails */
    3915     1248217 :       i = bit_prec(x); if (i <= expo(x)) return NULL;
    3916     1248228 :       return bestappr_real(x, k? k: int2n(i));
    3917             : 
    3918          28 :     case t_INTMOD: {
    3919          28 :       pari_sp av = avma;
    3920          28 :       a = mod_to_frac(gel(x,2), gel(x,1), k); if (!a) return NULL;
    3921          21 :       return gc_GEN(av, a);
    3922             :     }
    3923          14 :     case t_PADIC: {
    3924          14 :       pari_sp av = avma;
    3925          14 :       long v = valp(x);
    3926          14 :       a = mod_to_frac(padic_u(x), padic_pd(x), k); if (!a) return NULL;
    3927           7 :       if (v) a = gmul(a, powis(padic_p(x), v));
    3928           7 :       return gc_GEN(av, a);
    3929             :     }
    3930             : 
    3931        5453 :     case t_COMPLEX: {
    3932        5453 :       pari_sp av = avma;
    3933        5453 :       y = cgetg(3, t_COMPLEX);
    3934        5453 :       gel(y,2) = bestappr(gel(x,2), k);
    3935        5453 :       gel(y,1) = bestappr(gel(x,1), k);
    3936        5453 :       if (gequal0(gel(y,2))) return gc_upto(av, gel(y,1));
    3937          91 :       return y;
    3938             :     }
    3939           0 :     case t_SER:
    3940           0 :       if (ser_isexactzero(x)) return gcopy(x);
    3941             :       /* fall through */
    3942             :     case t_POLMOD: case t_POL: case t_RFRAC:
    3943             :     case t_VEC: case t_COL: case t_MAT:
    3944      739394 :       y = cgetg_copy(x, &lx);
    3945      739433 :       for(i = 1; i < lontyp[tx]; i++) y[i] = x[i];
    3946     2880047 :       for (; i < lx; i++)
    3947             :       {
    3948     2140637 :         a = bestappr_Q(gel(x,i),k); if (!a) return NULL;
    3949     2140628 :         gel(y,i) = a;
    3950             :       }
    3951      739410 :       if (tx == t_POL) return normalizepol(y);
    3952      739396 :       if (tx == t_SER) return normalizeser(y);
    3953      739396 :       return y;
    3954             :   }
    3955           0 :   pari_err_TYPE("bestappr_Q",x);
    3956             :   return NULL; /* LCOV_EXCL_LINE */
    3957             : }
    3958             : 
    3959             : static GEN
    3960          98 : bestappr_ser(GEN x, long B)
    3961             : {
    3962          98 :   long dN, v = valser(x), lx = lg(x);
    3963             :   GEN t;
    3964          98 :   x = normalizepol(ser2pol_i(x, lx));
    3965          98 :   dN = lx-2;
    3966          98 :   if (v > 0)
    3967             :   {
    3968          21 :     x = RgX_shift_shallow(x, v);
    3969          21 :     dN += v;
    3970             :   }
    3971          77 :   else if (v < 0)
    3972             :   {
    3973          14 :     if (B >= 0) B = maxss(B+v, 0);
    3974             :   }
    3975          98 :   t = mod_to_rfrac(x, pol_xn(dN, varn(x)), B);
    3976          98 :   if (!t) return NULL;
    3977          77 :   if (v < 0)
    3978             :   {
    3979             :     GEN a, b;
    3980             :     long vx;
    3981          14 :     if (typ(t) == t_POL) return RgX_mulXn(t, v);
    3982             :     /* t_RFRAC */
    3983          14 :     vx = varn(x);
    3984          14 :     a = gel(t,1);
    3985          14 :     b = gel(t,2);
    3986          14 :     v -= RgX_valrem(b, &b);
    3987          14 :     if (typ(a) == t_POL && varn(a) == vx) v += RgX_valrem(a, &a);
    3988          14 :     if (v < 0) b = RgX_shift_shallow(b, -v);
    3989           0 :     else if (v > 0) {
    3990           0 :       if (typ(a) != t_POL || varn(a) != vx) a = scalarpol_shallow(a, vx);
    3991           0 :       a = RgX_shift_shallow(a, v);
    3992             :     }
    3993          14 :     t = mkrfraccopy(a, b);
    3994             :   }
    3995          77 :   return t;
    3996             : }
    3997             : static GEN
    3998          42 : gc_empty(pari_sp av) { retgc_const(av, cgetg(1, t_VEC)); }
    3999             : static GEN
    4000         112 : _gc_upto(pari_sp av, GEN x) { return x? gc_upto(av, x): NULL; }
    4001             : 
    4002             : static GEN bestappr_RgX(GEN x, long B);
    4003             : /* B >= 0 or < 0 [omit condition on B].
    4004             :  * Look for coprime t_POL a,b, deg(b)<=B, such that a/b ~ x */
    4005             : static GEN
    4006         119 : bestappr_RgX(GEN x, long B)
    4007             : {
    4008             :   pari_sp av;
    4009         119 :   switch(typ(x))
    4010             :   {
    4011           0 :     case t_INT: case t_REAL: case t_INTMOD: case t_FRAC: case t_FFELT:
    4012             :     case t_COMPLEX: case t_PADIC: case t_QUAD: case t_POL:
    4013           0 :       return gcopy(x);
    4014          14 :     case t_RFRAC:
    4015          14 :       if (B < 0 || degpol(gel(x,2)) <= B) return gcopy(x);
    4016           7 :       av = avma; return _gc_upto(av, bestappr_ser(rfrac_to_ser_i(x, 2*B+1), B));
    4017          14 :     case t_POLMOD:
    4018          14 :       av = avma; return _gc_upto(av, mod_to_rfrac(gel(x,2), gel(x,1), B));
    4019          91 :     case t_SER:
    4020          91 :       av = avma; return _gc_upto(av, bestappr_ser(x, B));
    4021           0 :     case t_VEC: case t_COL: case t_MAT: {
    4022             :       long i, lx;
    4023           0 :       GEN y = cgetg_copy(x, &lx);
    4024           0 :       for (i = 1; i < lx; i++)
    4025             :       {
    4026           0 :         GEN t = bestappr_RgX(gel(x,i),B); if (!t) return NULL;
    4027           0 :         gel(y,i) = t;
    4028             :       }
    4029           0 :       return y;
    4030             :     }
    4031             :   }
    4032           0 :   pari_err_TYPE("bestappr_RgX",x);
    4033             :   return NULL; /* LCOV_EXCL_LINE */
    4034             : }
    4035             : 
    4036             : /* allow k = NULL: maximal accuracy */
    4037             : GEN
    4038      104848 : bestappr(GEN x, GEN k)
    4039             : {
    4040      104848 :   pari_sp av = avma;
    4041      104848 :   if (k) { /* replace by floor(k) */
    4042      104526 :     switch(typ(k))
    4043             :     {
    4044       33026 :       case t_INT:
    4045       33026 :         break;
    4046       71500 :       case t_REAL: case t_FRAC:
    4047       71500 :         k = floor_safe(k); /* left on stack for efficiency */
    4048       71499 :         if (!signe(k)) k = gen_1;
    4049       71499 :         break;
    4050           0 :       default:
    4051           0 :         pari_err_TYPE("bestappr [bound type]", k);
    4052           0 :         break;
    4053             :     }
    4054             :   }
    4055      104847 :   x = bestappr_Q(x, k);
    4056      104847 :   return x? x: gc_empty(av);
    4057             : }
    4058             : GEN
    4059         119 : bestapprPade(GEN x, long B)
    4060             : {
    4061         119 :   pari_sp av = avma;
    4062         119 :   GEN t = bestappr_RgX(x, B);
    4063         119 :   return t? t: gc_empty(av);
    4064             : }
    4065             : 
    4066             : static GEN
    4067          49 : serPade(GEN S, long p, long q)
    4068             : {
    4069          49 :   pari_sp av = avma;
    4070          49 :   long va, v, t = typ(S);
    4071          49 :   if (t!=t_SER && t!=t_POL && t!=t_RFRAC) pari_err_TYPE("bestapprPade", S);
    4072          49 :   va = gvar(S); v = gvaluation(S, pol_x(va));
    4073          49 :   if (p < 0) pari_err_DOMAIN("bestapprPade", "p", "<", gen_0, stoi(p));
    4074          49 :   if (q < 0) pari_err_DOMAIN("bestapprPade", "q", "<", gen_0, stoi(q));
    4075          49 :   if (v == LONG_MAX) return gc_empty(av);
    4076          42 :   S = gadd(S, zeroser(va, p + q + 1 + v));
    4077          42 :   return gc_upto(av, bestapprPade(S, q));
    4078             : }
    4079             : 
    4080             : GEN
    4081         126 : bestapprPade0(GEN x, long p, long q)
    4082             : {
    4083          77 :   return (p >= 0 && q >= 0)? serPade(x, p, q)
    4084         203 :                            : bestapprPade(x, p >= 0? p: q);
    4085             : }

Generated by: LCOV version 1.16