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 - ispower.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 29875-1c62f24b5e) Lines: 629 665 94.6 %
Date: 2025-01-17 09:09:20 Functions: 34 36 94.4 %
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             : #include "pari.h"
      16             : #include "paripriv.h"
      17             : /*********************************************************************/
      18             : /**                      PERFECT POWERS                             **/
      19             : /*********************************************************************/
      20             : #define DEBUGLEVEL DEBUGLEVEL_arith
      21             : 
      22             : /*********************************************************************/
      23             : /**                     INTEGRAL LOGARITHM                          **/
      24             : /*********************************************************************/
      25             : /* y > 1 and B > 0 integers. Return e such that y^e <= B < y^(e+1), i.e
      26             :  * e = floor(log_y B). Set *ptq = y^e if non-NULL */
      27             : long
      28      833184 : ulogintall(ulong B, ulong y, ulong *ptq)
      29             : {
      30             :   ulong r, r2;
      31             :   long e;
      32             : 
      33      833184 :   if (y == 2)
      34             :   {
      35       23070 :     long eB = expu(B); /* 2^eB <= B < 2^(eB + 1) */
      36       23070 :     if (ptq) *ptq = 1UL << eB;
      37       23070 :     return eB;
      38             :   }
      39      810114 :   r = y, r2 = 1UL;
      40     2936703 :   for (e=1;; e++)
      41             :   { /* here, r = y^e, r2 = y^(e-1) */
      42     2936703 :     if (r >= B)
      43             :     {
      44      808296 :       if (r != B) { e--; r = r2; }
      45      808296 :       if (ptq) *ptq = r;
      46      808296 :       return e;
      47             :     }
      48     2128407 :     r2 = r;
      49     2128407 :     r = umuluu_or_0(y, r);
      50     2128445 :     if (!r)
      51             :     {
      52        1856 :       if (ptq) *ptq = r2;
      53        1856 :       return e;
      54             :     }
      55             :   }
      56             : }
      57             : 
      58             : /* y > 1 and B > 0 integers. Return e such that y^e <= B < y^(e+1), i.e
      59             :  * e = floor(log_y B). Set *ptq = y^e if non-NULL */
      60             : long
      61      934108 : logintall(GEN B, GEN y, GEN *ptq)
      62             : {
      63             :   pari_sp av;
      64      934108 :   long ey, e, emax, i, eB = expi(B); /* 2^eB <= B < 2^(eB + 1) */
      65             :   GEN q, pow2;
      66             : 
      67      934108 :   if (lgefint(B) == 3)
      68             :   {
      69             :     ulong q;
      70      832034 :     if (lgefint(y) > 3)
      71             :     {
      72           0 :       if (ptq) *ptq = gen_1;
      73           0 :       return 0;
      74             :     }
      75      832034 :     if (!ptq) return ulogintall(B[2], y[2], NULL);
      76      127408 :     e = ulogintall(B[2], y[2], &q);
      77      127410 :     *ptq = utoi(q); return e;
      78             :   }
      79      102074 :   if (equaliu(y,2))
      80             :   {
      81         888 :     if (ptq) *ptq = int2n(eB);
      82         888 :     return eB;
      83             :   }
      84      101198 :   av = avma;
      85      101198 :   ey = expi(y);
      86             :   /* eB/(ey+1) - 1 < e <= eB/ey */
      87      101199 :   emax = eB/ey;
      88      101199 :   if (emax <= 13) /* e small, be naive */
      89             :   {
      90       10905 :     GEN r = y, r2 = gen_1;
      91       10905 :     for (e=1;; e++)
      92      105419 :     { /* here, r = y^e, r2 = y^(e-1) */
      93      116324 :       long fl = cmpii(r, B);
      94      116324 :       if (fl >= 0)
      95             :       {
      96       10905 :         if (fl) { e--; cgiv(r); r = r2; }
      97       10905 :         if (ptq) *ptq = gerepileuptoint(av, r); else set_avma(av);
      98       10905 :         return e;
      99             :       }
     100      105419 :       r2 = r; r = mulii(r,y);
     101             :     }
     102             :   }
     103             :   /* e >= 13 ey / (ey+1) >= 6.5 */
     104             : 
     105             :   /* binary splitting: compute bits of e one by one */
     106             :   /* compute pow2[i] = y^(2^i) [i < crude upper bound for log_2 log_y(B)] */
     107       90294 :   pow2 = new_chunk((long)log2(eB)+2);
     108       90294 :   gel(pow2,0) = y;
     109       90294 :   for (i=0, q=y;; )
     110      422909 :   {
     111      513203 :     GEN r = gel(pow2,i); /* r = y^2^i */
     112      513203 :     long fl = cmpii(r,B);
     113      513179 :     if (!fl)
     114             :     {
     115           0 :       e = 1L<<i;
     116           0 :       if (ptq) *ptq = gerepileuptoint(av, r); else set_avma(av);
     117           0 :       return e;
     118             :     }
     119      513179 :     if (fl > 0) { i--; break; }
     120      481551 :     q = r;
     121      481551 :     if (1L<<(i+1) > emax) break;
     122      422886 :     gel(pow2,++i) = sqri(q);
     123             :   }
     124             : 
     125       90293 :   for (e = 1L<<i;;)
     126      391267 :   { /* y^e = q < B < r = q * y^(2^i) */
     127      481560 :     pari_sp av2 = avma;
     128             :     long fl;
     129             :     GEN r;
     130      481560 :     if (--i < 0) break;
     131      391277 :     r = mulii(q, gel(pow2,i));
     132      391281 :     fl = cmpii(r, B);
     133      391295 :     if (fl > 0) set_avma(av2);
     134             :     else
     135             :     {
     136      175970 :       e += (1L<<i);
     137      175970 :       q = r;
     138      175970 :       if (!fl) break; /* B = r */
     139             :     }
     140             :   }
     141       90290 :   if (ptq) *ptq = gerepileuptoint(av, q); else set_avma(av);
     142       90290 :   return e;
     143             : }
     144             : 
     145             : long
     146       26189 : logint0(GEN B, GEN y, GEN *ptq)
     147             : {
     148       26189 :   const char *f = "logint";
     149       26189 :   if (typ(y) != t_INT) pari_err_TYPE(f,y);
     150       26189 :   if (cmpis(y, 2) < 0) pari_err_DOMAIN(f, "b" ,"<=", gen_1, y);
     151       26189 :   if (typ(B) != t_INT)
     152             :   {
     153          77 :     pari_sp av = avma;
     154             :     long a;
     155          77 :     if (typ(B) == t_REAL)
     156             :     {
     157             :       long e, p;
     158          35 :       if (cmprs(B, 1) < 1) pari_err_DOMAIN(f, "x", "<", gen_1, B);
     159          28 :       e = expo(B); if (e < 0) return 0;
     160          28 :       if (equaliu(y, 2)) return e;
     161          14 :       if (expu(e) < 50)
     162             :       {
     163          14 :         a = floor(dbllog2(B) / dbllog2(y));
     164          14 :         if (ptq) *ptq = powiu(y, a);
     165          14 :         return a;
     166             :       }
     167             :       /* play safe */
     168           0 :       p = lg(B);
     169           0 :       if (nbits2lg(e+1) > p)
     170             :       { /* try to avoid precision loss in truncation */
     171           0 :         if (p > DEFAULTPREC) { p = DEFAULTPREC; B = rtor(B, p); }
     172           0 :         a = itos(floorr(divrr(logr_abs(B), logr_abs(itor(y, p)))));
     173           0 :         set_avma(av); if (ptq) *ptq = powiu(y, a);
     174           0 :         return a;
     175             :       }
     176           0 :       a = logintall(truncr(B), y, ptq);
     177             :     }
     178             :     else
     179             :     {
     180          42 :       GEN b = gfloor(B);
     181          42 :       if (typ(b) != t_INT) pari_err_TYPE(f,B);
     182          42 :       if (signe(b) <= 0) pari_err_DOMAIN(f, "x", "<", gen_1, B);
     183          28 :       a = logintall(b, y, ptq);
     184             :     }
     185          28 :     if (!ptq) return gc_long(av, a);
     186          14 :     *ptq = gerepileuptoint(av, *ptq); return a;
     187             :   }
     188       26112 :   if (signe(B) <= 0) pari_err_DOMAIN(f, "x" ,"<=", gen_0, B);
     189       26112 :   return logintall(B,y,ptq);
     190             : }
     191             : 
     192             : /*********************************************************************/
     193             : /**                     INTEGRAL SQUARE ROOT                        **/
     194             : /*********************************************************************/
     195             : GEN
     196       88429 : sqrtint(GEN a)
     197             : {
     198       88429 :   if (typ(a) != t_INT)
     199             :   {
     200          56 :     pari_sp av = avma;
     201          56 :     if (typ(a) == t_REAL)
     202             :     {
     203             :       long e;
     204          28 :       switch(signe(a))
     205             :       {
     206           0 :         case 0: return gen_0;
     207           7 :         case -1: pari_err_DOMAIN("sqrtint", "argument", "<", gen_0,a);
     208             :       }
     209          21 :       e = expo(a); if (e < 0) return gen_0;
     210          21 :       if (nbits2lg(e+1) > lg(a))
     211          14 :         a = floorr(sqrtr(a)); /* try to avoid precision loss in truncation */
     212             :       else
     213           7 :         a = sqrti(truncr(a));
     214             :     }
     215             :     else
     216             :     {
     217          28 :       GEN b = gfloor(a);
     218          28 :       if (typ(b) != t_INT) pari_err_TYPE("sqrtint",a);
     219          21 :       if (signe(b) < 0) pari_err_DOMAIN("sqrtint", "argument", "<", gen_0,a);
     220          14 :       a = sqrti(b);
     221             :     }
     222          28 :     return gerepileuptoleaf(av, a);
     223             :   }
     224       88373 :   switch (signe(a))
     225             :   {
     226       88352 :     case 1: return sqrti(a);
     227           7 :     case 0: return gen_0;
     228          14 :     default: pari_err_DOMAIN("sqrtint", "argument", "<", gen_0,a);
     229             :   }
     230             :   return NULL; /* LCOV_EXCL_LINE */
     231             : }
     232             : GEN
     233         119 : sqrtint0(GEN a, GEN *r)
     234             : {
     235         119 :   if (!r) return sqrtint(a);
     236          49 :   if (typ(a) != t_INT)
     237             :   {
     238          28 :     GEN b = sqrtint(a);
     239          28 :     pari_sp av = avma;
     240          28 :     *r = gerepileupto(av, gsub(a, sqri(b))); return b;
     241             :   }
     242          21 :   switch (signe(a))
     243             :   {
     244          14 :     case 1: return sqrtremi(a, r);
     245           7 :     case 0: *r = gen_0; return gen_0;
     246           0 :     default: pari_err_DOMAIN("sqrtint", "argument", "<", gen_0,a);
     247             :   }
     248             :   return NULL; /* LCOV_EXCL_LINE */
     249             : }
     250             : 
     251             : /*********************************************************************/
     252             : /**                      PERFECT SQUARE                             **/
     253             : /*********************************************************************/
     254             : static int
     255    14327240 : squaremod(ulong A)
     256             : {
     257    14327240 :   const int squaremod64[]={
     258             :     1,1,0,0,1,0,0,0,0,1, 0,0,0,0,0,0,1,1,0,0, 0,0,0,0,0,1,0,0,0,0,
     259             :     0,0,0,1,0,0,1,0,0,0, 0,1,0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,1,0,0, 0,0,0,0};
     260    14327240 :   const int squaremod63[]={
     261             :     1,1,0,0,1,0,0,1,0,1, 0,0,0,0,0,0,1,0,1,0, 0,0,1,0,0,1,0,0,1,0,
     262             :     0,0,0,0,0,0,1,1,0,0, 0,0,0,1,0,0,1,0,0,1, 0,0,0,0,0,0,0,0,1,0, 0,0,0};
     263    14327240 :   const int squaremod65[]={
     264             :     1,1,0,0,1,0,0,0,0,1, 1,0,0,0,1,0,1,0,0,0, 0,0,0,0,0,1,1,0,0,1,
     265             :     1,0,0,0,0,1,1,0,0,1, 1,0,0,0,0,0,0,0,0,1, 0,1,0,0,0,1,1,0,0,0, 0,1,0,0,1};
     266    14327240 :   const int squaremod11[]={1,1,0,1,1,1,0,0,0,1, 0};
     267    14327240 :   return (squaremod64[A & 0x3fUL]
     268     6760235 :     && squaremod63[A % 63UL]
     269     4706373 :     && squaremod65[A % 65UL]
     270    21087475 :     && squaremod11[A % 11UL]);
     271             : }
     272             : 
     273             : /* emulate Z_issquareall on single-word integers */
     274             : long
     275    10689342 : uissquareall(ulong A, ulong *sqrtA)
     276             : {
     277    10689342 :   if (!A) { *sqrtA = 0; return 1; }
     278    10689342 :   if (squaremod(A))
     279             :   {
     280     1936874 :     ulong a = usqrt(A);
     281     1936867 :     if (a * a == A) { *sqrtA = a; return 1; }
     282             :   }
     283     8784662 :   return 0;
     284             : }
     285             : long
     286      274831 : uissquare(ulong A)
     287             : {
     288      274831 :   if (!A) return 1;
     289      274831 :   if (squaremod(A)) { ulong a = usqrt(A); if (a * a == A) return 1; }
     290      265038 :   return 0;
     291             : }
     292             : 
     293             : long
     294     6681695 : Z_issquareall(GEN x, GEN *pt)
     295             : {
     296             :   pari_sp av;
     297             :   GEN y, r;
     298             : 
     299     6681695 :   switch(signe(x))
     300             :   {
     301      181019 :     case -1: return 0;
     302        1813 :     case 0: if (pt) *pt=gen_0; return 1;
     303             :   }
     304     6498863 :   if (lgefint(x) == 3)
     305             :   {
     306     3135803 :     ulong u = uel(x,2), a;
     307     3135803 :     if (!pt) return uissquare(u);
     308     2860972 :     if (!uissquareall(u, &a)) return 0;
     309     1476669 :     *pt = utoipos(a); return 1;
     310             :   }
     311     3363060 :   if (!squaremod(umodiu(x, 64*63*65*11))) return 0;
     312     2211950 :   av = avma; y = sqrtremi(x, &r);
     313     2211950 :   if (r != gen_0) return gc_long(av,0);
     314       41269 :   if (pt) { *pt = y; set_avma((pari_sp)y); } else set_avma(av);
     315       41269 :   return 1;
     316             : }
     317             : 
     318             : /* a t_INT, p prime */
     319             : long
     320      111180 : Zp_issquare(GEN a, GEN p)
     321             : {
     322             :   long v;
     323             :   GEN ap;
     324             : 
     325      111180 :   if (!signe(a) || equali1(a)) return 1;
     326      111180 :   v = Z_pvalrem(a, p, &ap);
     327      111180 :   if (v&1) return 0;
     328       63425 :   return absequaliu(p, 2)? Mod8(ap) == 1
     329       63425 :                          : kronecker(ap,p) == 1;
     330             : }
     331             : 
     332             : static long
     333        3780 : polissquareall(GEN x, GEN *pt)
     334             : {
     335             :   pari_sp av;
     336             :   long v;
     337             :   GEN y, a, b, p;
     338             : 
     339        3780 :   if (!signe(x))
     340             :   {
     341           7 :     if (pt) *pt = gcopy(x);
     342           7 :     return 1;
     343             :   }
     344        3773 :   if (odd(degpol(x))) return 0; /* odd degree */
     345        3773 :   av = avma;
     346        3773 :   v = RgX_valrem(x, &x);
     347        3773 :   if (v & 1) return gc_long(av,0);
     348        3766 :   a = gel(x,2); /* test constant coeff */
     349        3766 :   if (!pt)
     350          63 :   { if (!issquare(a)) return gc_long(av,0); }
     351             :   else
     352        3703 :   { if (!issquareall(a,&b)) return gc_long(av,0); }
     353        3766 :   if (!degpol(x)) { /* constant polynomial */
     354          63 :     if (!pt) return gc_long(av,1);
     355          28 :     y = scalarpol(b, varn(x)); goto END;
     356             :   }
     357        3703 :   p = characteristic(x);
     358        3703 :   if (signe(p) && !mod2(p))
     359             :   {
     360             :     long i, lx;
     361          35 :     if (!absequaliu(p,2)) pari_err_IMPL("issquare for even characteristic != 2");
     362          28 :     x = gmul(x, mkintmod(gen_1, gen_2));
     363          28 :     lx = lg(x);
     364          28 :     if ((lx-3) & 1) return gc_long(av,0);
     365          49 :     for (i = 3; i < lx; i+=2)
     366          28 :       if (!gequal0(gel(x,i))) return gc_long(av,0);
     367          21 :     if (pt) {
     368          14 :       y = cgetg((lx+3) / 2, t_POL);
     369          49 :       for (i = 2; i < lx; i+=2)
     370          35 :         if (!issquareall(gel(x,i), &gel(y, (i+2)>>1))) return gc_long(av,0);
     371          14 :       y[1] = evalsigne(1) | evalvarn(varn(x));
     372          14 :       goto END;
     373             :     } else {
     374          21 :       for (i = 2; i < lx; i+=2)
     375          14 :         if (!issquare(gel(x,i))) return gc_long(av,0);
     376           7 :       return gc_long(av,1);
     377             :     }
     378             :   }
     379             :   else
     380             :   {
     381        3668 :     long m = 1;
     382        3668 :     x = RgX_Rg_div(x,a);
     383             :     /* a(x^m) = B^2 => B = b(x^m) provided a(0) != 0 */
     384        3668 :     if (!signe(p)) x = RgX_deflate_max(x,&m);
     385        3668 :     y = ser2rfrac_i(gsqrt(RgX_to_ser(x,lg(x)-1),0));
     386        3675 :     if (!RgX_equal(RgX_sqr(y), x)) return gc_long(av,0);
     387        3661 :     if (!pt) return gc_long(av,1);
     388        3654 :     if (!gequal1(a)) y = gmul(b, y);
     389        3654 :     if (m != 1) y = RgX_inflate(y,m);
     390             :   }
     391        3696 : END:
     392        3696 :   if (v) y = RgX_shift_shallow(y, v>>1);
     393        3696 :   *pt = gerepilecopy(av, y); return 1;
     394             : }
     395             : 
     396             : static long
     397          56 : polmodispower(GEN x, GEN K, GEN *pt)
     398             : {
     399          56 :   pari_sp av = avma;
     400          56 :   GEN p = NULL, T = NULL;
     401          56 :   if (Rg_is_FpXQ(x, &T,&p) && p)
     402             :   {
     403          42 :     x = liftall_shallow(x);
     404          42 :     if (T) T = liftall_shallow(T);
     405          42 :     if (!Fq_ispower(x, K, T, p)) return gc_long(av,0);
     406          28 :     if (!pt) return gc_long(av,1);
     407          21 :     x = Fq_sqrtn(x, K, T,p, NULL);
     408          21 :     if (typ(x) == t_INT)
     409           7 :       x = Fp_to_mod(x,p);
     410             :     else
     411          14 :       x = mkpolmod(FpX_to_mod(x,p), FpX_to_mod(T,p));
     412          21 :     *pt = gerepilecopy(av, x); return 1;
     413             :   }
     414          14 :   pari_err_IMPL("ispower for general t_POLMOD");
     415           0 :   return 0;
     416             : }
     417             : static long
     418          56 : rfracispower(GEN x, GEN K, GEN *pt)
     419             : {
     420          56 :   pari_sp av = avma;
     421          56 :   GEN n = gel(x,1), d = gel(x,2);
     422          56 :   long v = -RgX_valrem(d, &d), vx = varn(d);
     423          56 :   if (typ(n) == t_POL && varn(n) == vx) v += RgX_valrem(n, &n);
     424          56 :   if (!dvdsi(v, K)) return gc_long(av, 0);
     425          49 :   if (lg(d) >= 3)
     426             :   {
     427          49 :     GEN a = gel(d,2); /* constant term */
     428          49 :     if (!gequal1(a)) { d = RgX_Rg_div(d, a); n = gdiv(n, a); }
     429             :   }
     430          49 :   if (!ispower(d, K, pt? &d: NULL) || !ispower(n, K, pt? &n: NULL))
     431           0 :     return gc_long(av, 0);
     432          49 :   if (!pt) return gc_long(av, 1);
     433          28 :   x = gdiv(n, d);
     434          28 :   if (v) x = gmul(x, monomial(gen_1, v / itos(K), vx));
     435          28 :   *pt = gerepileupto(av, x); return 1;
     436             : }
     437             : long
     438      252275 : issquareall(GEN x, GEN *pt)
     439             : {
     440      252275 :   long tx = typ(x);
     441             :   GEN F;
     442             :   pari_sp av;
     443             : 
     444      252275 :   if (!pt) return issquare(x);
     445       38093 :   switch(tx)
     446             :   {
     447       17506 :     case t_INT: return Z_issquareall(x, pt);
     448        1939 :     case t_FRAC: av = avma;
     449        1939 :       F = cgetg(3, t_FRAC);
     450        1939 :       if (   !Z_issquareall(gel(x,1), &gel(F,1))
     451        1939 :           || !Z_issquareall(gel(x,2), &gel(F,2))) return gc_long(av,0);
     452        1876 :       *pt = F; return 1;
     453             : 
     454          21 :     case t_POLMOD:
     455          21 :       return polmodispower(x, gen_2, pt);
     456        3710 :     case t_POL: return polissquareall(x,pt);
     457          21 :     case t_RFRAC: return rfracispower(x, gen_2, pt);
     458             : 
     459       14791 :     case t_REAL: case t_COMPLEX: case t_PADIC: case t_SER:
     460       14791 :       if (!issquare(x)) return 0;
     461       14791 :       *pt = gsqrt(x, DEFAULTPREC); return 1;
     462             : 
     463          63 :     case t_INTMOD:
     464          63 :       return Zn_ispower(gel(x,2), gel(x,1), gen_2, pt);
     465             : 
     466          42 :     case t_FFELT: return FF_issquareall(x, pt);
     467             : 
     468             :   }
     469           0 :   pari_err_TYPE("issquareall",x);
     470             :   return 0; /* LCOV_EXCL_LINE */
     471             : }
     472             : 
     473             : long
     474      229267 : issquare(GEN x)
     475             : {
     476             :   GEN a, p;
     477             :   long v;
     478             : 
     479      229267 :   switch(typ(x))
     480             :   {
     481      214077 :     case t_INT:
     482      214077 :       return Z_issquare(x);
     483             : 
     484       14721 :     case t_REAL:
     485       14721 :       return (signe(x)>=0);
     486             : 
     487          84 :     case t_INTMOD:
     488          84 :       return Zn_ispower(gel(x,2), gel(x,1), gen_2, NULL);
     489             : 
     490          35 :     case t_FRAC:
     491          35 :       return Z_issquare(gel(x,1)) && Z_issquare(gel(x,2));
     492             : 
     493           7 :     case t_FFELT: return FF_issquareall(x, NULL);
     494             : 
     495          56 :     case t_COMPLEX:
     496          56 :       return 1;
     497             : 
     498         133 :     case t_PADIC:
     499         133 :       a = gel(x,4); if (!signe(a)) return 1;
     500         133 :       if (valp(x)&1) return 0;
     501         119 :       p = gel(x,2);
     502         119 :       if (!absequaliu(p, 2)) return (kronecker(a,p) != -1);
     503             : 
     504          42 :       v = precp(x); /* here p=2, a is odd */
     505          42 :       if ((v>=3 && mod8(a) != 1 ) ||
     506          21 :           (v==2 && mod4(a) != 1)) return 0;
     507          21 :       return 1;
     508             : 
     509          21 :     case t_POLMOD:
     510          21 :       return polmodispower(x, gen_2, NULL);
     511             : 
     512          70 :     case t_POL:
     513          70 :       return polissquareall(x,NULL);
     514             : 
     515          49 :     case t_SER:
     516          49 :       if (!signe(x)) return 1;
     517          42 :       if (valser(x)&1) return 0;
     518          35 :       return issquare(gel(x,2));
     519             : 
     520          14 :     case t_RFRAC:
     521          14 :       return rfracispower(x, gen_2, NULL);
     522             :   }
     523           0 :   pari_err_TYPE("issquare",x);
     524             :   return 0; /* LCOV_EXCL_LINE */
     525             : }
     526           0 : GEN gissquare(GEN x) { return issquare(x)? gen_1: gen_0; }
     527           0 : GEN gissquareall(GEN x, GEN *pt) { return issquareall(x,pt)? gen_1: gen_0; }
     528             : 
     529             : long
     530        1386 : ispolygonal(GEN x, GEN S, GEN *N)
     531             : {
     532        1386 :   pari_sp av = avma;
     533             :   GEN D, d, n;
     534        1386 :   if (typ(x) != t_INT) pari_err_TYPE("ispolygonal", x);
     535        1386 :   if (typ(S) != t_INT) pari_err_TYPE("ispolygonal", S);
     536        1386 :   if (abscmpiu(S,3) < 0) pari_err_DOMAIN("ispolygonal","s","<", utoipos(3),S);
     537        1386 :   if (signe(x) < 0) return 0;
     538        1386 :   if (signe(x) == 0) { if (N) *N = gen_0; return 1; }
     539        1260 :   if (is_pm1(x)) { if (N) *N = gen_1; return 1; }
     540             :   /* n = (sqrt( (8s - 16) x + (s-4)^2 ) + s - 4) / 2(s - 2) */
     541        1134 :   if (abscmpiu(S, 1<<16) < 0) /* common case ! */
     542             :   {
     543         441 :     ulong s = S[2], r;
     544         441 :     if (s == 4) return Z_issquareall(x, N);
     545         378 :     if (s == 3)
     546           0 :       D = addiu(shifti(x, 3), 1);
     547             :     else
     548         378 :       D = addiu(mului(8*s - 16, x), (s-4)*(s-4));
     549         378 :     if (!Z_issquareall(D, &d)) return gc_long(av,0);
     550         378 :     if (s == 3)
     551           0 :       d = subiu(d, 1);
     552             :     else
     553         378 :       d = addiu(d, s - 4);
     554         378 :     n = absdiviu_rem(d, 2*s - 4, &r);
     555         378 :     if (r) return gc_long(av,0);
     556             :   }
     557             :   else
     558             :   {
     559         693 :     GEN r, S_2 = subiu(S,2), S_4 = subiu(S,4);
     560         693 :     D = addii(mulii(shifti(S_2,3), x), sqri(S_4));
     561         693 :     if (!Z_issquareall(D, &d)) return gc_long(av,0);
     562         693 :     d = addii(d, S_4);
     563         693 :     n = dvmdii(shifti(d,-1), S_2, &r);
     564         693 :     if (r != gen_0) return gc_long(av,0);
     565             :   }
     566        1071 :   if (N) *N = gerepileuptoint(av, n); else set_avma(av);
     567        1071 :   return 1;
     568             : }
     569             : 
     570             : /*********************************************************************/
     571             : /**                        PERFECT POWER                            **/
     572             : /*********************************************************************/
     573             : static long
     574         987 : polispower(GEN x, GEN K, GEN *pt)
     575             : {
     576             :   pari_sp av;
     577         987 :   long v, d, k = itos(K);
     578             :   GEN y, a, b;
     579         987 :   GEN T = NULL, p = NULL;
     580             : 
     581         987 :   if (!signe(x))
     582             :   {
     583           7 :     if (pt) *pt = gcopy(x);
     584           7 :     return 1;
     585             :   }
     586         980 :   d = degpol(x);
     587         980 :   if (d % k) return 0; /* degree not multiple of k */
     588         973 :   av = avma;
     589         973 :   if (RgX_is_FpXQX(x, &T, &p) && p)
     590             :   { /* over Fq */
     591         336 :     if (T && typ(T) == t_FFELT)
     592             :     {
     593         126 :       if (!FFX_ispower(x, k, T, pt)) return gc_long(av,0);
     594         105 :       return 1;
     595             :     }
     596         210 :     x = RgX_to_FqX(x,T,p);
     597         210 :     if (!FqX_ispower(x, k, T,p, pt)) return gc_long(av,0);
     598         175 :     if (pt) *pt = gerepileupto(av, FqX_to_mod(*pt, T, p));
     599         175 :     return 1;
     600             :   }
     601         637 :   v = RgX_valrem(x, &x);
     602         637 :   if (v % k) return 0;
     603         630 :   v /= k;
     604         630 :   a = gel(x,2); b = NULL;
     605         630 :   if (!ispower(a, K, &b)) return gc_long(av,0);
     606         616 :   if (d)
     607             :   {
     608         588 :     GEN p = characteristic(x);
     609         588 :     a = leading_coeff(x);
     610         588 :     if (!ispower(a, K, &b)) return gc_long(av,0);
     611         588 :     x = RgX_normalize(x);
     612         588 :     if (signe(p) && cmpii(p,K) <= 0)
     613           0 :       pari_err_IMPL("ispower(general t_POL) in small characteristic");
     614         588 :     y = gtrunc(gsqrtn(RgX_to_ser(x,lg(x)), K, NULL, 0));
     615         588 :     if (!RgX_equal(powgi(y, K), x)) return gc_long(av,0);
     616             :   }
     617             :   else
     618          28 :     y = pol_1(varn(x));
     619         616 :   if (pt)
     620             :   {
     621         581 :     if (!gequal1(a))
     622             :     {
     623          35 :       if (!b) b = gsqrtn(a, K, NULL, DEFAULTPREC);
     624          35 :       y = gmul(b,y);
     625             :     }
     626         581 :     if (v) y = RgX_shift_shallow(y, v);
     627         581 :     *pt = gerepilecopy(av, y);
     628             :   }
     629          35 :   else set_avma(av);
     630         616 :   return 1;
     631             : }
     632             : 
     633             : long
     634     1559328 : Z_ispowerall(GEN x, ulong k, GEN *pt)
     635             : {
     636     1559328 :   long s = signe(x);
     637             :   ulong mask;
     638     1559328 :   if (!s) { if (pt) *pt = gen_0; return 1; }
     639     1559328 :   if (s > 0) {
     640     1558999 :     if (k == 2) return Z_issquareall(x, pt);
     641     1425582 :     if (k == 3) { mask = 1; return !!is_357_power(x, pt, &mask); }
     642      227878 :     if (k == 5) { mask = 2; return !!is_357_power(x, pt, &mask); }
     643       60305 :     if (k == 7) { mask = 4; return !!is_357_power(x, pt, &mask); }
     644       54187 :     return is_kth_power(x, k, pt);
     645             :   }
     646         329 :   if (!odd(k)) return 0;
     647         140 :   if (Z_ispowerall(absi_shallow(x), k, pt))
     648             :   {
     649         126 :     if (pt) *pt = negi(*pt);
     650         126 :     return 1;
     651             :   };
     652          14 :   return 0;
     653             : }
     654             : 
     655             : /* is x a K-th power mod p ? Assume p prime. */
     656             : int
     657         567 : Fp_ispower(GEN x, GEN K, GEN p)
     658             : {
     659         567 :   pari_sp av = avma;
     660             :   GEN p_1;
     661         567 :   x = modii(x, p);
     662         567 :   if (!signe(x) || equali1(x)) return gc_bool(av,1);
     663             :   /* implies p > 2 */
     664         126 :   p_1 = subiu(p,1);
     665         126 :   K = gcdii(K, p_1);
     666         126 :   if (absequaliu(K, 2)) return gc_bool(av, kronecker(x,p) > 0);
     667          49 :   x = Fp_pow(x, diviiexact(p_1,K), p);
     668          49 :   return gc_bool(av, equali1(x));
     669             : }
     670             : 
     671             : /* x unit defined modulo 2^e, e > 0, p prime */
     672             : static int
     673        2541 : U2_issquare(GEN x, long e)
     674             : {
     675        2541 :   long r = signe(x)>=0?mod8(x):8-mod8(x);
     676        2541 :   if (e==1) return 1;
     677        2541 :   if (e==2) return (r&3L) == 1;
     678        2009 :   return r == 1;
     679             : }
     680             : /* x unit defined modulo p^e, e > 0, p prime */
     681             : static int
     682        5229 : Up_issquare(GEN x, GEN p, long e)
     683        5229 : { return (absequaliu(p,2))? U2_issquare(x, e): kronecker(x,p)==1; }
     684             : 
     685             : long
     686        2793 : Zn_issquare(GEN d, GEN fn)
     687             : {
     688             :   long j, np;
     689        2793 :   if (typ(d) != t_INT) pari_err_TYPE("Zn_issquare",d);
     690        2793 :   if (typ(fn) == t_INT) return Zn_ispower(d, fn, gen_2, NULL);
     691             :   /* integer factorization */
     692        2793 :   np = nbrows(fn);
     693        6006 :   for (j = 1; j <= np; ++j)
     694             :   {
     695        5586 :     GEN  r, p = gcoeff(fn, j, 1);
     696        5586 :     long e = itos(gcoeff(fn, j, 2));
     697        5586 :     long v = Z_pvalrem(d,p,&r);
     698        5586 :     if (v < e && (odd(v) || !Up_issquare(r, p, e-v))) return 0;
     699             :   }
     700         420 :   return 1;
     701             : }
     702             : 
     703             : static long
     704        1113 : Qp_ispower(GEN x, GEN K, GEN *pt)
     705             : {
     706        1113 :   pari_sp av = avma;
     707        1113 :   GEN z = Qp_sqrtn(x, K, NULL);
     708        1113 :   if (!z) return gc_long(av,0);
     709         819 :   if (pt) *pt = z;
     710         819 :   return 1;
     711             : }
     712             : 
     713             : long
     714     8556102 : ispower(GEN x, GEN K, GEN *pt)
     715             : {
     716             :   GEN z;
     717             : 
     718     8556102 :   if (!K) return gisanypower(x, pt);
     719     1555920 :   if (typ(K) != t_INT) pari_err_TYPE("ispower",K);
     720     1555920 :   if (signe(K) <= 0) pari_err_DOMAIN("ispower","exponent","<=",gen_0,K);
     721     1555920 :   if (equali1(K)) { if (pt) *pt = gcopy(x); return 1; }
     722     1555857 :   switch(typ(x)) {
     723     1482880 :     case t_INT:
     724     1482880 :       if (lgefint(K) != 3) return 0;
     725     1482824 :       return Z_ispowerall(x, itou(K), pt);
     726       70184 :     case t_FRAC:
     727             :     {
     728       70184 :       GEN a = gel(x,1), b = gel(x,2);
     729             :       ulong k;
     730       70184 :       if (lgefint(K) != 3) return 0;
     731       70177 :       k = itou(K);
     732       70177 :       if (pt) {
     733       70114 :         z = cgetg(3, t_FRAC);
     734       70114 :         if (Z_ispowerall(a, k, &a) && Z_ispowerall(b, k, &b)) {
     735        1484 :           *pt = z; gel(z,1) = a; gel(z,2) = b; return 1;
     736             :         }
     737       68630 :         set_avma((pari_sp)(z + 3)); return 0;
     738             :       }
     739          63 :       return Z_ispower(a, k) && Z_ispower(b, k);
     740             :     }
     741         609 :     case t_INTMOD:
     742         609 :       return Zn_ispower(gel(x,2), gel(x,1), K, pt);
     743          28 :     case t_FFELT:
     744          28 :       return FF_ispower(x, K, pt);
     745             : 
     746        1113 :     case t_PADIC:
     747        1113 :       return Qp_ispower(x, K, pt);
     748          14 :     case t_POLMOD:
     749          14 :       return polmodispower(x, K, pt);
     750         987 :     case t_POL:
     751         987 :       return polispower(x, K, pt);
     752          21 :     case t_RFRAC:
     753          21 :       return rfracispower(x, K, pt);
     754           7 :     case t_REAL:
     755           7 :       if (signe(x) < 0 && !mpodd(K)) return 0;
     756             :     case t_COMPLEX:
     757          14 :       if (pt) *pt = gsqrtn(x, K, NULL, DEFAULTPREC);
     758          14 :       return 1;
     759             : 
     760           7 :     case t_SER:
     761           7 :       if (signe(x) && (!dvdsi(valser(x), K) || !ispower(gel(x,2), K, NULL)))
     762           0 :         return 0;
     763           7 :       if (pt) *pt = gsqrtn(x, K, NULL, DEFAULTPREC);
     764           7 :       return 1;
     765             :   }
     766           0 :   pari_err_TYPE("ispower",x);
     767             :   return 0; /* LCOV_EXCL_LINE */
     768             : }
     769             : 
     770             : long
     771     7000182 : gisanypower(GEN x, GEN *pty)
     772             : {
     773     7000182 :   long tx = typ(x);
     774             :   ulong k, h;
     775     7000182 :   if (tx == t_INT) return Z_isanypower(x, pty);
     776          14 :   if (tx == t_FRAC)
     777             :   {
     778          14 :     pari_sp av = avma;
     779          14 :     GEN fa, P, E, a = gel(x,1), b = gel(x,2);
     780             :     long i, j, p, e;
     781          14 :     int sw = (abscmpii(a, b) > 0);
     782             : 
     783          14 :     if (sw) swap(a, b);
     784          14 :     k = Z_isanypower(a, pty? &a: NULL);
     785          14 :     if (!k)
     786             :     { /* a = -1,1 or not a pure power */
     787           7 :       if (!is_pm1(a)) return gc_long(av,0);
     788           7 :       if (signe(a) < 0) b = negi(b);
     789           7 :       k = Z_isanypower(b, pty? &b: NULL);
     790           7 :       if (!k || !pty) return gc_long(av,k);
     791           7 :       *pty = gerepileupto(av, ginv(b));
     792           7 :       return k;
     793             :     }
     794           7 :     fa = factoru(k);
     795           7 :     P = gel(fa,1);
     796           7 :     E = gel(fa,2); h = k;
     797          14 :     for (i = lg(P) - 1; i > 0; i--)
     798             :     {
     799           7 :       p = P[i];
     800           7 :       e = E[i];
     801          21 :       for (j = 0; j < e; j++)
     802          14 :         if (!is_kth_power(b, p, &b)) break;
     803           7 :       if (j < e) k /= upowuu(p, e - j);
     804             :     }
     805           7 :     if (k == 1) return gc_long(av,0);
     806           7 :     if (!pty) return gc_long(av,k);
     807           0 :     if (k != h) a = powiu(a, h/k);
     808           0 :     *pty = gerepilecopy(av, mkfrac(a, b));
     809           0 :     return k;
     810             :   }
     811           0 :   pari_err_TYPE("gisanypower", x);
     812             :   return 0; /* LCOV_EXCL_LINE */
     813             : }
     814             : 
     815             : /* v_p(x) = e != 0 for some p; return ispower(x,,&x), updating x.
     816             :  * No need to optimize for 2,3,5,7 powers (done before) */
     817             : static long
     818      507443 : split_exponent(ulong e, GEN *x)
     819             : {
     820             :   GEN fa, P, E;
     821      507443 :   long i, j, l, k = 1;
     822      507443 :   if (e == 1) return 1;
     823          14 :   fa = factoru(e);
     824          14 :   P = gel(fa,1);
     825          14 :   E = gel(fa,2); l = lg(P);
     826          28 :   for (i = 1; i < l; i++)
     827             :   {
     828          14 :     ulong p = P[i];
     829          28 :     for (j = 0; j < E[i]; j++)
     830             :     {
     831             :       GEN y;
     832          14 :       if (!is_kth_power(*x, p, &y)) break;
     833          14 :       k *= p; *x = y;
     834             :     }
     835             :   }
     836          14 :   return k;
     837             : }
     838             : 
     839             : /* any prime divisor of x is > 102 */
     840             : static long
     841      870335 : Z_isanypower_101(GEN *px)
     842             : {
     843      870335 :   const double LOG2_103 = 6.6865; /* lower bound for log_2(103) */
     844      870335 :   const double LOG103 = 4.6347; /* lower bound for log(103) */
     845             :   forprime_t T;
     846      870335 :   ulong mask = 7, e2;
     847             :   long k, ex;
     848      870335 :   GEN y, x = *px;
     849             : 
     850      870335 :   k = 1;
     851      873837 :   while (Z_issquareall(x, &y)) { k <<= 1; x = y; }
     852      870770 :   while ( (ex = is_357_power(x, &y, &mask)) ) { k *= ex; x = y; }
     853      870335 :   e2 = (ulong)((expi(x) + 1) / LOG2_103); /* >= log_103 (x) */
     854      870335 :   if (u_forprime_init(&T, 11, e2))
     855             :   {
     856       17647 :     GEN logx = NULL;
     857       17647 :     const ulong Q = 30011; /* prime */
     858             :     ulong p, xmodQ;
     859       17647 :     double dlogx = 0;
     860             :     /* cut off at x^(1/p) ~ 2^30 bits which seems to be about optimum;
     861             :      * for large p the modular checks are no longer competitively fast */
     862       17689 :     while ( (ex = is_pth_power(x, &y, &T, 30)) )
     863             :     {
     864          42 :       k *= ex; x = y;
     865          42 :       e2 = (ulong)((expi(x) + 1) / LOG2_103);
     866          42 :       u_forprime_restrict(&T, e2);
     867             :     }
     868       17647 :     if (DEBUGLEVEL>4)
     869           0 :       err_printf("Z_isanypower: now k=%ld, x=%ld-bit\n", k, expi(x)+1);
     870       17647 :     xmodQ = umodiu(x, Q);
     871             :     /* test Q | x, just in case */
     872       17647 :     if (!xmodQ) { *px = x; return k * split_exponent(Z_lval(x,Q), px); }
     873             :     /* x^(1/p) < 2^31 */
     874       17633 :     p = T.p;
     875       17633 :     if (p <= e2)
     876             :     {
     877       17619 :       logx = logr_abs( itor(x, DEFAULTPREC) );
     878       17619 :       dlogx = rtodbl(logx);
     879       17619 :       e2 = (ulong)(dlogx / LOG103); /* >= log_103(x) */
     880             :     }
     881      147329 :     while (p && p <= e2)
     882             :     { /* is x a p-th power ? By computing y = round(x^(1/p)).
     883             :        * Check whether y^p = x, first mod Q, then exactly. */
     884      129696 :       pari_sp av = avma;
     885             :       long e;
     886      129696 :       GEN logy = divru(logx, p), y = grndtoi(mpexp(logy), &e);
     887      129696 :       ulong ymodQ = umodiu(y,Q);
     888      129696 :       if (e >= -10 || Fl_powu(ymodQ, p % (Q-1), Q) != xmodQ
     889      129696 :                    || !equalii(powiu(y, p), x)) set_avma(av);
     890             :       else
     891             :       {
     892          21 :         k *= p; x = y; xmodQ = ymodQ; logx = logy; dlogx /= p;
     893          21 :         e2 = (ulong)(dlogx / LOG103); /* >= log_103(x) */
     894          21 :         u_forprime_restrict(&T, e2);
     895          21 :         continue; /* if success, retry same p */
     896             :       }
     897      129675 :       p = u_forprime_next(&T);
     898             :     }
     899             :   }
     900      870321 :   *px = x; return k;
     901             : }
     902             : 
     903             : static ulong tinyprimes[] = {
     904             :   2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
     905             :   73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
     906             :   157, 163, 167, 173, 179, 181, 191, 193, 197, 199
     907             : };
     908             : 
     909             : /* disregard the sign of x, caller will take care of x < 0 */
     910             : static long
     911     7195980 : Z_isanypower_aux(GEN x, GEN *pty)
     912             : {
     913             :   long ex, v, i, l, k;
     914             :   GEN y, P, E;
     915     7195980 :   ulong mask, e = 0;
     916             : 
     917     7195980 :   if (abscmpii(x, gen_2) < 0) return 0; /* -1,0,1 */
     918             : 
     919     7195251 :   x = absi_shallow(x);
     920     7195251 :   k = l = 1;
     921     7195251 :   P = cgetg(26 + 1, t_VECSMALL);
     922     7195251 :   E = cgetg(26 + 1, t_VECSMALL);
     923             :   /* trial division */
     924    61992459 :   for(i = 0; i < 26; i++)
     925             :   {
     926    60650577 :     ulong p = tinyprimes[i];
     927             :     int stop;
     928    60650577 :     v = Z_lvalrem_stop(&x, p, &stop);
     929    60650576 :     if (v)
     930             :     {
     931     8043941 :       P[l] = p;
     932     8043941 :       E[l] = v; l++;
     933     8423997 :       e = ugcd(e, v); if (e == 1) goto END;
     934             :     }
     935    55177263 :     if (stop) {
     936      380056 :       if (is_pm1(x)) k = e;
     937      380056 :       goto END;
     938             :     }
     939             :   }
     940             : 
     941     1341882 :   if (e)
     942             :   { /* Bingo. Result divides e */
     943             :     long v3, v5, v7;
     944      507429 :     ulong e2 = e;
     945      507429 :     v = u_lvalrem(e2, 2, &e2);
     946      507429 :     if (v)
     947             :     {
     948      377780 :       for (i = 0; i < v; i++)
     949             :       {
     950      375659 :         if (!Z_issquareall(x, &y)) break;
     951        2333 :         k <<= 1; x = y;
     952             :       }
     953             :     }
     954      507429 :     mask = 0;
     955      507429 :     v3 = u_lvalrem(e2, 3, &e2); if (v3) mask = 1;
     956      507429 :     v5 = u_lvalrem(e2, 5, &e2); if (v5) mask |= 2;
     957      507429 :     v7 = u_lvalrem(e2, 7, &e2); if (v7) mask |= 4;
     958      507506 :     while ( (ex = is_357_power(x, &y, &mask)) ) {
     959          77 :       x = y;
     960          77 :       switch(ex)
     961             :       {
     962          28 :         case 3: k *= 3; if (--v3 == 0) mask &= ~1; break;
     963          28 :         case 5: k *= 5; if (--v5 == 0) mask &= ~2; break;
     964          21 :         case 7: k *= 7; if (--v7 == 0) mask &= ~4; break;
     965             :       }
     966             :     }
     967      507429 :     k *= split_exponent(e2, &x);
     968             :   }
     969             :   else
     970      834453 :     k = Z_isanypower_101(&x);
     971     7195251 : END:
     972     7195251 :   if (pty && k != 1)
     973             :   {
     974       70224 :     if (e)
     975             :     { /* add missing small factors */
     976       66869 :       y = powuu(P[1], E[1] / k);
     977       76863 :       for (i = 2; i < l; i++) y = mulii(y, powuu(P[i], E[i] / k));
     978       66869 :       x = equali1(x)? y: mulii(x,y);
     979             :     }
     980       70224 :     *pty = x;
     981             :   }
     982     7195251 :   return k == 1? 0: k;
     983             : }
     984             : 
     985             : long
     986     7195980 : Z_isanypower(GEN x, GEN *pty)
     987             : {
     988     7195980 :   pari_sp av = avma;
     989     7195980 :   long k = Z_isanypower_aux(x, pty);
     990     7195980 :   if (!k) return gc_long(av,0);
     991       70287 :   if (signe(x) < 0)
     992             :   {
     993          42 :     long v = vals(k);
     994          42 :     if (v)
     995             :     {
     996          28 :       k >>= v;
     997          28 :       if (k == 1) return gc_long(av,0);
     998          21 :       if (!pty) return gc_long(av,k);
     999          14 :       *pty = gerepileuptoint(av, powiu(*pty, 1<<v));
    1000          14 :       togglesign(*pty); return k;
    1001             :     }
    1002          14 :     if (pty) togglesign_safe(pty);
    1003             :   }
    1004       70259 :   if (!pty) return gc_long(av, k);
    1005       70203 :   *pty = gerepilecopy(av, *pty); return k;
    1006             : }
    1007             : 
    1008             : /* Faster than expi(n) == vali(n) or hamming(n) == 1 even for single-word
    1009             :  * values. If all you have is a word, you can just use n & !(n & (n-1)). */
    1010             : long
    1011      526511 : Z_ispow2(GEN n)
    1012             : {
    1013             :   GEN xp;
    1014             :   long i, l;
    1015             :   ulong u;
    1016      526511 :   if (signe(n) != 1) return 0;
    1017      470504 :   xp = int_LSW(n); u = *xp; l = lgefint(n);
    1018      531385 :   for (i = 3; i < l; ++i)
    1019             :   {
    1020      250463 :     if (u) return 0;
    1021       60881 :     xp = int_nextW(xp); u = *xp;
    1022             :   }
    1023      280922 :   return !(u & (u-1));
    1024             : }
    1025             : 
    1026             : static long
    1027      842128 : isprimepower_i(GEN n, GEN *pt, long flag)
    1028             : {
    1029      842128 :   pari_sp av = avma;
    1030             :   long i, v;
    1031             : 
    1032      842128 :   if (typ(n) != t_INT) pari_err_TYPE("isprimepower", n);
    1033      842128 :   if (signe(n) <= 0) return 0;
    1034             : 
    1035      842128 :   if (lgefint(n) == 3)
    1036             :   {
    1037             :     ulong p;
    1038      541232 :     v = uisprimepower(n[2], &p);
    1039      541232 :     if (v)
    1040             :     {
    1041       55006 :       if (pt) *pt = utoipos(p);
    1042       55006 :       return v;
    1043             :     }
    1044      486226 :     return 0;
    1045             :   }
    1046     1663673 :   for (i = 0; i < 26; i++)
    1047             :   {
    1048     1627791 :     ulong p = tinyprimes[i];
    1049     1627791 :     v = Z_lvalrem(n, p, &n);
    1050     1627790 :     if (v)
    1051             :     {
    1052      265013 :       set_avma(av);
    1053      265013 :       if (!is_pm1(n)) return 0;
    1054         617 :       if (pt) *pt = utoipos(p);
    1055         617 :       return v;
    1056             :     }
    1057             :   }
    1058             :   /* p | n => p >= 103 */
    1059       35882 :   v = Z_isanypower_101(&n); /* expensive */
    1060       35882 :   if (!(flag? isprime(n): BPSW_psp(n))) return gc_long(av,0);
    1061        5570 :   if (pt) *pt = gerepilecopy(av, n); else set_avma(av);
    1062        5570 :   return v;
    1063             : }
    1064             : long
    1065      840147 : isprimepower(GEN n, GEN *pt) { return isprimepower_i(n,pt,1); }
    1066             : long
    1067        1981 : ispseudoprimepower(GEN n, GEN *pt) { return isprimepower_i(n,pt,0); }
    1068             : 
    1069             : long
    1070      642976 : uisprimepower(ulong n, ulong *pp)
    1071             : { /* We must have CUTOFF^11 >= ULONG_MAX and CUTOFF^3 < ULONG_MAX.
    1072             :    * Tests suggest that 200-300 is the best range for 64-bit platforms. */
    1073      642976 :   const ulong CUTOFF = 200UL;
    1074      642976 :   const long TINYCUTOFF = 46;  /* tinyprimes[45] = 199 */
    1075      642976 :   const ulong CUTOFF3 = CUTOFF*CUTOFF*CUTOFF;
    1076             : #ifdef LONG_IS_64BIT
    1077             :   /* primes preceeding the appropriate root of ULONG_MAX. */
    1078      568277 :   const ulong ROOT9 = 137;
    1079      568277 :   const ulong ROOT8 = 251;
    1080      568277 :   const ulong ROOT7 = 563;
    1081      568277 :   const ulong ROOT5 = 7129;
    1082      568277 :   const ulong ROOT4 = 65521;
    1083             : #else
    1084       74699 :   const ulong ROOT9 = 11;
    1085       74699 :   const ulong ROOT8 = 13;
    1086       74699 :   const ulong ROOT7 = 23;
    1087       74699 :   const ulong ROOT5 = 83;
    1088       74699 :   const ulong ROOT4 = 251;
    1089             : #endif
    1090             :   ulong mask;
    1091             :   long v, i;
    1092             :   int e;
    1093      642976 :   if (n < 2) return 0;
    1094      642934 :   if (!odd(n)) {
    1095      341851 :     if (n & (n-1)) return 0;
    1096       65544 :     *pp = 2; return vals(n);
    1097             :   }
    1098      301083 :   if (n < 8) { *pp = n; return 1; } /* 3,5,7 */
    1099     3655110 :   for (i = 1/*skip p=2*/; i < TINYCUTOFF; i++)
    1100             :   {
    1101     3596035 :     ulong p = tinyprimes[i];
    1102     3596035 :     if (n % p == 0)
    1103             :     {
    1104      212447 :       v = u_lvalrem(n, p, &n);
    1105      212447 :       if (n == 1) { *pp = p; return v; }
    1106      210012 :       return 0;
    1107             :     }
    1108             :   }
    1109             :   /* p | n => p >= CUTOFF */
    1110             : 
    1111       59075 :   if (n < CUTOFF3)
    1112             :   {
    1113       46354 :     if (n < CUTOFF*CUTOFF || uisprime_101(n)) { *pp = n; return 1; }
    1114           0 :     if (uissquareall(n, &n)) { *pp = n; return 2; }
    1115           0 :     return 0;
    1116             :   }
    1117             : 
    1118             :   /* Check for squares, fourth powers, and eighth powers as appropriate. */
    1119       12721 :   v = 1;
    1120       12721 :   if (uissquareall(n, &n)) {
    1121           0 :     v <<= 1;
    1122           0 :     if (CUTOFF <= ROOT4 && uissquareall(n, &n)) {
    1123           0 :       v <<= 1;
    1124           0 :       if (CUTOFF <= ROOT8 && uissquareall(n, &n)) v <<= 1;
    1125             :     }
    1126             :   }
    1127             : 
    1128       12721 :   if (CUTOFF > ROOT5) mask = 1;
    1129             :   else
    1130             :   {
    1131       12720 :     const ulong CUTOFF5 = CUTOFF3*CUTOFF*CUTOFF;
    1132       12720 :     if (n < CUTOFF5) mask = 1; else mask = 3;
    1133       12720 :     if (CUTOFF <= ROOT7)
    1134             :     {
    1135       12720 :       const ulong CUTOFF7 = CUTOFF5*CUTOFF*CUTOFF;
    1136       12720 :       if (n >= CUTOFF7) mask = 7;
    1137             :     }
    1138             :   }
    1139             : 
    1140       12721 :   if (CUTOFF <= ROOT9 && (e = uis_357_power(n, &n, &mask))) { v *= e; mask=1; }
    1141       12721 :   if ((e = uis_357_power(n, &n, &mask))) v *= e;
    1142             : 
    1143       12721 :   if (uisprime_101(n)) { *pp = n; return v; }
    1144        6984 :   return 0;
    1145             : }
    1146             : 

Generated by: LCOV version 1.16