[BACK]Return to arith1.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / pari-2.2 / src / basemath

Annotation of OpenXM_contrib/pari-2.2/src/basemath/arith1.c, Revision 1.2

1.2     ! noro        1: /* $Id: arith1.c,v 1.101 2002/09/05 16:40:24 karim Exp $
1.1       noro        2:
                      3: Copyright (C) 2000  The PARI group.
                      4:
                      5: This file is part of the PARI/GP package.
                      6:
                      7: PARI/GP is free software; you can redistribute it and/or modify it under the
                      8: terms of the GNU General Public License as published by the Free Software
                      9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
                     10: ANY WARRANTY WHATSOEVER.
                     11:
                     12: Check the License for details. You should have received a copy of it, along
                     13: with the package; see the file 'COPYING'. If not, write to the Free Software
                     14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
                     15:
                     16: /*********************************************************************/
                     17: /**                                                                 **/
                     18: /**                     ARITHMETIC FUNCTIONS                        **/
                     19: /**                         (first part)                            **/
                     20: /**                                                                 **/
                     21: /*********************************************************************/
                     22: #include "pari.h"
                     23:
                     24: /*********************************************************************/
                     25: /**                                                                 **/
                     26: /**                  ARITHMETIC FUNCTION PROTOTYPES                 **/
                     27: /**                                                                 **/
                     28: /*********************************************************************/
                     29: GEN
                     30: garith_proto(GEN f(GEN), GEN x, int do_error)
                     31: {
                     32:   long tx=typ(x),lx,i;
                     33:   GEN y;
                     34:
                     35:   if (is_matvec_t(tx))
                     36:   {
                     37:     lx=lg(x); y=cgetg(lx,tx);
                     38:     for (i=1; i<lx; i++) y[i] = (long) garith_proto(f,(GEN) x[i], do_error);
                     39:     return y;
                     40:   }
                     41:   if (tx != t_INT && do_error) err(arither1);
                     42:   return f(x);
                     43: }
                     44:
                     45: GEN
                     46: arith_proto(long f(GEN), GEN x, int do_error)
                     47: {
                     48:   long tx=typ(x),lx,i;
                     49:   GEN y;
                     50:
                     51:   if (is_matvec_t(tx))
                     52:   {
                     53:     lx=lg(x); y=cgetg(lx,tx);
                     54:     for (i=1; i<lx; i++) y[i] = (long) arith_proto(f,(GEN) x[i], do_error);
                     55:     return y;
                     56:   }
                     57:   if (tx != t_INT && do_error) err(arither1);
                     58:   return stoi(f(x));
                     59: }
                     60:
                     61: GEN
                     62: arith_proto2(long f(GEN,GEN), GEN x, GEN n)
                     63: {
                     64:   long l,i,tx = typ(x);
                     65:   GEN y;
                     66:
                     67:   if (is_matvec_t(tx))
                     68:   {
                     69:     l=lg(x); y=cgetg(l,tx);
                     70:     for (i=1; i<l; i++) y[i] = (long) arith_proto2(f,(GEN) x[i],n);
                     71:     return y;
                     72:   }
                     73:   if (tx != t_INT) err(arither1);
                     74:   tx=typ(n);
                     75:   if (is_matvec_t(tx))
                     76:   {
                     77:     l=lg(n); y=cgetg(l,tx);
                     78:     for (i=1; i<l; i++) y[i] = (long) arith_proto2(f,x,(GEN) n[i]);
                     79:     return y;
                     80:   }
                     81:   if (tx != t_INT) err(arither1);
                     82:   return stoi(f(x,n));
                     83: }
                     84:
                     85: static GEN
                     86: arith_proto2gs(long f(GEN,long), GEN x, long y)
                     87: {
                     88:   long l,i,tx = typ(x);
                     89:   GEN t;
                     90:
                     91:   if (is_matvec_t(tx))
                     92:   {
                     93:     l=lg(x); t=cgetg(l,tx);
                     94:     for (i=1; i<l; i++) t[i]= (long) arith_proto2gs(f,(GEN) x[i],y);
                     95:     return t;
                     96:   }
                     97:   if (tx != t_INT) err(arither1);
                     98:   return stoi(f(x,y));
                     99: }
                    100:
                    101: GEN
                    102: garith_proto2gs(GEN f(GEN,long), GEN x, long y)
                    103: {
                    104:   long l,i,tx = typ(x);
                    105:   GEN t;
                    106:
                    107:   if (is_matvec_t(tx))
                    108:   {
                    109:     l=lg(x); t=cgetg(l,tx);
                    110:     for (i=1; i<l; i++) t[i]= (long) garith_proto2gs(f,(GEN) x[i],y);
                    111:     return t;
                    112:   }
                    113:   if (tx != t_INT) err(arither1);
                    114:   return f(x,y);
                    115: }
                    116:
                    117: GEN
1.2     ! noro      118: garith_proto3ggs(GEN f(GEN,GEN,long), GEN x, GEN y, long z)
        !           119: {
        !           120:   long l,i,tx = typ(x);
        !           121:   GEN t;
        !           122:
        !           123:   if (is_matvec_t(tx))
        !           124:   {
        !           125:     l=lg(x); t=cgetg(l,tx);
        !           126:     for (i=1; i<l; i++) t[i]= (long) garith_proto3ggs(f,(GEN) x[i],y,z);
        !           127:     return t;
        !           128:   }
        !           129:   if (tx != t_INT) err(arither1);
        !           130:   tx = typ(y);
        !           131:   if (is_matvec_t(tx))
        !           132:   {
        !           133:     l=lg(y); t=cgetg(l,tx);
        !           134:     for (i=1; i<l; i++) t[i]= (long) garith_proto3ggs(f,x,(GEN) y[i],z);
        !           135:     return t;
        !           136:   }
        !           137:   if (tx != t_INT) err(arither1);
        !           138:   return f(x,y,z);
        !           139: }
        !           140:
        !           141: GEN
1.1       noro      142: gassoc_proto(GEN f(GEN,GEN), GEN x, GEN y)
                    143: {
                    144:   int tx=typ(x);
                    145:   if (!y)
                    146:   {
1.2     ! noro      147:     gpmem_t av = avma;
1.1       noro      148:     if (tx!=t_VEC && tx!=t_COL)
                    149:       err(typeer,"association");
                    150:     return gerepileupto(av,divide_conquer_prod(x,f));
                    151:   }
                    152:   return f(x,y);
                    153: }
                    154:
                    155: /*********************************************************************/
                    156: /**                                                                 **/
                    157: /**               ORDER of INTEGERMOD x  in  (Z/nZ)*                **/
                    158: /**                                                                 **/
                    159: /*********************************************************************/
                    160:
                    161: GEN
                    162: order(GEN x)
                    163: {
1.2     ! noro      164:   gpmem_t av = avma,av1;
        !           165:   long i,e;
1.1       noro      166:   GEN o,m,p;
                    167:
                    168:   if (typ(x) != t_INTMOD || !gcmp1(mppgcd((GEN) x[1],(GEN) x[2])))
                    169:     err(talker,"not an element of (Z/nZ)* in order");
                    170:   o=phi((GEN) x[1]); m=decomp(o);
                    171:   for (i = lg(m[1])-1; i; i--)
                    172:   {
                    173:     p=gcoeff(m,i,1); e=itos(gcoeff(m,i,2));
                    174:     do
                    175:     {
                    176:       GEN o1=divii(o,p), y=powgi(x,o1);
                    177:       if (!gcmp1((GEN)y[2])) break;
                    178:       e--; o = o1;
                    179:     }
                    180:     while (e);
                    181:   }
                    182:   av1=avma; return gerepile(av,av1,icopy(o));
                    183: }
                    184:
                    185: /******************************************************************/
                    186: /*                                                                */
                    187: /*                 GENERATOR of (Z/mZ)*                           */
                    188: /*                                                                */
                    189: /******************************************************************/
                    190:
                    191: GEN
                    192: ggener(GEN m)
                    193: {
                    194:   return garith_proto(gener,m,1);
                    195: }
                    196:
                    197: GEN
                    198: gener(GEN m)
                    199: {
1.2     ! noro      200:   gpmem_t av=avma,av1;
        !           201:   long k,i,e;
1.1       noro      202:   GEN x,t,q,p;
                    203:
                    204:   if (typ(m) != t_INT) err(arither1);
                    205:   e = signe(m);
                    206:   if (!e) err(talker,"zero modulus in znprimroot");
1.2     ! noro      207:   if (is_pm1(m)) return gmodulss(0,1);
        !           208:   if (e < 0) m = absi(m);
1.1       noro      209:
                    210:   e = mod4(m);
                    211:   if (e == 0) /* m = 0 mod 4 */
                    212:   {
                    213:     if (cmpis(m,4)) err(generer); /* m != 4, non cyclic */
                    214:     return gmodulsg(3,m);
                    215:   }
                    216:   if (e == 2) /* m = 0 mod 2 */
                    217:   {
                    218:     q=shifti(m,-1); x = (GEN) gener(q)[2];
                    219:     if (!mod2(x)) x = addii(x,q);
                    220:     av1=avma; return gerepile(av,av1,gmodulcp(x,m));
                    221:   }
                    222:
                    223:   t=decomp(m); if (lg(t[1]) != 2) err(generer);
                    224:   p=gcoeff(t,1,1); e=itos(gcoeff(t,1,2)); q=subis(p,1);
1.2     ! noro      225:   if (e >= 2)
1.1       noro      226:   {
1.2     ! noro      227:     x = (GEN)gener(p)[2];
1.1       noro      228:     if (gcmp1(powmodulo(x,q, sqri(p)))) x = addii(x,p);
                    229:     av1=avma; return gerepile(av,av1,gmodulcp(x,m));
                    230:   }
                    231:
                    232:   p=(GEN)decomp(q)[1]; k=lg(p)-1; x=stoi(1);
1.2     ! noro      233:   for (i=1; i<=k; i++) p[i] = (long)diviiexact(q, (GEN)p[i]);
1.1       noro      234:   for(;;)
                    235:   {
                    236:     x[2]++;
                    237:     if (gcmp1(mppgcd(m,x)))
                    238:     {
                    239:       for (i=k; i; i--)
1.2     ! noro      240:        if (gcmp1(powmodulo(x, (GEN)p[i], m))) break;
1.1       noro      241:       if (!i) break;
                    242:     }
                    243:   }
                    244:   av1=avma; return gerepile(av,av1,gmodulcp(x,m));
                    245: }
                    246:
1.2     ! noro      247: /* assume p odd prime */
        !           248: ulong
        !           249: u_gener(ulong p)
        !           250: {
        !           251:   const gpmem_t av = avma;
        !           252:   const long q = p - 1;
        !           253:   const GEN L = (GEN)decomp(utoi(q))[1];
        !           254:   const int k = lg(L) - 1;
        !           255:   int i,x;
        !           256:
        !           257:   for (x=2;;x++)
        !           258:     if (x % p)
        !           259:     {
        !           260:       for (i=k; i; i--)
        !           261:        if (powuumod(x, q/itos((GEN)L[i]), p) == 1) break;
        !           262:       if (!i) break;
        !           263:     }
        !           264:   avma = av; return x;
        !           265: }
        !           266:
1.1       noro      267: GEN
                    268: znstar(GEN n)
                    269: {
                    270:   GEN p1,z,q,u,v,d,list,ep,h,gen,moduli,p,a;
                    271:   long i,j,nbp,sizeh;
1.2     ! noro      272:   gpmem_t av;
1.1       noro      273:
                    274:   if (typ(n) != t_INT) err(arither1);
                    275:   if (!signe(n))
                    276:   {
                    277:     z=cgetg(4,t_VEC);
                    278:     z[1]=deux; p1=cgetg(2,t_VEC);
                    279:     z[2]=(long)p1; p1[1]=deux; p1=cgetg(2,t_VEC);
                    280:     z[3]=(long)p1; p1[1]=lneg(gun);
                    281:     return z;
                    282:   }
                    283:   av=avma; n=absi(n);
                    284:   if (cmpis(n,2)<=0)
                    285:   {
                    286:     avma=av; z=cgetg(4,t_VEC);
                    287:     z[1]=un;
                    288:     z[2]=lgetg(1,t_VEC);
                    289:     z[3]=lgetg(1,t_VEC);
                    290:     return z;
                    291:   }
                    292:   list=factor(n); ep=(GEN)list[2]; list=(GEN)list[1]; nbp=lg(list)-1;
                    293:   h      = cgetg(nbp+2,t_VEC);
                    294:   gen    = cgetg(nbp+2,t_VEC);
                    295:   moduli = cgetg(nbp+2,t_VEC);
                    296:   switch(mod8(n))
                    297:   {
                    298:     case 0:
                    299:       h[1] = lmul2n(gun,itos((GEN)ep[1])-2); h[2] = deux;
                    300:       gen[1] = lstoi(5); gen[2] = laddis(gmul2n((GEN)h[1],1),-1);
                    301:       moduli[1] = moduli[2] = lmul2n(gun,itos((GEN)ep[1]));
                    302:       sizeh = nbp+1; i=3; j=2; break;
                    303:     case 4:
                    304:       h[1] = deux;
                    305:       gen[1] = lstoi(3);
                    306:       moduli[1] = lmul2n(gun,itos((GEN)ep[1]));
                    307:       sizeh = nbp; i=j=2; break;
                    308:     case 2: case 6:
                    309:       sizeh = nbp-1; i=1; j=2; break;
                    310:     default: /* 1, 3, 5, 7 */
                    311:       sizeh = nbp; i=j=1;
                    312:   }
                    313:   for ( ; j<=nbp; i++,j++)
                    314:   {
                    315:     p = (GEN)list[j]; q = gpuigs(p, itos((GEN)ep[j])-1);
                    316:     h[i] = lmulii(addis(p,-1),q); p1 = mulii(p,q);
                    317:     gen[i] = gener(p1)[2];
                    318:     moduli[i] = (long)p1;
                    319:   }
                    320: #if 0
                    321:   if (nbp == 1 && is_pm1(ep[1]))
                    322:     gen[1] = lmodulcp((GEN)gen[1],n);
                    323:   else
                    324: #endif
                    325:     for (i=1; i<=sizeh; i++)
                    326:     {
                    327:       q = (GEN)moduli[i]; a = (GEN)gen[i];
                    328:       u = mpinvmod(q,divii(n,q));
                    329:       gen[i] = lmodulcp(addii(a,mulii(mulii(subsi(1,a),u),q)), n);
                    330:     }
                    331:
                    332:   for (i=sizeh; i>=2; i--)
                    333:     for (j=i-1; j>=1; j--)
                    334:       if (!divise((GEN)h[j],(GEN)h[i]))
                    335:       {
                    336:        d=bezout((GEN)h[i],(GEN)h[j],&u,&v);
                    337:         q=divii((GEN)h[j],d);
                    338:        h[j]=(long)mulii((GEN)h[i],q); h[i]=(long)d;
                    339:        gen[j]=ldiv((GEN)gen[j], (GEN)gen[i]);
                    340:        gen[i]=lmul((GEN)gen[i], powgi((GEN)gen[j], mulii(v,q)));
                    341:       }
                    342:   q=gun; for (i=1; i<=sizeh && !gcmp1((GEN)h[i]); i++) q=mulii(q,(GEN)h[i]);
                    343:   setlg(h,i); setlg(gen,i); z=cgetg(4,t_VEC);
                    344:   z[1]=(long)q; z[2]=(long)h; z[3]=(long)gen;
                    345:   return gerepilecopy(av,z);
                    346: }
                    347:
                    348: /*********************************************************************/
                    349: /**                                                                 **/
                    350: /**                     INTEGRAL SQUARE ROOT                        **/
                    351: /**                                                                 **/
                    352: /*********************************************************************/
                    353: extern ulong mpsqrtl(GEN a);
                    354:
                    355: GEN
                    356: gracine(GEN a)
                    357: {
                    358:   return garith_proto(racine,a,1); /* hm. --GN */
                    359: }
                    360:
                    361: /* Use l as lgefint(a) [a may have more digits] */
                    362: static GEN
                    363: racine_r(GEN a, long l)
                    364: {
1.2     ! noro      365:   gpmem_t av;
        !           366:   long s;
1.1       noro      367:   GEN x,y,z;
                    368:
                    369:   if (l <= 4) return utoi(mpsqrtl(a));
                    370:   av = avma;
                    371:   s = 2 + ((l-1) >> 1);
                    372:   setlgefint(a, s);
                    373:   x = addis(racine_r(a, s), 1); setlgefint(a, l);
                    374:   /* x = good approx (from above) of sqrt(a): about l/2 correct bits */
                    375:   x = shifti(x, (l - s)*(BITS_IN_LONG/2));
                    376:   do
                    377:   { /* one or two iterations should do the trick */
                    378:     z = shifti(addii(x,divii(a,x)), -1);
                    379:     y = x; x = z;
                    380:   }
                    381:   while (cmpii(x,y) < 0);
1.2     ! noro      382:   avma = (gpmem_t)y;
1.1       noro      383:   return gerepileuptoint(av,y);
                    384: }
                    385:
                    386: GEN
                    387: racine_i(GEN a, int roundup)
                    388: {
1.2     ! noro      389:   gpmem_t av = avma;
        !           390:   long k,m,l = lgefint(a);
1.1       noro      391:   GEN x = racine_r(a, l);
                    392:   if (roundup && signe(x))
                    393:   {
                    394:     m = modBIL(x);
                    395:     k = (m * m != a[l-1] || !egalii(sqri(x),a));
1.2     ! noro      396:     avma = (gpmem_t)x;
1.1       noro      397:     if (k) x = gerepileuptoint(av, addis(x,1));
                    398:   }
                    399:   return x;
                    400: }
                    401:
                    402: GEN
                    403: racine(GEN a)
                    404: {
                    405:   if (typ(a) != t_INT) err(arither1);
                    406:   switch (signe(a))
                    407:   {
                    408:     case 1: return racine_i(a,0);
                    409:     case 0: return gzero;
                    410:     case -1:
                    411:     {
                    412:       GEN x = cgetg(3,t_COMPLEX);
                    413:       x[1] = zero;
                    414:       x[2] = (long)racine_i(a,0); return x;
                    415:     }
                    416:   }
                    417:   return NULL; /* not reached */
                    418: }
                    419:
                    420: /*********************************************************************/
                    421: /**                                                                 **/
                    422: /**                      PERFECT SQUARE                             **/
                    423: /**                                                                 **/
                    424: /*********************************************************************/
                    425: extern ulong usqrtsafe(ulong a);
                    426:
                    427: static int
                    428: carremod(ulong A)
                    429: {
                    430:   static int carresmod64[]={
                    431:     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,
                    432:     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};
                    433:   static int carresmod63[]={
                    434:     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,
                    435:     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};
                    436:   static int carresmod65[]={
                    437:     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,
                    438:     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};
                    439:   static int carresmod11[]={1,1,0,1,1,1,0,0,0,1, 0};
                    440:   return (carresmod64[A & 0x3fUL]
                    441:     && carresmod63[A % 63UL]
                    442:     && carresmod65[A % 65UL]
                    443:     && carresmod11[A % 11UL]);
                    444: }
                    445:
                    446: /* emulate carrecomplet on single-word positive integers */
                    447: ulong
                    448: ucarrecomplet(ulong A)
                    449: {
                    450:   if (carremod(A))
                    451:   {
                    452:     ulong a = usqrtsafe(A);
                    453:     if (a * a == A) return a;
                    454:   }
                    455:   return 0;
                    456: }
                    457:
                    458: long
                    459: carrecomplet(GEN x, GEN *pt)
                    460: {
1.2     ! noro      461:   gpmem_t av;
1.1       noro      462:   GEN y;
                    463:
                    464:   switch(signe(x))
                    465:   {
                    466:     case -1: return 0;
                    467:     case 0: if (pt) *pt=gzero; return 1;
                    468:   }
                    469:   if (lgefint(x) == 3)
                    470:   {
                    471:     long a = ucarrecomplet((ulong)x[2]);
                    472:     if (!a) return 0;
                    473:     if (pt) *pt = stoi(a);
                    474:     return 1;
                    475:   }
                    476:   if (!carremod((ulong)smodis(x, 64*63*65*11))) return 0;
                    477:   av=avma; y = racine(x);
                    478:   if (!egalii(sqri(y),x)) { avma=av; return 0; }
1.2     ! noro      479:   if (pt) { *pt = y; avma=(gpmem_t)y; } else avma=av;
1.1       noro      480:   return 1;
                    481: }
                    482:
                    483: static GEN
                    484: polcarrecomplet(GEN x, GEN *pt)
                    485: {
1.2     ! noro      486:   gpmem_t av,av2;
        !           487:   long i,l;
1.1       noro      488:   GEN y,a,b;
                    489:
                    490:   if (!signe(x)) return gun;
                    491:   l=lgef(x); if ((l&1) == 0) return gzero; /* odd degree */
                    492:   i=2; while (isexactzero((GEN)x[i])) i++;
                    493:   if (i&1) return gzero;
                    494:   av2 = avma; a = (GEN)x[i];
                    495:   switch (typ(a))
                    496:   {
                    497:     case t_POL: case t_INT:
                    498:       y = gcarrecomplet(a,&b); break;
                    499:     default:
                    500:       y = gcarreparfait(a); b = NULL; break;
                    501:   }
                    502:   if (y == gzero) { avma = av2; return gzero; }
                    503:   av = avma; x = gdiv(x,a);
                    504:   y = gtrunc(gsqrt(greffe(x,l,1),0)); av2 = avma;
                    505:   if (!gegal(gsqr(y), x)) { avma=av; return gzero; }
                    506:   if (pt)
                    507:   {
                    508:     avma = av2;
                    509:     if (!gcmp1(a))
                    510:     {
                    511:       if (!b) b = gsqrt(a,DEFAULTPREC);
                    512:       y = gmul(b,y);
                    513:     }
                    514:     *pt = gerepileupto(av,y);
                    515:   }
                    516:   else avma = av;
                    517:   return gun;
                    518: }
                    519:
                    520: GEN
                    521: gcarrecomplet(GEN x, GEN *pt)
                    522: {
                    523:   long tx = typ(x),l,i;
                    524:   GEN z,y,p,t;
                    525:
                    526:   if (!pt) return gcarreparfait(x);
                    527:   if (is_matvec_t(tx))
                    528:   {
                    529:     l=lg(x); y=cgetg(l,tx); z=cgetg(l,tx);
                    530:     for (i=1; i<l; i++)
                    531:     {
                    532:       t=gcarrecomplet((GEN)x[i],&p);
                    533:       y[i] = (long)t;
                    534:       z[i] = gcmp0(t)? zero: (long)p;
                    535:     }
                    536:     *pt=z; return y;
                    537:   }
                    538:   if (tx == t_POL) return polcarrecomplet(x,pt);
                    539:   if (tx != t_INT) err(arither1);
                    540:   return stoi(carrecomplet(x,pt));
                    541: }
                    542:
                    543: GEN
                    544: gcarreparfait(GEN x)
                    545: {
1.2     ! noro      546:   gpmem_t av;
1.1       noro      547:   GEN p1,a,p;
1.2     ! noro      548:   long tx=typ(x),l,i,v;
1.1       noro      549:
                    550:   switch(tx)
                    551:   {
                    552:     case t_INT:
                    553:       return carreparfait(x)? gun: gzero;
                    554:
                    555:     case t_REAL:
                    556:       return (signe(x)>=0)? gun: gzero;
                    557:
                    558:     case t_INTMOD:
                    559:     {
1.2     ! noro      560:       GEN b, q;
1.1       noro      561:       long w;
                    562:       a = (GEN)x[2]; if (!signe(a)) return gun;
                    563:       av = avma;
                    564:       q = absi((GEN)x[1]); v = vali(q);
                    565:       if (v) /* > 0 */
                    566:       {
                    567:         long dv;
                    568:         w = vali(a); dv = v - w;
                    569:         if (dv > 0)
                    570:         {
                    571:           if (w & 1) { avma = av; return gzero; }
                    572:           if (dv >= 2)
                    573:           {
                    574:             b = w? shifti(a,-w): a;
                    575:             if ((dv>=3 && mod8(b) != 1) ||
                    576:                 (dv==2 && mod4(b) != 1)) { avma = av; return gzero; }
                    577:           }
                    578:         }
                    579:         q = shifti(q, -v);
                    580:       }
                    581:       /* q is now odd */
                    582:       i = kronecker(a,q);
                    583:       if (i < 0) { avma = av; return gzero; }
                    584:       if (i==0)
                    585:       {
                    586:         GEN d = mppgcd(a,q);
1.2     ! noro      587:         p = (GEN)factor(d)[1]; l = lg(p);
1.1       noro      588:         for (i=1; i<l; i++)
                    589:         {
                    590:           v = pvaluation(a,(GEN)p[i],&p1);
1.2     ! noro      591:           w = pvaluation(q,(GEN)p[i], &q);
1.1       noro      592:           if (v < w && (v&1 || kronecker(p1,(GEN)p[i]) == -1))
                    593:             { avma = av; return gzero; }
                    594:         }
                    595:         if (kronecker(a,q) == -1) { avma = av; return gzero; }
                    596:       }
                    597:       /* kro(a,q) = 1, q odd: need to factor q */
1.2     ! noro      598:       p = (GEN)factor(q)[1]; l = lg(p) - 1;
1.1       noro      599:       /* kro(a,q) = 1, check all p|q but the last (product formula) */
                    600:       for (i=1; i<l; i++)
                    601:         if (kronecker(a,(GEN)p[i]) == -1) { avma = av; return gzero; }
                    602:       return gun;
                    603:     }
                    604:
                    605:     case t_FRAC: case t_FRACN:
                    606:       av=avma; l=carreparfait(mulii((GEN)x[1],(GEN)x[2]));
                    607:       avma=av; return l? gun: gzero;
                    608:
                    609:     case t_COMPLEX:
                    610:       return gun;
                    611:
                    612:     case t_PADIC:
                    613:       a = (GEN)x[4]; if (!signe(a)) return gun;
                    614:       if (valp(x)&1) return gzero;
                    615:       p = (GEN)x[2];
                    616:       if (!egalii(p, gdeux))
                    617:         return (kronecker(a,p)== -1)? gzero: gun;
                    618:
                    619:       v = precp(x); /* here p=2, a is odd */
                    620:       if ((v>=3 && mod8(a) != 1 ) ||
                    621:           (v==2 && mod4(a) != 1)) return gzero;
                    622:       return gun;
                    623:
                    624:     case t_POL:
                    625:       return polcarrecomplet(x,NULL);
                    626:
                    627:     case t_SER:
                    628:       if (!signe(x)) return gun;
                    629:       if (valp(x)&1) return gzero;
                    630:       return gcarreparfait((GEN)x[2]);
                    631:
                    632:     case t_RFRAC: case t_RFRACN:
                    633:       av=avma;
                    634:       l=itos(gcarreparfait(gmul((GEN)x[1],(GEN)x[2])));
                    635:       avma=av; return stoi(l);
                    636:
                    637:     case t_QFR: case t_QFI:
                    638:       return gcarreparfait((GEN)x[1]);
                    639:
                    640:     case t_VEC: case t_COL: case t_MAT:
                    641:       l=lg(x); p1=cgetg(l,tx);
                    642:       for (i=1; i<l; i++) p1[i]=(long)gcarreparfait((GEN)x[i]);
                    643:       return p1;
                    644:   }
                    645:   err(typeer,"issquare");
                    646:   return NULL; /* not reached */
                    647: }
                    648:
                    649: /*********************************************************************/
                    650: /**                                                                 **/
                    651: /**                        KRONECKER SYMBOL                         **/
                    652: /**                                                                 **/
                    653: /*********************************************************************/
                    654: /* u = 3,5 mod 8 ?  (= 2 not a square mod u) */
                    655: #define  ome(t) (labs(((t)&7)-4) == 1)
                    656: #define gome(t) (ome(modBIL(t)))
                    657:
                    658: GEN
                    659: gkronecker(GEN x, GEN y)
                    660: {
                    661:   return arith_proto2(kronecker,x,y);
                    662: }
                    663:
                    664: long
                    665: kronecker(GEN x, GEN y)
                    666: {
1.2     ! noro      667:   const gpmem_t av = avma;
1.1       noro      668:   GEN z;
1.2     ! noro      669:   long r,s=1;
1.1       noro      670:
                    671:   switch (signe(y))
                    672:   {
                    673:     case -1: y=negi(y); if (signe(x)<0) s= -1; break;
                    674:     case 0: return is_pm1(x);
                    675:   }
                    676:   r=vali(y);
                    677:   if (r)
                    678:   {
                    679:     if (mpodd(x))
                    680:     {
                    681:       if (odd(r) && gome(x)) s= -s;
                    682:       y=shifti(y,-r);
                    683:     }
                    684:     else { avma=av; return 0; }
                    685:   }
                    686:   x=modii(x,y);
                    687:   while (signe(x))
                    688:   {
                    689:     r=vali(x);
                    690:     if (r)
                    691:     {
                    692:       if (odd(r) && gome(y)) s= -s;
                    693:       x=shifti(x,-r);
                    694:     }
                    695:     /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */
                    696:     if (modBIL(x) & modBIL(y) & 2) s = -s;
                    697:     z=resii(y,x); y=x; x=z;
                    698:   }
                    699:   avma=av; return is_pm1(y)? s: 0;
                    700: }
                    701:
                    702: GEN
                    703: gkrogs(GEN x, long y)
                    704: {
                    705:   return arith_proto2gs(krogs,x,y);
                    706: }
                    707:
                    708: long
                    709: krogs(GEN x, long y)
                    710: {
1.2     ! noro      711:   const gpmem_t av = avma;
        !           712:   long r,s=1,x1,z;
1.1       noro      713:
                    714:   if (y<=0)
                    715:   {
                    716:     if (y) { y = -y; if (signe(x)<0) s = -1; }
                    717:     else  return is_pm1(x);
                    718:   }
                    719:   r=vals(y);
                    720:   if (r)
                    721:   {
                    722:     if (mpodd(x))
                    723:     {
                    724:       if (odd(r) && gome(x)) s= -s;
                    725:       y>>=r;
                    726:     }
                    727:     else return 0;
                    728:   }
                    729:   x1=smodis(x,y); avma = av;
                    730:   while (x1)
                    731:   {
                    732:     r=vals(x1);
                    733:     if (r)
                    734:     {
                    735:       if (odd(r) && ome(y)) s= -s;
                    736:       x1>>=r;
                    737:     }
                    738:     if (x1 & y & 2) s= -s;
                    739:     z=y%x1; y=x1; x1=z;
                    740:   }
                    741:   return (y==1)? s: 0;
                    742: }
                    743:
                    744: long
                    745: krosg(long s, GEN x)
                    746: {
1.2     ! noro      747:   gpmem_t av = avma;
        !           748:   long y = kronecker(stoi(s),x);
1.1       noro      749:   avma = av; return y;
                    750: }
                    751:
                    752: long
                    753: kross(long x, long y)
                    754: {
                    755:   long r,s=1,x1,z;
                    756:
                    757:   if (y<=0)
                    758:   {
                    759:     if (y) { y= -y; if (x<0) s = -1; }
                    760:     else  return (labs(x)==1);
                    761:   }
                    762:   r=vals(y);
                    763:   if (r)
                    764:   {
                    765:     if (odd(x))
                    766:     {
                    767:       if (odd(r) && ome(x)) s = -s;
                    768:       y>>=r;
                    769:     }
                    770:     else return 0;
                    771:   }
                    772:   x1=x%y; if (x1<0) x1+=y;
                    773:   while (x1)
                    774:   {
                    775:     r=vals(x1);
                    776:     if (r)
                    777:     {
                    778:       if (odd(r) && ome(y)) s = -s;
                    779:       x1>>=r;
                    780:     }
                    781:     if (x1 & y & 2) s = -s;
                    782:     z=y%x1; y=x1; x1=z;
                    783:   }
                    784:   return (y==1)? s: 0;
                    785: }
                    786:
                    787: long
                    788: hil0(GEN x, GEN y, GEN p)
                    789: {
                    790:   return hil(x,y, p? p: gzero);
                    791: }
                    792:
                    793: #define eps(t) (((signe(t)*(modBIL(t)))&3)==3)
                    794: long
                    795: hil(GEN x, GEN y, GEN p)
                    796: {
1.2     ! noro      797:   gpmem_t av;
        !           798:   long a,b,tx,ty,z;
1.1       noro      799:   GEN p1,p2,u,v;
                    800:
                    801:   if (gcmp0(x) || gcmp0(y)) return 0;
                    802:   av=avma; tx=typ(x); ty=typ(y);
                    803:   if (tx>ty) { p1=x; x=y; y=p1; a=tx,tx=ty; ty=a; }
                    804:   switch(tx)
                    805:   {
                    806:     case t_INT:
                    807:       switch(ty)
                    808:       {
                    809:        case t_INT:
                    810:          if (signe(p)<=0)
                    811:            return (signe(x)<0 && signe(y)<0)? -1: 1;
                    812:          a = odd(pvaluation(x,p,&u));
                    813:           b = odd(pvaluation(y,p,&v));
                    814:          if (egalii(p,gdeux))
                    815:           {
                    816:            z = (eps(u) && eps(v))? -1: 1;
                    817:            if (a && gome(v)) z= -z;
                    818:            if (b && gome(u)) z= -z;
                    819:           }
                    820:           else
                    821:          {
                    822:            z = (a && b && eps(p))? -1: 1;
                    823:            if (a && kronecker(v,p)<0) z= -z;
                    824:            if (b && kronecker(u,p)<0) z= -z;
                    825:          }
                    826:          avma=av; return z;
                    827:        case t_REAL:
                    828:          return (signe(x)<0 && signe(y)<0)? -1: 1;
                    829:        case t_INTMOD:
1.2     ! noro      830:           p = (GEN)y[1];
        !           831:          if (egalii(gdeux,p)) err(hiler1);
        !           832:          return hil(x,(GEN)y[2],p);
1.1       noro      833:        case t_FRAC: case t_FRACN:
                    834:          p1=mulii((GEN)y[1],(GEN)y[2]); z=hil(x,p1,p);
                    835:          avma=av; return z;
                    836:        case t_PADIC:
1.2     ! noro      837:           p = (GEN)y[2];
        !           838:          if (egalii(gdeux,p) && precp(y) <= 1) err(hiler1);
        !           839:          p1 = odd(valp(y))? mulii(p,(GEN)y[4]): (GEN)y[4];
        !           840:          z=hil(x,p1,p); avma=av; return z;
1.1       noro      841:       }
                    842:       break;
                    843:
                    844:     case t_REAL:
                    845:       if (! is_frac_t(ty)) break;
                    846:       if (signe(x) > 0) return 1;
                    847:       return signe(y[1])*signe(y[2]);
                    848:
                    849:     case t_INTMOD:
1.2     ! noro      850:       p = (GEN)x[1];
        !           851:       if (egalii(gdeux,p)) err(hiler1);
1.1       noro      852:       switch(ty)
                    853:       {
                    854:         case t_INTMOD:
1.2     ! noro      855:           if (!egalii(p, (GEN)y[1])) break;
        !           856:           return hil((GEN)x[2],(GEN)y[2],p);
1.1       noro      857:         case t_FRAC: case t_FRACN:
1.2     ! noro      858:          return hil((GEN)x[2],y,p);
1.1       noro      859:         case t_PADIC:
1.2     ! noro      860:           if (!egalii(p, (GEN)y[2])) break;
        !           861:           return hil((GEN)x[2],y,p);
1.1       noro      862:       }
                    863:       break;
                    864:
                    865:     case t_FRAC: case t_FRACN:
                    866:       p1=mulii((GEN)x[1],(GEN)x[2]);
                    867:       switch(ty)
                    868:       {
                    869:        case t_FRAC: case t_FRACN:
                    870:          p2=mulii((GEN)y[1],(GEN)y[2]);
                    871:          z=hil(p1,p2,p); avma=av; return z;
                    872:        case t_PADIC:
                    873:          z=hil(p1,y,NULL); avma=av; return z;
                    874:       }
                    875:       break;
                    876:
                    877:     case t_PADIC:
1.2     ! noro      878:       p = (GEN)x[2];
        !           879:       if (ty != t_PADIC || !egalii(p,(GEN)y[2])) break;
        !           880:       if (egalii(p, gdeux) && (precp(x) <= 1 || precp(y) <= 1)) err(hiler1);
        !           881:       p1 = odd(valp(x))? mulii(p,(GEN)x[4]): (GEN)x[4];
        !           882:       p2 = odd(valp(y))? mulii(p,(GEN)y[4]): (GEN)y[4];
        !           883:       z=hil(p1,p2,p); avma=av; return z;
1.1       noro      884:   }
                    885:   err(talker,"forbidden or incompatible types in hil");
                    886:   return 0; /* not reached */
                    887: }
                    888: #undef eps
                    889: #undef ome
                    890: #undef gome
                    891:
                    892: /*******************************************************************/
                    893: /*                                                                 */
                    894: /*                       SQUARE ROOT MODULO p                      */
                    895: /*                                                                 */
                    896: /*******************************************************************/
                    897:
                    898: #define sqrmod(x,p) (resii(sqri(x),p))
                    899:
1.2     ! noro      900: static GEN ffsqrtmod(GEN a, GEN p);
        !           901:
        !           902: /* Tonelli-Shanks. Assume p is prime and return NULL if (a,p) = -1. */
1.1       noro      903: GEN
                    904: mpsqrtmod(GEN a, GEN p)
                    905: {
1.2     ! noro      906:   gpmem_t av = avma, av1,lim;
        !           907:   long i,k,e;
1.1       noro      908:   GEN p1,q,v,y,w,m;
                    909:
                    910:   if (typ(a) != t_INT || typ(p) != t_INT) err(arither1);
                    911:   if (signe(p) <= 0 || is_pm1(p)) err(talker,"not a prime in mpsqrtmod");
                    912:   p1 = addsi(-1,p); e = vali(p1);
1.2     ! noro      913:
        !           914:   /* If `e' is "too big", use Cipolla algorithm ! [GTL] */
        !           915:   if (e*(e-1) > 20 + 8 * bit_accuracy(lgefint(p)))
        !           916:   {
        !           917:     v = ffsqrtmod(a,p);
        !           918:     if (!v) { avma = av; return NULL; }
        !           919:     return gerepileuptoint(av,v);
        !           920:   }
        !           921:
1.1       noro      922:   if (e == 0) /* p = 2 */
                    923:   {
                    924:     avma = av;
                    925:     if (!egalii(p, gdeux))
                    926:       err(talker,"composite modulus in mpsqrtmod: %Z",p);
                    927:     if (!signe(a) || !mod2(a)) return gzero;
                    928:     return gun;
                    929:   }
                    930:   q = shifti(p1,-e); /* q = (p-1)/2^oo is odd */
                    931:   if (e == 1) y = p1;
                    932:   else /* look for an odd power of a primitive root */
                    933:     for (k=2; ; k++)
                    934:     { /* loop terminates for k < p (even if p composite) */
                    935:
                    936:       i = krosg(k,p);
                    937:       if (i >= 0)
                    938:       {
                    939:         if (i) continue;
                    940:         err(talker,"composite modulus in mpsqrtmod: %Z",p);
                    941:       }
                    942:       av1 = avma;
                    943:       y = m = powmodulo(stoi(k),q,p);
                    944:       for (i=1; i<e; i++)
                    945:        if (gcmp1(m = sqrmod(m,p))) break;
                    946:       if (i == e) break; /* success */
                    947:       avma = av1;
                    948:     }
                    949:
                    950:   p1 = powmodulo(a, shifti(q,-1), p); /* a ^ [(q-1)/2] */
                    951:   if (!signe(p1)) { avma=av; return gzero; }
                    952:   v = modii(mulii(a, p1), p);
                    953:   w = modii(mulii(v, p1), p);
                    954:   lim = stack_lim(av,1);
                    955:   while (!gcmp1(w))
                    956:   { /* a*w = v^2, y primitive 2^e-th root of 1
                    957:        a square --> w even power of y, hence w^(2^(e-1)) = 1 */
                    958:     p1 = sqrmod(w,p);
                    959:     for (k=1; !gcmp1(p1) && k < e; k++) p1 = sqrmod(p1,p);
                    960:     if (k == e) { avma=av; return NULL; } /* p composite or (a/p) != 1 */
                    961:     /* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */
                    962:     p1 = y;
                    963:     for (i=1; i < e-k; i++) p1 = sqrmod(p1,p);
                    964:     y = sqrmod(p1, p); e = k;
                    965:     w = modii(mulii(y, w), p);
                    966:     v = modii(mulii(v, p1), p);
                    967:     if (low_stack(lim, stack_lim(av,1)))
                    968:     {
                    969:       GEN *gptr[3]; gptr[0]=&y; gptr[1]=&w; gptr[2]=&v;
                    970:       if(DEBUGMEM>1) err(warnmem,"mpsqrtmod");
                    971:       gerepilemany(av,gptr,3);
                    972:     }
                    973:   }
                    974:   av1 = avma;
                    975:   p1 = subii(p,v); if (cmpii(v,p1) > 0) v = p1; else avma = av1;
                    976:   return gerepileuptoint(av, v);
                    977: }
                    978:
1.2     ! noro      979: /* Cipolla's algorithm is better when e = v_2(p-1) is "too big".
        !           980:  * Otherwise, is a constant times worse than the above one.
        !           981:  * For p = 3 (mod 4), is about 3 times worse, and in average
        !           982:  * is about 2 or 2.5 times worse.
        !           983:  *
        !           984:  * But try both algorithms for e.g. S(n)=(2^n+3)^2-8 with
        !           985:  * n = 750, 771, 779, 790, 874, 1176, 1728, 2604, etc.
        !           986:  *
        !           987:  * If X^2 = t^2 - a  is not a square in F_p, then
        !           988:  *
        !           989:  *   (t+X)^(p+1) = (t+X)(t-X) = a
        !           990:  *
        !           991:  * so we get sqrt(a) in F_p^2 by
        !           992:  *
        !           993:  *   sqrt(a) = (t+X)^((p+1)/2)
        !           994:  *
        !           995:  * If (a|p)=1, then sqrt(a) is in F_p.
        !           996:  *
        !           997:  * cf: LNCS 2286, pp 430-434 (2002)  [Gonzalo Tornaria] */
        !           998: static GEN
        !           999: ffsqrtmod(GEN a, GEN p)
        !          1000: {
        !          1001:   gpmem_t av = avma, av1, lim;
        !          1002:   long e, t, man, k, nb;
        !          1003:   GEN q, n, u, v, d, d2, b, u2, v2, qptr;
        !          1004:
        !          1005:   if (kronecker(a, p) < 0) return NULL;
        !          1006:
        !          1007:   av1 = avma;
        !          1008:   for(t=1; ; t++)
        !          1009:   {
        !          1010:     n = subsi(t*t, a);
        !          1011:     if (kronecker(n, p) < 0) break;
        !          1012:     avma = av1;
        !          1013:   }
        !          1014:
        !          1015:   u = stoi(t); v = gun; /* u+vX = t+X */
        !          1016:   e = vali(addsi(-1,p)); q = shifti(p, -e);
        !          1017:   /* p = 2^e q + 1  and  (p+1)/2 = 2^(e-1)q + 1 */
        !          1018:
        !          1019:   /* Compute u+vX := (t+X)^q */
        !          1020:   av1 = avma; lim = stack_lim(av1, 1);
        !          1021:   qptr = q+2; man = *qptr;
        !          1022:   k = 1+bfffo(man); man<<=k; k=BITS_IN_LONG-k;
        !          1023:   for (nb=lgefint(q)-2;nb; nb--)
        !          1024:   {
        !          1025:     for (; k; man<<=1, k--)
        !          1026:     {
        !          1027:       if (man < 0)
        !          1028:       { /* u+vX := (u+vX)^2 (t+X) */
        !          1029:         d = addii(u, mulsi(t,v));
        !          1030:         d2 = sqri(d);
        !          1031:         b = resii(mulii(a,v), p);
        !          1032:         u = modii(subii(mulsi(t,d2), mulii(b,addii(u,d))), p);
        !          1033:         v = modii(subii(d2, mulii(b,v)), p);
        !          1034:       }
        !          1035:       else
        !          1036:       { /* u+vX := (u+vX)^2 */
        !          1037:         u2 = sqri(u);
        !          1038:         v2 = sqri(v);
        !          1039:         v = modii(subii(sqri(addii(v,u)), addii(u2,v2)), p);
        !          1040:         u = modii(addii(u2, mulii(v2,n)), p);
        !          1041:       }
        !          1042:     }
        !          1043:
        !          1044:     if (low_stack(lim, stack_lim(av1, 1)))
        !          1045:     {
        !          1046:        GEN *gptr[2]; gptr[0]=&u; gptr[1]=&v;
        !          1047:        if (DEBUGMEM>1) err(warnmem, "ffsqrtmod");
        !          1048:        gerepilemany(av1,gptr,2);
        !          1049:     }
        !          1050:
        !          1051:     man = *++qptr; k = BITS_IN_LONG;
        !          1052:   }
        !          1053:
        !          1054:   while (--e)
        !          1055:   { /* u+vX := (u+vX)^2 */
        !          1056:     u2 = sqri(u);
        !          1057:     v2 = sqri(v);
        !          1058:     v = modii(subii(sqri(addii(v,u)), addii(u2,v2)), p);
        !          1059:     u = modii(addii(u2, mulii(v2,n)), p);
        !          1060:
        !          1061:     if (low_stack(lim, stack_lim(av1, 1)))
        !          1062:     {
        !          1063:        GEN *gptr[2]; gptr[0]=&u; gptr[1]=&v;
        !          1064:        if (DEBUGMEM>1) err(warnmem, "ffsqrtmod");
        !          1065:        gerepilemany(av1,gptr,2);
        !          1066:     }
        !          1067:   }
        !          1068:
        !          1069:   /* Now u+vX = (t+X)^(2^(e-1)q); thus
        !          1070:    *
        !          1071:    *   (u+vX)(t+X) = sqrt(a) + 0 X
        !          1072:    *
        !          1073:    * Whence,
        !          1074:    *
        !          1075:    *   sqrt(a) = (u+vt)t - v*a
        !          1076:    *   0       = (u+vt)
        !          1077:    *
        !          1078:    * Thus a square root is v*a */
        !          1079:
        !          1080:   v = modii(mulii(v,a), p);
        !          1081:
        !          1082:   u = subii(p,v); if (cmpii(v,u) > 0) v = u;
        !          1083:   return gerepileuptoint(av,v);
        !          1084: }
        !          1085:
1.1       noro     1086: /*******************************************************************/
                   1087: /*                                                                 */
                   1088: /*                       n-th ROOT MODULO p                        */
                   1089: /*                                                                 */
                   1090: /*******************************************************************/
                   1091:
                   1092: /* UNCLEAN
                   1093:  * p-1=l^e*r
                   1094:  * l doit etre premier
                   1095:  * q=p-1
                   1096:  * q=(l^e)*r
                   1097:  * e>=1
                   1098:  * pgcd(r,l)=1
                   1099:  * return a non l-power residue and set zeta to a primitive l root of unity.
                   1100:  */
                   1101:
                   1102: static GEN
                   1103: mplgenmod(GEN l, long e, GEN r,GEN p,GEN *zeta)
                   1104: {
1.2     ! noro     1105:   const gpmem_t av1 = avma;
1.1       noro     1106:   GEN m,m1;
                   1107:   long k,i;
                   1108:   for (k=1; ; k++)
                   1109:   {
                   1110:     m1 = m = powmodulo(stoi(k+1),r,p);
1.2     ! noro     1111:     if (gcmp1(m)) {avma=av1; continue;}
1.1       noro     1112:     for (i=1; i<e; i++)
                   1113:       if (gcmp1(m=powmodulo(m,l,p))) break;
                   1114:     if (i==e) break;
                   1115:     avma = av1;
                   1116:   }
                   1117:   *zeta=m;
                   1118:   return m1;
                   1119: }
                   1120: /* resoud x^l=a mod (p)
                   1121:  * l doit etre premier
                   1122:  * q=p-1
                   1123:  * q=(l^e)*r
                   1124:  * e>=1
                   1125:  * pgcd(r,l)=1
                   1126:  * m=y^(q/l)
                   1127:  * y n'est pas une puissance l-ieme
                   1128:  * m!=1
                   1129:  * ouf!
                   1130:  */
                   1131: GEN Fp_shanks(GEN x,GEN g0,GEN p, GEN q);
                   1132: static GEN
                   1133: mpsqrtlmod(GEN a, GEN l, GEN p, GEN q,long e, GEN r, GEN y, GEN m)
                   1134: {
1.2     ! noro     1135:   gpmem_t av = avma, tetpil,lim;
1.1       noro     1136:   long k;
                   1137:   GEN p1,u1,u2,v,w,z,dl;
                   1138:   /* y contient un generateur de (Z/pZ)^* eleve a la puis (p-1)/(l^e) */
1.2     ! noro     1139:   (void)bezout(r,l,&u1,&u2);
1.1       noro     1140:   v=powmodulo(a,u2,p);
                   1141:   w=powmodulo(a,modii(mulii(negi(u1),r),q),p);
                   1142:   lim = stack_lim(av,1);
                   1143:   while (!gcmp1(w))
                   1144:   {
                   1145:     /* if p is not prime, next loop will not end */
                   1146:     k=0;
                   1147:     p1=w;
                   1148:     do
                   1149:     {
                   1150:       z=p1;
                   1151:       p1=powmodulo(p1,l,p);
                   1152:       k++;
                   1153:     }while(!gcmp1(p1));
                   1154:     if (k==e) { avma=av; return NULL; }
                   1155:     dl=Fp_shanks(mpinvmod(z,p),m,p,l);
                   1156:     p1=powmodulo(y,modii(mulii(dl,gpowgs(l,e-k-1)),q),p);
                   1157:     m=powmodulo(m,dl,p);
                   1158:     e = k;
                   1159:     v = modii(mulii(p1,v),p);
                   1160:     y = powmodulo(p1,l,p);
                   1161:     w = modii(mulii(y,w),p);
                   1162:     if (low_stack(lim, stack_lim(av,1)))
                   1163:     {
                   1164:       GEN *gptr[4];
                   1165:       if(DEBUGMEM>1) err(warnmem,"mpsqrtlmod");
                   1166:       gptr[0]=&y; gptr[1]=&v; gptr[2]=&w; gptr[3]=&m;
                   1167:       gerepilemany(av,gptr,4);
                   1168:     }
                   1169:   }
                   1170:   tetpil=avma; return gerepile(av,tetpil,icopy(v));
                   1171: }
                   1172: /* a and n are integers, p is prime
                   1173:
                   1174: return a solution of
                   1175:
                   1176: x^n=a mod p
                   1177:
                   1178: 1)If there is no solution return NULL and if zetan is not NULL set zetan to gzero.
                   1179:
                   1180: 2) If there is solution there are exactly  m=gcd(p-1,n) of them.
                   1181:
                   1182: If zetan is not NULL, zetan is set to a primitive mth root of unity so that
                   1183: the set of solutions is {x*zetan^k;k=0 to m-1}
                   1184:
                   1185: If a=0 ,return 0 and if zetan is not NULL zetan is set to gun
                   1186: */
                   1187: GEN
                   1188: mpsqrtnmod(GEN a, GEN n, GEN p, GEN *zetan)
                   1189: {
1.2     ! noro     1190:   gpmem_t ltop=avma,lbot=0,av1,lim;
1.1       noro     1191:   GEN m,u1,u2;
                   1192:   GEN q,z;
                   1193:   GEN *gptr[2];
                   1194:   if (typ(a) != t_INT || typ(n) != t_INT || typ(p)!=t_INT)
                   1195:     err(typeer,"mpsqrtnmod");
                   1196:   if(!signe(n))
                   1197:     err(talker,"1/0 exponent in mpsqrtnmod");
                   1198:   if(gcmp1(n)) {if (zetan) *zetan=gun;return gcopy(a);}
                   1199:   a=modii(a,p);
                   1200:   if(gcmp0(a)) {if (zetan) *zetan=gun;avma=ltop;return gzero;}
                   1201:   q=addsi(-1,p);
                   1202:   m=bezout(n,q,&u1,&u2);
                   1203:   if (zetan) z=gun;
                   1204:   lim=stack_lim(ltop,1);
                   1205:   if (!gcmp1(m))
                   1206:   {
                   1207:     GEN F=decomp(m);
                   1208:     long i,j,e;
                   1209:     GEN r,zeta,y,l;
                   1210:     av1=avma;
                   1211:     for (i = lg(F[1])-1; i; i--)
                   1212:     {
                   1213:       l=gcoeff(F,i,1); j=itos(gcoeff(F,i,2));
                   1214:       e=pvaluation(q,l,&r);
                   1215:       y=mplgenmod(l,e,r,p,&zeta);
                   1216:       if (zetan) z=modii(mulii(z,powmodulo(y,gpowgs(l,e-j),p)),p);
                   1217:       do
                   1218:       {
                   1219:        lbot=avma;
                   1220:        if (!is_pm1(a) || signe(a)<0)
                   1221:          a=mpsqrtlmod(a,l,p,q,e,r,y,zeta);
                   1222:        else
                   1223:          a=icopy(a);
                   1224:        if (!a){avma=ltop;if (zetan)  *zetan=gzero;return NULL;}
                   1225:        j--;
                   1226:       }while (j);
                   1227:       if (low_stack(lim, stack_lim(ltop,1)))
                   1228:        /* n can have lots of prime factors*/
                   1229:       {
                   1230:        if(DEBUGMEM>1) err(warnmem,"mpsqrtnmod");
                   1231:        if (zetan)
                   1232:        {
                   1233:          z=gcopy(z);
                   1234:          gptr[0]=&a;gptr[1]=&z;
                   1235:          gerepilemanysp(av1,lbot,gptr,2);
                   1236:        }
                   1237:        else
                   1238:          a=gerepile(av1,lbot,a);
                   1239:        lbot=av1;
                   1240:       }
                   1241:     }
                   1242:   }
                   1243:   if (cmpii(m,n))
                   1244:   {
                   1245:     GEN b=modii(u1,q);
                   1246:     lbot=avma;
                   1247:     a=powmodulo(a,b,p);
                   1248:   }
                   1249:   if (zetan)
                   1250:   {
                   1251:     *zetan=gcopy(z);
                   1252:     gptr[0]=&a;gptr[1]=zetan;
                   1253:     gerepilemanysp(ltop,lbot,gptr,2);
                   1254:   }
                   1255:   else
                   1256:     a=gerepile(ltop,lbot,a);
                   1257:   return a;
                   1258: }
                   1259:
                   1260: /*********************************************************************/
                   1261: /**                                                                 **/
                   1262: /**                        GCD & BEZOUT                             **/
                   1263: /**                                                                 **/
                   1264: /*********************************************************************/
                   1265:
                   1266: /* Ultra-fast private ulong gcd for trial divisions.  Called with y odd;
                   1267:    x can be arbitrary (but will most of the time be smaller than y).
                   1268:    Will also be used from inside ifactor2.c, so it's `semi-private' really.
                   1269:    --GN */
                   1270:
                   1271: /* Gotos are Harmful, and Programming is a Science.  E.W.Dijkstra. */
                   1272: ulong
                   1273: ugcd(ulong x, ulong y)         /* assume y&1==1, y > 1 */
                   1274: {
                   1275:   if (!x) return y;
                   1276:   /* fix up x */
                   1277:   while (!(x&1)) x>>=1;
                   1278:   if (x==1) return 1;
                   1279:   if (x==y) return y;
                   1280:   else if (x>y) goto xislarger;/* will be rare, given how we'll use this */
                   1281:   /* loop invariants: x,y odd and distinct. */
                   1282:  yislarger:
                   1283:   if ((x^y)&2)                 /* ...01, ...11 or vice versa */
                   1284:     y=(x>>2)+(y>>2)+1;         /* ==(x+y)>>2 except it can't overflow */
                   1285:   else                         /* ...01,...01 or ...11,...11 */
                   1286:     y=(y-x)>>2;                /* now y!=0 in either case */
                   1287:   while (!(y&1)) y>>=1;        /* kill any windfall-gained powers of 2 */
                   1288:   if (y==1) return 1;          /* comparand == return value... */
                   1289:   if (x==y) return y;          /* this and the next is just one comparison */
                   1290:   else if (x<y) goto yislarger;/* else fall through to xislarger */
                   1291:
                   1292:  xislarger:                    /* same as above, seen through a mirror */
                   1293:   if ((x^y)&2)
                   1294:     x=(x>>2)+(y>>2)+1;
                   1295:   else
                   1296:     x=(x-y)>>2;                /* x!=0 */
                   1297:   while (!(x&1)) x>>=1;
                   1298:   if (x==1) return 1;
                   1299:   if (x==y) return y;
                   1300:   else if (x>y) goto xislarger;/* again, a decent [g]cc should notice that
                   1301:                                   it can re-use the comparison */
                   1302:   goto yislarger;
                   1303: }
                   1304: /* Gotos are useful, and Programming is an Art.  D.E.Knuth. */
                   1305: /* PS: Of course written with Dijkstra's lessons firmly in mind... --GN */
                   1306:
                   1307: /* modified right shift binary algorithm with at most one division */
                   1308: long
                   1309: cgcd(long a,long b)
                   1310: {
                   1311:   long v;
                   1312:   a=labs(a); if (!b) return a;
                   1313:   b=labs(b); if (!a) return b;
                   1314:   if (a>b) { a %= b; if (!a) return b; }
                   1315:   else { b %= a; if (!b) return a; }
                   1316:   v=vals(a|b); a>>=v; b>>=v;
                   1317:   if (a==1 || b==1) return 1L<<v;
                   1318:   if (b&1)
                   1319:     return ((long)ugcd((ulong)a, (ulong)b)) << v;
                   1320:   else
                   1321:     return ((long)ugcd((ulong)b, (ulong)a)) << v;
                   1322: }
                   1323: long
                   1324: clcm(long a,long b)
                   1325: {
                   1326:   long d;
                   1327:   if(!a) return 0;
                   1328:   d=cgcd(a,b);
                   1329:   if(d!=1) return a*(b/d);
                   1330:   return a*b;
                   1331: }
                   1332:
                   1333: /* assume a>b>0, return gcd(a,b) as a GEN (for mppgcd) */
                   1334: static GEN
                   1335: mppgcd_cgcd(ulong a, ulong b)
                   1336: {
                   1337:   GEN r = cgeti(3);
                   1338:   long v;
                   1339:
                   1340:   r[1] = evalsigne(1)|evallgefint(3);
                   1341:   a %= b; if (!a) { r[2]=(long)b; return r; }
                   1342:   v=vals(a|b); a>>=v; b>>=v;
                   1343:   if (a==1 || b==1) { r[2]=(long)(1UL<<v); return r; }
                   1344:   if (b&1)
                   1345:     r[2] = (long)(ugcd((ulong)a, (ulong)b) << v);
                   1346:   else
                   1347:     r[2] = (long)(ugcd((ulong)b, (ulong)a) << v);
                   1348:   return r;
                   1349: }
                   1350:
                   1351: void mppgcd_plus_minus(GEN x, GEN y, GEN t);
                   1352: ulong mppgcd_resiu(GEN y, ulong x);
                   1353:
                   1354: /* uses modified right-shift binary algorithm now --GN 1998Jul23 */
                   1355: GEN
                   1356: mppgcd(GEN a, GEN b)
                   1357: {
1.2     ! noro     1358:   long v, w;
        !          1359:   gpmem_t av;
1.1       noro     1360:   GEN t, p1;
                   1361:
                   1362:   if (typ(a) != t_INT || typ(b) != t_INT) err(arither1);
                   1363:   switch (absi_cmp(a,b))
                   1364:   {
                   1365:     case 0: return absi(a);
                   1366:     case -1: t=b; b=a; a=t;
                   1367:   }
                   1368:   if (!signe(b)) return absi(a);
                   1369:   /* here |a|>|b|>0. Try single precision first */
                   1370:   if (lgefint(a)==3)
                   1371:     return mppgcd_cgcd((ulong)a[2], (ulong)b[2]);
                   1372:   if (lgefint(b)==3)
                   1373:   {
                   1374:     ulong u = mppgcd_resiu(a,(ulong)b[2]);
                   1375:     if (!u) return absi(b);
                   1376:     return mppgcd_cgcd((ulong)b[2], u);
                   1377:   }
                   1378:
                   1379:   /* larger than gcd: "avma=av" gerepile (erasing t) is valid */
1.2     ! noro     1380:   av = avma; (void)new_chunk(lgefint(b)); /* HACK */
1.1       noro     1381:   t = resii(a,b);
                   1382:   if (!signe(t)) { avma=av; return absi(b); }
                   1383:
                   1384:   a = b; b = t;
                   1385:   v = vali(a); a = shifti(a,-v); setsigne(a,1);
                   1386:   w = vali(b); b = shifti(b,-w); setsigne(b,1);
                   1387:   if (w < v) v = w;
                   1388:   switch(absi_cmp(a,b))
                   1389:   {
                   1390:     case  0: avma=av; a=shifti(a,v); return a;
                   1391:     case -1: p1=b; b=a; a=p1;
                   1392:   }
                   1393:   if (is_pm1(b)) { avma=av; return shifti(gun,v); }
                   1394:
                   1395:   /* we have three consecutive memory locations: a,b,t.
                   1396:    * All computations are done in place */
                   1397:
                   1398:   /* a and b are odd now, and a>b>1 */
                   1399:   while (lgefint(a) > 3)
                   1400:   {
                   1401:     /* if a=b mod 4 set t=a-b, otherwise t=a+b, then strip powers of 2 */
                   1402:     /* so that t <= (a+b)/4 < a/2 */
                   1403:     mppgcd_plus_minus(a,b, t);
                   1404:     if (is_pm1(t)) { avma=av; return shifti(gun,v); }
                   1405:     switch(absi_cmp(t,b))
                   1406:     {
                   1407:       case -1: p1 = a; a = b; b = t; t = p1; break;
                   1408:       case  1: p1 = a; a = t; t = p1; break;
                   1409:       case  0: avma = av; b=shifti(b,v); return b;
                   1410:     }
                   1411:   }
                   1412:   {
1.2     ! noro     1413:     long r[] = {evaltyp(t_INT)|_evallg(3), evalsigne(1)|evallgefint(3), 0};
1.1       noro     1414:     r[2] = (long) ugcd((ulong)b[2], (ulong)a[2]);
                   1415:     avma = av; return shifti(r,v);
                   1416:   }
                   1417: }
                   1418:
                   1419: GEN
                   1420: mpppcm(GEN x, GEN y)
                   1421: {
1.2     ! noro     1422:   gpmem_t av;
1.1       noro     1423:   GEN p1,p2;
                   1424:   if (typ(x) != t_INT || typ(y) != t_INT) err(arither1);
                   1425:   if (!signe(x)) return gzero;
                   1426:   av = avma;
                   1427:   p1 = mppgcd(x,y); if (!is_pm1(p1)) y = divii(y,p1);
                   1428:   p2 = mulii(x,y);
                   1429:   if (signe(p2) < 0) setsigne(p2,1);
                   1430:   return gerepileuptoint(av, p2);
                   1431: }
                   1432:
                   1433: /*********************************************************************/
                   1434: /**                                                                 **/
                   1435: /**                      CHINESE REMAINDERS                         **/
                   1436: /**                                                                 **/
                   1437: /*********************************************************************/
                   1438:
                   1439: /*  P.M. & M.H.
                   1440:  *
                   1441:  *  Chinese Remainder Theorem.  x and y must have the same type (integermod,
                   1442:  *  polymod, or polynomial/vector/matrix recursively constructed with these
                   1443:  *  as coefficients). Creates (with the same type) a z in the same residue
                   1444:  *  class as x and the same residue class as y, if it is possible.
                   1445:  *
                   1446:  *  We also allow (during recursion) two identical objects even if they are
                   1447:  *  not integermod or polymod. For example, if
                   1448:  *
                   1449:  *    x = [1. mod(5, 11), mod(X + mod(2, 7), X^2 + 1)]
                   1450:  *    y = [1, mod(7, 17), mod(X + mod(0, 3), X^2 + 1)],
                   1451:  *
                   1452:  *  then chinois(x, y) returns
                   1453:  *
                   1454:  *    [1, mod(16, 187), mod(X + mod(9, 21), X^2 + 1)]
                   1455:  *
                   1456:  *  Someone else may want to allow power series, complex numbers, and
                   1457:  *  quadratic numbers.
                   1458:  */
                   1459:
                   1460: GEN chinese(GEN x, GEN y)
                   1461: {
                   1462:   return gassoc_proto(chinois,x,y);
                   1463: }
                   1464:
                   1465: GEN
                   1466: chinois(GEN x, GEN y)
                   1467: {
1.2     ! noro     1468:   gpmem_t av,tetpil;
        !          1469:   long i,lx,vx, tx = typ(x);
1.1       noro     1470:   GEN z,p1,p2,d,u,v;
                   1471:
                   1472:   if (gegal(x,y)) return gcopy(x);
                   1473:   if (tx == typ(y)) switch(tx)
                   1474:   {
                   1475:     case t_POLMOD:
                   1476:       if (gegal((GEN)x[1],(GEN)y[1]))  /* same modulus */
                   1477:       {
                   1478:        z=cgetg(3,tx);
                   1479:        z[1]=lcopy((GEN)x[1]);
                   1480:        z[2]=(long)chinois((GEN)x[2],(GEN)y[2]);
                   1481:         return z;
                   1482:       }  /* fall through */
                   1483:     case t_INTMOD:
                   1484:       z=cgetg(3,tx); av=avma;
                   1485:       d=gbezout((GEN)x[1],(GEN)y[1],&u,&v);
                   1486:       if (!gegal(gmod((GEN)x[2],d), gmod((GEN)y[2],d))) break;
                   1487:       p1 = gdiv((GEN)x[1],d);
                   1488:       p2 = gadd((GEN)x[2], gmul(gmul(u,p1), gadd((GEN)y[2],gneg((GEN)x[2]))));
                   1489:
                   1490:       tetpil=avma; z[1]=lmul(p1,(GEN)y[1]); z[2]=lmod(p2,(GEN)z[1]);
                   1491:       gerepilemanyvec(av,tetpil,z+1,2); return z;
                   1492:
                   1493:     case t_POL:
                   1494:       lx=lgef(x); vx=varn(x); z=cgetg(lx,tx);
                   1495:       if (lx!=lgef(y) || vx!=varn(y)) break;
                   1496:       z[1]=evalsigne(1)|evallgef(lx)|evalvarn(vx);
                   1497:       for (i=2; i<lx; i++) z[i]=(long)chinois((GEN)x[i],(GEN)y[i]);
                   1498:       return z;
                   1499:
                   1500:     case t_VEC: case t_COL: case t_MAT:
                   1501:       lx=lg(x); z=cgetg(lx,tx); if (lx!=lg(y)) break;
                   1502:       for (i=1; i<lx; i++) z[i]=(long)chinois((GEN)x[i],(GEN)y[i]);
                   1503:       return z;
                   1504:   }
                   1505:   err(talker,"incompatible arguments in chinois");
                   1506:   return NULL; /* not reached */
                   1507: }
                   1508:
                   1509: /* return lift(chinois(x2 mod x1, y2 mod y1))
                   1510:  * assume(x1,y1)=1, xi,yi integers and z1 = x1*y1
                   1511:  */
                   1512: GEN
                   1513: chinois_int_coprime(GEN x2, GEN y2, GEN x1, GEN y1, GEN z1)
                   1514: {
1.2     ! noro     1515:   gpmem_t av = avma;
1.1       noro     1516:   GEN ax,p1;
                   1517:   (void)new_chunk((lgefint(z1)<<1)+lgefint(x1)+lgefint(y1)); /* HACK */
                   1518:   ax = mulii(mpinvmod(x1,y1), x1);
                   1519:   p1 = addii(x2, mulii(ax, subii(y2,x2)));
                   1520:   avma = av; return modii(p1,z1);
                   1521: }
                   1522:
                   1523: /*********************************************************************/
                   1524: /**                                                                 **/
                   1525: /**                      INVERSE MODULO b                           **/
                   1526: /**                                                                 **/
                   1527: /*********************************************************************/
                   1528:
                   1529: GEN
                   1530: mpinvmod(GEN a, GEN m)
                   1531: {
                   1532:   GEN res;
                   1533:   if (! invmod(a,m,&res))
                   1534:     err(invmoder,"%Z",gmodulcp(res,m));
                   1535:   return res;
                   1536: }
                   1537:
                   1538: /*********************************************************************/
                   1539: /**                                                                 **/
1.2     ! noro     1540: /**                    MODULAR EXPONENTIATION                       **/
1.1       noro     1541: /**                                                                 **/
                   1542: /*********************************************************************/
1.2     ! noro     1543: extern ulong invrev(ulong b);
        !          1544: extern GEN resiimul(GEN x, GEN y);
        !          1545:
        !          1546: static GEN _resii(GEN x, GEN y) { return resii(x,y); }
        !          1547:
        !          1548: /* Montgomery reduction */
        !          1549:
        !          1550: typedef struct {
        !          1551:   GEN N;
        !          1552:   ulong inv; /* inv = -N^(-1) mod B, */
        !          1553: } montdata;
        !          1554:
        !          1555: void
        !          1556: init_montdata(GEN N, montdata *s)
        !          1557: {
        !          1558:   s->N = N;
        !          1559:   s->inv = (ulong) -invrev(modBIL(N));
        !          1560: }
1.1       noro     1561:
                   1562: GEN
                   1563: init_remainder(GEN M)
                   1564: {
                   1565:   GEN sM = cgetg(3, t_VEC);
                   1566:   sM[1] = (long)M;
1.2     ! noro     1567:   sM[2] = (long)linv( itor(M, lgefint(M) + 1) ); /* 1. / M */
1.1       noro     1568:   return sM;
                   1569: }
                   1570:
                   1571: /* optimal on UltraSPARC */
1.2     ! noro     1572: static long RESIIMUL_LIMIT   = 150;
        !          1573: static long MONTGOMERY_LIMIT = 32;
1.1       noro     1574:
                   1575: void
                   1576: setresiilimit(long n) { RESIIMUL_LIMIT = n; }
1.2     ! noro     1577: void
        !          1578: setmontgomerylimit(long n) { MONTGOMERY_LIMIT = n; }
1.1       noro     1579:
1.2     ! noro     1580: typedef struct {
        !          1581:   GEN N;
        !          1582:   GEN (*res)(GEN,GEN);
        !          1583:   GEN (*mulred)(GEN,GEN,GEN);
        !          1584: } muldata;
        !          1585:
        !          1586: /* reduction for multiplication by 2 */
        !          1587: static GEN
        !          1588: _redsub(GEN x, GEN N)
        !          1589: {
        !          1590:   return (cmpii(x,N) >= 0)? subii(x,N): x;
        !          1591: }
        !          1592: /* Montgomery reduction */
        !          1593: extern GEN red_montgomery(GEN T, GEN N, ulong inv);
        !          1594: static GEN
        !          1595: montred(GEN x, GEN N)
        !          1596: {
        !          1597:   return red_montgomery(x, ((montdata*)N)->N, ((montdata*)N)->inv);
        !          1598: }
        !          1599: /* 2x mod N */
        !          1600: static GEN
        !          1601: _muli2red(GEN x, GEN y/* ignored */, GEN N) {
        !          1602:   (void)y; return _redsub(shifti(x,1), N);
        !          1603: }
        !          1604: static GEN
        !          1605: _muli2montred(GEN x, GEN y/* ignored */, GEN N) {
        !          1606:   GEN n = ((montdata*)N)->N;
        !          1607:   GEN z = _muli2red(x,y, n);
        !          1608:   long l = lgefint(n);
        !          1609:   while (lgefint(z) > l) z = subii(z,n);
        !          1610:   return z;
        !          1611: }
        !          1612: static GEN
        !          1613: _muli2invred(GEN x, GEN y/* ignored */, GEN N) {
        !          1614:   return _muli2red(x,y, (GEN)N[1]);
        !          1615: }
        !          1616: /* xy mod N */
        !          1617: static GEN
        !          1618: _muliired(GEN x, GEN y, GEN N) { return resii(mulii(x,y), N); }
        !          1619: static GEN
        !          1620: _muliimontred(GEN x, GEN y, GEN N) { return montred(mulii(x,y), N); }
        !          1621: static GEN
        !          1622: _muliiinvred(GEN x, GEN y, GEN N) { return resiimul(mulii(x,y), N); }
        !          1623:
        !          1624: static GEN
        !          1625: _mul(void *data, GEN x, GEN y)
        !          1626: {
        !          1627:   muldata *D = (muldata *)data;
        !          1628:   return D->mulred(x,y,D->N);
        !          1629: }
        !          1630: static GEN
        !          1631: _sqr(void *data, GEN x)
        !          1632: {
        !          1633:   muldata *D = (muldata *)data;
        !          1634:   return D->res(sqri(x), D->N);
        !          1635: }
        !          1636:
        !          1637: /* A^k mod N */
1.1       noro     1638: GEN
1.2     ! noro     1639: powmodulo(GEN A, GEN k, GEN N)
1.1       noro     1640: {
1.2     ! noro     1641:   gpmem_t av = avma;
        !          1642:   long t,s, lN;
        !          1643:   int base_is_2, use_montgomery;
1.1       noro     1644:   GEN y;
1.2     ! noro     1645:   muldata  D;
        !          1646:   montdata S;
1.1       noro     1647:
1.2     ! noro     1648:   if (typ(A) != t_INT || typ(k) != t_INT || typ(N) != t_INT) err(arither1);
        !          1649:   s = signe(k);
1.1       noro     1650:   if (!s)
                   1651:   {
1.2     ! noro     1652:     t = signe(resii(A,N)); avma = av;
        !          1653:     return t? gun: gzero;
1.1       noro     1654:   }
1.2     ! noro     1655:   if (s < 0) y = mpinvmod(A,N);
1.1       noro     1656:   else
                   1657:   {
1.2     ! noro     1658:     y = modii(A,N);
        !          1659:     if (!signe(y)) { avma = av; return gzero; }
1.1       noro     1660:   }
1.2     ! noro     1661:
        !          1662:   base_is_2 = 0;
        !          1663:   if (lgefint(y) == 3) switch(y[2])
1.1       noro     1664:   {
1.2     ! noro     1665:     case 1: avma = av; return gun;
        !          1666:     case 2: base_is_2 = 1; break;
1.1       noro     1667:   }
                   1668:
                   1669:   /* TODO: Move this out of here and use for general modular computations */
1.2     ! noro     1670:   lN = lgefint(N);
        !          1671:   use_montgomery = mod2(N) && lN < MONTGOMERY_LIMIT;
        !          1672:   if (use_montgomery)
        !          1673:   {
        !          1674:     init_montdata(N, &S);
        !          1675:     y = resii(shifti(y, bit_accuracy(lN)), N);
        !          1676:     D.mulred = base_is_2? &_muli2montred: &_muliimontred;
        !          1677:     D.res = &montred;
        !          1678:     D.N = (GEN)&S;
        !          1679:   }
        !          1680:   else if (lN > RESIIMUL_LIMIT
        !          1681:        && (lgefint(k) > 3 || (((double)k[2])*expi(A)) > 2 + expi(N)))
        !          1682:   {
        !          1683:     D.mulred = base_is_2? &_muli2invred: &_muliiinvred;
        !          1684:     D.res = &resiimul;
        !          1685:     D.N = init_remainder(N);
        !          1686:   }
        !          1687:   else
        !          1688:   {
        !          1689:     D.mulred = base_is_2? &_muli2red: &_muliired;
        !          1690:     D.res = &_resii;
        !          1691:     D.N = N;
        !          1692:   }
        !          1693:   y = leftright_pow(y, k, (void*)&D, &_sqr, &_mul);
        !          1694:   if (use_montgomery)
        !          1695:   {
        !          1696:     y = montred(y, (GEN)&S);
        !          1697:     if (cmpii(y,N) >= 0) y = subii(y,N);
1.1       noro     1698:   }
1.2     ! noro     1699:   return gerepileuptoint(av,y);
1.1       noro     1700: }
                   1701:
                   1702: /*********************************************************************/
                   1703: /**                                                                 **/
                   1704: /**                NEXT / PRECEDING (PSEUDO) PRIME                  **/
                   1705: /**                                                                 **/
                   1706: /*********************************************************************/
                   1707: GEN
1.2     ! noro     1708: gnextprime(GEN n) { return garith_proto(nextprime,n,0); }
1.1       noro     1709:
                   1710: GEN
1.2     ! noro     1711: gprecprime(GEN n) { return garith_proto(precprime,n,0); }
1.1       noro     1712:
                   1713: GEN
                   1714: gisprime(GEN x, long flag)
                   1715: {
                   1716:   switch (flag)
                   1717:   {
1.2     ! noro     1718:     case 0: return arith_proto(isprime,x,1);
        !          1719:     case 1: return garith_proto2gs(plisprime,x,1);
        !          1720:     case 2: return arith_proto(isprimeAPRCL,x,1);
1.1       noro     1721:   }
                   1722:   err(flagerr,"gisprime");
                   1723:   return 0;
                   1724: }
                   1725:
                   1726: long
1.2     ! noro     1727: isprimeSelfridge(GEN x) { return (plisprime(x,0)==gun); }
        !          1728:
        !          1729: /* assume x BSW pseudoprime. Check whether it's small enough to be certified
        !          1730:  * prime */
        !          1731: int
        !          1732: BSW_isprime_small(GEN x)
        !          1733: {
        !          1734:   long l = lgefint(x);
        !          1735:   if (l < 4) return 1;
        !          1736:   if (l == 4)
        !          1737:   {
        !          1738:     gpmem_t av = avma;
        !          1739:     long t = cmpii(x, u2toi(0x918UL, 0x4e72a000UL)); /* 10^13 */
        !          1740:     avma = av;
        !          1741:     if (t < 0) return 1;
        !          1742:   }
        !          1743:   return 0;
        !          1744: }
        !          1745:
        !          1746: /* assume x a BSW pseudoprime */
        !          1747: int
        !          1748: BSW_isprime(GEN x)
        !          1749: {
        !          1750:   gpmem_t av = avma;
        !          1751:   long l, res;
        !          1752:   GEN F, p;
        !          1753:
        !          1754:   if (BSW_isprime_small(x)) return 1;
        !          1755:   F = (GEN)auxdecomp(subis(x,1), 0)[1];
        !          1756:   l = lg(F); p = (GEN)F[l-1];
        !          1757:   if (BSW_psp(p))
        !          1758:   { /* smooth */
        !          1759:     GEN z = cgetg(3, t_VEC);
        !          1760:     z[1] = (long)x;
        !          1761:     z[2] = (long)F; res = isprimeSelfridge(z);
        !          1762:   }
        !          1763:   else
        !          1764:     res = isprimeAPRCL(x);
        !          1765:   avma = av; return res;
        !          1766: }
        !          1767:
        !          1768: long
1.1       noro     1769: isprime(GEN x)
                   1770: {
1.2     ! noro     1771:   return BSW_psp(x) && BSW_isprime(x);
1.1       noro     1772: }
                   1773:
                   1774: GEN
1.2     ! noro     1775: gispseudoprime(GEN x, long flag)
1.1       noro     1776: {
1.2     ! noro     1777:   if (flag == 0) return arith_proto(BSW_psp,x,1);
        !          1778:   return gmillerrabin(x, flag);
1.1       noro     1779: }
                   1780:
                   1781: long
1.2     ! noro     1782: ispseudoprime(GEN x, long flag)
1.1       noro     1783: {
1.2     ! noro     1784:   if (flag == 0) return BSW_psp(x);
        !          1785:   return millerrabin(x, flag);
1.1       noro     1786: }
                   1787:
                   1788: GEN
1.2     ! noro     1789: gispsp(GEN x) { return arith_proto(ispsp,x,1); }
        !          1790:
        !          1791: long
        !          1792: ispsp(GEN x) { return millerrabin(x,1); }
        !          1793:
        !          1794: GEN
        !          1795: gmillerrabin(GEN n, long k) { return arith_proto2gs(millerrabin,n,k); }
1.1       noro     1796:
                   1797: /*********************************************************************/
                   1798: /**                                                                 **/
                   1799: /**                    FUNDAMENTAL DISCRIMINANTS                    **/
                   1800: /**                                                                 **/
                   1801: /*********************************************************************/
                   1802: GEN
1.2     ! noro     1803: gisfundamental(GEN x) { return arith_proto(isfundamental,x,1); }
1.1       noro     1804:
                   1805: long
                   1806: isfundamental(GEN x)
                   1807: {
1.2     ! noro     1808:   long r;
1.1       noro     1809:   GEN p1;
                   1810:
                   1811:   if (gcmp0(x)) return 0;
                   1812:   r=mod4(x);
                   1813:   if (!r)
                   1814:   {
1.2     ! noro     1815:     const gpmem_t av = avma;
        !          1816:     p1=shifti(x,-2);
1.1       noro     1817:     r=mod4(p1); if (!r) return 0;
                   1818:     if (signe(x)<0) r=4-r;
                   1819:     r = (r==1)? 0: issquarefree(p1);
                   1820:     avma=av; return r;
                   1821:   }
                   1822:   if (signe(x)<0) r=4-r;
                   1823:   return (r==1) ? issquarefree(x) : 0;
                   1824: }
                   1825:
                   1826: GEN
                   1827: quaddisc(GEN x)
                   1828: {
1.2     ! noro     1829:   const gpmem_t av = avma;
        !          1830:   long i,r,tx=typ(x);
1.1       noro     1831:   GEN p1,p2,f,s;
                   1832:
                   1833:   if (tx != t_INT && ! is_frac_t(tx)) err(arither1);
                   1834:   f=factor(x); p1=(GEN)f[1]; p2=(GEN)f[2];
1.2     ! noro     1835:   s = gun;
1.1       noro     1836:   for (i=1; i<lg(p1); i++)
1.2     ! noro     1837:     if (odd(mael(p2,i,2))) s = gmul(s,(GEN)p1[i]);
1.1       noro     1838:   r=mod4(s); if (gsigne(x)<0) r=4-r;
1.2     ! noro     1839:   if (r>1) s = shifti(s,2);
        !          1840:   return gerepileuptoint(av, s);
1.1       noro     1841: }
                   1842:
                   1843: /*********************************************************************/
                   1844: /**                                                                 **/
                   1845: /**                              FACTORIAL                          **/
                   1846: /**                                                                 **/
                   1847: /*********************************************************************/
                   1848: GEN
                   1849: mpfact(long n)
                   1850: {
1.2     ! noro     1851:   const gpmem_t av = avma;
        !          1852:   long lx,k,l;
1.1       noro     1853:   GEN x;
                   1854:
                   1855:   if (n<2)
                   1856:   {
                   1857:     if (n<0) err(facter);
                   1858:     return gun;
                   1859:   }
                   1860:   if (n < 60)
                   1861:   {
                   1862:     x = gdeux;
                   1863:     for (k=3; k<=n; k++) x = mulsi(k,x);
                   1864:     return gerepileuptoint(av,x);
                   1865:   }
                   1866:   lx = 1; x = cgetg(1 + n/2, t_VEC);
                   1867:   for (k=2;; k++)
                   1868:   {
                   1869:     l = n+2-k; if (l <= k) break;
                   1870:     x[lx++] = (long)muluu(k,l);
                   1871:   }
                   1872:   if (l == k) x[lx++] = lstoi(k);
                   1873:   setlg(x, lx);
                   1874:   return gerepileuptoint(av, divide_conquer_prod(x, mulii));
                   1875: }
                   1876:
                   1877: GEN
                   1878: mpfactr(long n, long prec)
                   1879: {
1.2     ! noro     1880:   gpmem_t av = avma, lim;
        !          1881:   long k;
        !          1882:   GEN f = realun(prec);
1.1       noro     1883:
                   1884:   if (n<2)
                   1885:   {
                   1886:     if (n<0) err(facter);
                   1887:     return f;
                   1888:   }
                   1889:   lim = stack_lim(av,1);
                   1890:   for (k=2; k<=n; k++)
                   1891:   {
                   1892:     f = mulsr(k,f);
                   1893:     if (low_stack(lim, stack_lim(av,1)))
                   1894:     {
                   1895:       if(DEBUGMEM>1) err(warnmem,"mpfactr k=%ld",k);
                   1896:       f = gerepileuptoleaf(av,f);
                   1897:     }
                   1898:   }
                   1899:   return gerepileuptoleaf(av,f);
                   1900: }
                   1901:
                   1902: /*******************************************************************/
                   1903: /**                                                               **/
                   1904: /**                      LUCAS & FIBONACCI                        **/
                   1905: /**                                                               **/
                   1906: /*******************************************************************/
                   1907:
                   1908: void
                   1909: lucas(long n, GEN *ln, GEN *ln1)
                   1910: {
1.2     ! noro     1911:   gpmem_t av;
        !          1912:   long taille;
1.1       noro     1913:   GEN z,t;
                   1914:
1.2     ! noro     1915:   if (!n) { *ln = stoi(2); *ln1 = stoi(1); return; }
1.1       noro     1916:
1.2     ! noro     1917:   taille = 3 + (long)(pariC3 * (1+labs(n)));
        !          1918:   *ln = cgeti(taille);
        !          1919:   *ln1= cgeti(taille);
        !          1920:   av = avma; lucas(n/2, &z, &t);
1.1       noro     1921:   switch(n % 4)
                   1922:   {
                   1923:     case -3:
1.2     ! noro     1924:       addsiz(2,sqri(z), *ln1);
        !          1925:       subiiz(addsi(1,mulii(z,t)),*ln1, *ln); break;
        !          1926:     case -1:
        !          1927:       subisz(sqri(z),2, *ln1);
        !          1928:       subiiz(subis(mulii(z,t),1),*ln1, *ln); break;
        !          1929:     case  0: subisz(sqri(z),2,    *ln); subisz(mulii(z,t),1, *ln1); break;
        !          1930:     case  1: subisz(mulii(z,t),1, *ln); addsiz(2,sqri(t),    *ln1); break;
1.1       noro     1931:     case -2:
1.2     ! noro     1932:     case  2: addsiz(2,sqri(z),    *ln); addsiz(1,mulii(z,t), *ln1); break;
        !          1933:     case  3: addsiz(1,mulii(z,t), *ln); subisz(sqri(t),2,    *ln1);
1.1       noro     1934:   }
1.2     ! noro     1935:   avma = av;
1.1       noro     1936: }
                   1937:
                   1938: GEN
                   1939: fibo(long n)
                   1940: {
1.2     ! noro     1941:   gpmem_t av = avma;
1.1       noro     1942:   GEN ln,ln1;
                   1943:
                   1944:   lucas(n-1,&ln,&ln1);
                   1945:   return gerepileupto(av, divis(addii(shifti(ln,1),ln1), 5));
                   1946: }
                   1947:
                   1948: /*******************************************************************/
                   1949: /*                                                                 */
                   1950: /*                      CONTINUED FRACTIONS                        */
                   1951: /*                                                                 */
                   1952: /*******************************************************************/
1.2     ! noro     1953: static GEN
        !          1954: icopy_lg(GEN x, long l)
1.1       noro     1955: {
1.2     ! noro     1956:   long lx = lgefint(x);
        !          1957:   GEN y;
        !          1958:
        !          1959:   if (lx >= l) return icopy(x);
        !          1960:   y = cgeti(l); affii(x, y); return y;
1.1       noro     1961: }
                   1962:
1.2     ! noro     1963: /* if y != NULL, stop as soon as partial quotients differ from y */
        !          1964: static GEN
        !          1965: Qsfcont(GEN x, GEN y, long k)
1.1       noro     1966: {
1.2     ! noro     1967:   GEN  z, p1, p2, p3;
        !          1968:   long i, l, ly;
1.1       noro     1969:
1.2     ! noro     1970:   ly = lgefint(x[2]);
        !          1971:   l = 3 + (long) ((ly-2) / pariC3);
        !          1972:   if (k > 0 && ++k > 0 && l > k) l = k; /* beware overflow */
        !          1973:   if ((ulong)l > LGBITS) l = LGBITS;
        !          1974:
        !          1975:   p1 = (GEN)x[1];
        !          1976:   p2 = (GEN)x[2];
        !          1977:   z = cgetg(l,t_VEC);
        !          1978:   l--;
        !          1979:   if (y) {
        !          1980:     gpmem_t av = avma;
        !          1981:     if (l >= lg(y)) l = lg(y)-1;
        !          1982:     for (i = 1; i <= l; i++)
        !          1983:     {
        !          1984:       z[i] = y[i];
        !          1985:       p3 = p2; if (!gcmp1((GEN)z[i])) p3 = mulii((GEN)z[i], p2);
        !          1986:       p3 = subii(p1, p3);
        !          1987:       if (signe(p3) < 0)
        !          1988:       { /* partial quotient too large */
        !          1989:         p3 = addii(p3, p2);
        !          1990:         if (signe(p3) >= 0) i++; /* by 1 */
        !          1991:         break;
        !          1992:       }
        !          1993:       if (cmpii(p3, p2) >= 0)
        !          1994:       { /* partial quotient too small */
        !          1995:         p3 = subii(p3, p2);
        !          1996:         if (cmpii(p3, p2) < 0) i++; /* by 1 */
        !          1997:         break;
        !          1998:       }
        !          1999:       if ((i & 0xff) == 0) gerepileall(av, 2, &p2, &p3);
        !          2000:       p1 = p2; p2 = p3;
        !          2001:     }
        !          2002:   } else {
        !          2003:     p1 = icopy_lg(p1, ly);
        !          2004:     p2 = icopy(p2);
        !          2005:     for (i = 1; i <= l; i++)
        !          2006:     {
        !          2007:       z[i] = (long)truedvmdii(p1,p2,&p3);
        !          2008:       if (p3 == gzero) { i++; break; }
        !          2009:       affii(p3, p1); cgiv(p3); p3 = p1;
        !          2010:       p1 = p2; p2 = p3;
        !          2011:     }
        !          2012:   }
        !          2013:   i--;
        !          2014:   if (i > 2 && gcmp1((GEN)z[i]))
        !          2015:   {
        !          2016:     cgiv((GEN)z[i]); --i;
        !          2017:     addsiz(1,(GEN)z[i], (GEN)z[i]);
        !          2018:   }
        !          2019:   setlg(z,i+1); return z;
1.1       noro     2020: }
                   2021:
1.2     ! noro     2022: static GEN
        !          2023: sfcont(GEN x, long k)
1.1       noro     2024: {
1.2     ! noro     2025:   gpmem_t av;
        !          2026:   long lx,tx=typ(x),e,i,l;
        !          2027:   GEN  y,p1,p2,p3;
1.1       noro     2028:
                   2029:   if (is_scalar_t(tx))
                   2030:   {
1.2     ! noro     2031:     if (gcmp0(x)) return _vec(gzero);
1.1       noro     2032:     switch(tx)
                   2033:     {
1.2     ! noro     2034:       case t_INT: y = cgetg(2,t_VEC); y[1] = (long)icopy(x); return y;
1.1       noro     2035:       case t_REAL:
1.2     ! noro     2036:         av = avma; lx = lg(x);
1.1       noro     2037:        p2 = rcopy(x); settyp(p2,t_INT); setlgefint(p2,lx);
1.2     ! noro     2038:         e = bit_accuracy(lx)-1-expo(x);
        !          2039:        if (e < 0) err(talker,"integral part not significant in scfont");
        !          2040:         p1 = cgetg(3, t_FRACN);
        !          2041:        p1[1] = (long)p2;
        !          2042:        p1[2] = lshifti(gun, e);
        !          2043:
        !          2044:         p3 = cgetg(3, t_FRACN);
        !          2045:        p3[1] = laddsi(signe(x), p2);
        !          2046:        p3[2] = p1[2];
        !          2047:        p1 = Qsfcont(p1,NULL,k);
        !          2048:        return gerepilecopy(av, Qsfcont(p3,p1,k));
1.1       noro     2049:
                   2050:       case t_FRAC: case t_FRACN:
1.2     ! noro     2051:         av = avma;
        !          2052:         return gerepileupto(av, Qsfcont(x, NULL, k));
1.1       noro     2053:     }
                   2054:     err(typeer,"sfcont");
                   2055:   }
                   2056:
                   2057:   switch(tx)
                   2058:   {
1.2     ! noro     2059:     case t_POL: return _veccopy(x);
1.1       noro     2060:     case t_SER:
1.2     ! noro     2061:       av = avma; p1 = gtrunc(x);
        !          2062:       return gerepileupto(av,sfcont(p1,k));
1.1       noro     2063:     case t_RFRAC:
                   2064:     case t_RFRACN:
1.2     ! noro     2065:       av = avma;
        !          2066:       l = typ(x[1]) == t_POL? lgef(x[1]): 3;
        !          2067:       if (lgef(x[2]) > l) l = lgef(x[2]);
        !          2068:       if (k > 0 && l > k+1) l = k+1;
        !          2069:       y = cgetg(l,t_VEC);
        !          2070:       p1 = (GEN)x[1];
        !          2071:       p2 = (GEN)x[2];
        !          2072:       for (i=1; i<l; i++)
1.1       noro     2073:       {
1.2     ! noro     2074:        y[i] = ldivres(p1,p2,&p3);
        !          2075:         if (gcmp0(p3)) { i++; break; }
        !          2076:        p1 = p2; p2 = p3;
1.1       noro     2077:       }
1.2     ! noro     2078:       setlg(y, i); return gerepilecopy(av, y);
1.1       noro     2079:   }
1.2     ! noro     2080:   err(typeer,"sfcont");
        !          2081:   return NULL; /* not reached */
1.1       noro     2082: }
                   2083:
                   2084: static GEN
                   2085: sfcont2(GEN b, GEN x, long k)
                   2086: {
1.2     ! noro     2087:   gpmem_t av = avma;
1.1       noro     2088:   long l1 = lg(b), tx = typ(x), i;
                   2089:   GEN y,p1;
                   2090:
                   2091:   if (k)
                   2092:   {
                   2093:     if (k>=l1) err(typeer,"sfcont2");
                   2094:     l1 = k+1;
                   2095:   }
                   2096:   y=cgetg(l1,t_VEC);
                   2097:   if (l1==1) return y;
                   2098:   if (is_scalar_t(tx))
                   2099:   {
                   2100:     if (!is_intreal_t(tx) && !is_frac_t(tx)) err(typeer,"sfcont2");
                   2101:   }
                   2102:   else if (tx == t_SER) x = gtrunc(x);
                   2103:
                   2104:   if (!gcmp1((GEN)b[1])) x = gmul((GEN)b[1],x);
                   2105:   i = 2; y[1] = lfloor(x); p1 = gsub(x,(GEN)y[1]);
                   2106:   for (  ; i<l1 && !gcmp0(p1); i++)
                   2107:   {
                   2108:     x = gdiv((GEN)b[i],p1);
                   2109:     if (tx == t_REAL)
                   2110:     {
                   2111:       long e = expo(x);
                   2112:       if (e>0 && (e>>TWOPOTBITS_IN_LONG)+3 > lg(x)) break;
                   2113:     }
                   2114:     y[i] = lfloor(x);
                   2115:     p1 = gsub(x,(GEN)y[i]);
                   2116:   }
                   2117:   setlg(y,i);
                   2118:   return gerepilecopy(av,y);
                   2119: }
                   2120:
1.2     ! noro     2121:
        !          2122: GEN
        !          2123: gcf(GEN x)
        !          2124: {
        !          2125:   return sfcont(x,0);
        !          2126: }
        !          2127:
        !          2128: GEN
        !          2129: gcf2(GEN b, GEN x)
        !          2130: {
        !          2131:   return contfrac0(x,b,0);
        !          2132: }
        !          2133:
        !          2134: GEN
        !          2135: gboundcf(GEN x, long k)
        !          2136: {
        !          2137:   return sfcont(x,k);
        !          2138: }
        !          2139:
        !          2140: GEN
        !          2141: contfrac0(GEN x, GEN b, long flag)
        !          2142: {
        !          2143:   long lb,tb,i;
        !          2144:   GEN y;
        !          2145:
        !          2146:   if (!b || gcmp0(b)) return sfcont(x,flag);
        !          2147:   tb = typ(b);
        !          2148:   if (tb == t_INT) return sfcont(x,itos(b));
        !          2149:   if (! is_matvec_t(tb)) err(typeer,"contfrac0");
        !          2150:
        !          2151:   lb=lg(b); if (lb==1) return cgetg(1,t_VEC);
        !          2152:   if (tb != t_MAT) return sfcont2(b,x,flag);
        !          2153:   if (lg(b[1])==1) return sfcont(x,flag);
        !          2154:   y = (GEN) gpmalloc(lb*sizeof(long));
        !          2155:   for (i=1; i<lb; i++) y[i]=coeff(b,1,i);
        !          2156:   x = sfcont2(y,x,flag); free(y); return x;
        !          2157: }
        !          2158:
1.1       noro     2159: GEN
                   2160: pnqn(GEN x)
                   2161: {
1.2     ! noro     2162:   gpmem_t av=avma,tetpil;
        !          2163:   long lx,ly,tx=typ(x),i;
1.1       noro     2164:   GEN y,p0,p1,q0,q1,a,b,p2,q2;
                   2165:
                   2166:   if (! is_matvec_t(tx)) err(typeer,"pnqn");
                   2167:   lx=lg(x); if (lx==1) return idmat(2);
                   2168:   p0=gun; q0=gzero;
                   2169:   if (tx != t_MAT)
                   2170:   {
                   2171:     p1=(GEN)x[1]; q1=gun;
                   2172:     for (i=2; i<lx; i++)
                   2173:     {
                   2174:       a=(GEN)x[i];
                   2175:       p2=gadd(gmul(a,p1),p0); p0=p1; p1=p2;
                   2176:       q2=gadd(gmul(a,q1),q0); q0=q1; q1=q2;
                   2177:     }
                   2178:   }
                   2179:   else
                   2180:   {
                   2181:     ly=lg(x[1]);
                   2182:     if (ly==2)
                   2183:     {
                   2184:       p1=cgetg(lx,t_VEC); for (i=1; i<lx; i++) p1[i]=mael(x,i,1);
                   2185:       tetpil=avma; return gerepile(av,tetpil,pnqn(p1));
                   2186:     }
                   2187:     if (ly!=3) err(talker,"incorrect size in pnqn");
                   2188:     p1=gcoeff(x,2,1); q1=gcoeff(x,1,1);
                   2189:     for (i=2; i<lx; i++)
                   2190:     {
                   2191:       a=gcoeff(x,2,i); b=gcoeff(x,1,i);
                   2192:       p2=gadd(gmul(a,p1),gmul(b,p0)); p0=p1; p1=p2;
                   2193:       q2=gadd(gmul(a,q1),gmul(b,q0)); q0=q1; q1=q2;
                   2194:     }
                   2195:   }
                   2196:   tetpil=avma; y=cgetg(3,t_MAT);
                   2197:   p2=cgetg(3,t_COL); y[1]=(long)p2; p2[1]=lcopy(p1); p2[2]=lcopy(q1);
                   2198:   p2=cgetg(3,t_COL); y[2]=(long)p2; p2[1]=lcopy(p0); p2[2]=lcopy(q0);
                   2199:   return gerepile(av,tetpil,y);
                   2200: }
                   2201:
                   2202: /* x t_INTMOD. Look for coprime integers a<=A and b<=B, such that a/b = x */
                   2203: GEN
                   2204: bestappr_mod(GEN x, GEN A, GEN B)
                   2205: {
                   2206:   long i,lx,tx;
                   2207:   GEN y;
                   2208:   tx = typ(x);
                   2209:   switch(tx)
                   2210:   {
                   2211:     case t_INTMOD:
                   2212:     {
1.2     ! noro     2213:       gpmem_t av = avma;
1.1       noro     2214:       GEN a,b,d, t = cgetg(3, t_FRAC);
                   2215:       if (! ratlift((GEN)x[2], (GEN)x[1], &a,&b,A,B)) return NULL;
                   2216:       if (is_pm1(b)) return icopy_av(a, (GEN)av);
                   2217:       d = mppgcd(a,b);
                   2218:       if (!is_pm1(d)) { avma = av; return NULL; }
                   2219:       cgiv(d);
                   2220:       t[1] = (long)a;
                   2221:       t[2] = (long)b; return t;
                   2222:     }
                   2223:     case t_COMPLEX: case t_POL: case t_SER: case t_RFRAC:
                   2224:     case t_RFRACN: case t_VEC: case t_COL: case t_MAT:
                   2225:       lx = (tx==t_POL)? lgef(x): lg(x); y=cgetg(lx,tx);
                   2226:       for (i=1; i<lontyp[tx]; i++) y[i]=x[i];
                   2227:       for (   ; i<lx; i++)
                   2228:       {
                   2229:         GEN t = bestappr_mod((GEN)x[i],A,B);
                   2230:         if (!t) return NULL;
                   2231:         y[i] = (long)t;
                   2232:       }
                   2233:       return y;
                   2234:   }
                   2235:   err(typeer,"bestappr0");
                   2236:   return NULL; /* not reached */
                   2237: }
                   2238:
                   2239: GEN
                   2240: bestappr(GEN x, GEN k)
                   2241: {
1.2     ! noro     2242:   gpmem_t av = avma, tetpil;
1.1       noro     2243:   long tx,tk=typ(k),lx,i,e;
                   2244:   GEN p0,p1,p,q0,q1,q,a,y;
                   2245:
                   2246:   if (tk != t_INT)
                   2247:   {
                   2248:     if (tk != t_REAL && !is_frac_t(tk))
                   2249:       err(talker,"incorrect bound type in bestappr");
                   2250:     k = gcvtoi(k,&e);
                   2251:   }
                   2252:   if (signe(k) <= 0) k=gun;
1.2     ! noro     2253:   tx=typ(x); if (tx == t_FRACN) { x = gred(x); tx = typ(x); }
1.1       noro     2254:   switch(tx)
                   2255:   {
                   2256:     case t_INT:
                   2257:       if (av==avma) return icopy(x);
                   2258:       tetpil=avma; return gerepile(av,tetpil,icopy(x));
                   2259:
                   2260:     case t_FRAC:
                   2261:       if (cmpii((GEN)x[2],k) <= 0)
                   2262:       {
                   2263:         if (av==avma) return gcopy(x);
                   2264:         return gerepilecopy(av,x);
                   2265:       }
                   2266:
                   2267:     case t_REAL:
1.2     ! noro     2268:       p1=gun; a=p0=gfloor(x); q1=gzero; q0=gun;
        !          2269:       while (cmpii(q0,k)<=0)
1.1       noro     2270:       {
                   2271:        x = gsub(x,a);
                   2272:        if (gcmp0(x)) { p1=p0; q1=q0; break; }
                   2273:
                   2274:        x = ginv(x); a = (gcmp(x,k)<0)? gfloor(x): k;
                   2275:        p = addii(mulii(a,p0),p1); p1=p0; p0=p;
                   2276:         q = addii(mulii(a,q0),q1); q1=q0; q0=q;
                   2277:       }
                   2278:       tetpil=avma; return gerepile(av,tetpil,gdiv(p1,q1));
                   2279:
                   2280:    case t_COMPLEX: case t_POL: case t_SER: case t_RFRAC:
                   2281:    case t_RFRACN: case t_VEC: case t_COL: case t_MAT:
                   2282:       lx = (tx==t_POL)? lgef(x): lg(x); y=cgetg(lx,tx);
                   2283:       for (i=1; i<lontyp[tx]; i++) y[i]=x[i];
                   2284:       for (   ; i<lx; i++) y[i]=(long)bestappr((GEN)x[i],k);
                   2285:       return y;
                   2286:   }
                   2287:   err(typeer,"bestappr");
                   2288:   return NULL; /* not reached */
                   2289: }
                   2290:
                   2291: GEN
                   2292: bestappr0(GEN x, GEN a, GEN b)
                   2293: {
1.2     ! noro     2294:   gpmem_t av;
1.1       noro     2295:   GEN t;
                   2296:   if (!b) return bestappr(x,a);
                   2297:   av = avma;
                   2298:   t = bestappr_mod(x,a,b);
                   2299:   if (!t) { avma = av; return stoi(-1); }
                   2300:   return t;
                   2301: }
                   2302:
                   2303: /***********************************************************************/
                   2304: /**                                                                   **/
                   2305: /**         FUNDAMENTAL UNIT AND REGULATOR (QUADRATIC FIELDS)         **/
                   2306: /**                                                                   **/
                   2307: /***********************************************************************/
                   2308:
                   2309: GEN
                   2310: gfundunit(GEN x)
                   2311: {
                   2312:   return garith_proto(fundunit,x,1);
                   2313: }
                   2314:
                   2315: static GEN
                   2316: get_quad(GEN f, GEN pol, long r)
                   2317: {
                   2318:   GEN y, c=(GEN)f[2], p1=(GEN)c[1], q1=(GEN)c[2];
                   2319:   y=cgetg(4,t_QUAD); y[1]=(long)pol;
                   2320:   y[2]=r? lsubii(p1,q1): (long)p1;
                   2321:   y[3]=(long)q1; return y;
                   2322: }
                   2323:
                   2324: /* replace f by f * [a,1; 1,0] */
                   2325: static void
                   2326: update_f(GEN f, GEN a)
                   2327: {
                   2328:   GEN p1;
                   2329:   p1=gcoeff(f,1,1);
                   2330:   coeff(f,1,1)=laddii(mulii(a,p1), gcoeff(f,1,2));
                   2331:   coeff(f,1,2)=(long)p1;
                   2332:
                   2333:   p1=gcoeff(f,2,1);
                   2334:   coeff(f,2,1)=laddii(mulii(a,p1), gcoeff(f,2,2));
                   2335:   coeff(f,2,2)=(long)p1;
                   2336: }
                   2337:
                   2338: GEN
                   2339: fundunit(GEN x)
                   2340: {
1.2     ! noro     2341:   gpmem_t av = avma, av2, lim;
        !          2342:   long r,flp,flq;
1.1       noro     2343:   GEN pol,y,a,u,v,u1,v1,sqd,f;
                   2344:
                   2345:   if (typ(x) != t_INT) err(arither1);
                   2346:   if (signe(x)<=0) err(arither2);
                   2347:   r=mod4(x); if (r==2 || r==3) err(funder2,"fundunit");
                   2348:
                   2349:   sqd=racine(x); av2=avma; lim=stack_lim(av2,2);
                   2350:   a = shifti(addsi(r,sqd),-1);
                   2351:   f=cgetg(3,t_MAT); f[1]=lgetg(3,t_COL); f[2]=lgetg(3,t_COL);
                   2352:   coeff(f,1,1)=(long)a; coeff(f,1,2)=un;
                   2353:   coeff(f,2,1)=un;      coeff(f,2,2)=zero;
                   2354:   v = gdeux; u = stoi(r);
                   2355:   for(;;)
                   2356:   {
                   2357:     u1=subii(mulii(a,v),u);       flp=egalii(u,u1); u=u1;
                   2358:     v1=divii(subii(x,sqri(u)),v); flq=egalii(v,v1); v=v1;
                   2359:     if (flq) break; a = divii(addii(sqd,u),v);
                   2360:     if (flp) break; update_f(f,a);
                   2361:     if (low_stack(lim, stack_lim(av2,2)))
                   2362:     {
                   2363:       GEN *gptr[4]; gptr[0]=&a; gptr[1]=&f; gptr[2]=&u; gptr[3]=&v;
                   2364:       if(DEBUGMEM>1) err(warnmem,"fundunit");
                   2365:       gerepilemany(av2,gptr,4);
                   2366:     }
                   2367:   }
                   2368:   pol = quadpoly(x); y = get_quad(f,pol,r);
                   2369:   if (!flq) v1 = y; else { update_f(f,a); v1 = get_quad(f,pol,r); }
                   2370:
1.2     ! noro     2371:   u1=gconj(y); y=gdiv(v1,u1);
        !          2372:   if (signe(y[3]) < 0) y = gneg(y);
        !          2373:   return gerepileupto(av, y);
1.1       noro     2374: }
                   2375:
                   2376: GEN
                   2377: gregula(GEN x, long prec)
                   2378: {
                   2379:   return garith_proto2gs(regula,x,prec);
                   2380: }
                   2381:
                   2382: GEN
                   2383: regula(GEN x, long prec)
                   2384: {
1.2     ! noro     2385:   gpmem_t av = avma,av2,lim;
        !          2386:   long r,fl,rexp;
1.1       noro     2387:   GEN reg,rsqd,y,u,v,u1,v1, sqd = racine(x);
                   2388:
                   2389:   if (signe(x)<=0) err(arither2);
                   2390:   r=mod4(x); if (r==2 || r==3) err(funder2,"regula");
                   2391:
                   2392:   rsqd = gsqrt(x,prec);
                   2393:   if (egalii(sqri(sqd),x)) err(talker,"square argument in regula");
                   2394:
1.2     ! noro     2395:   rexp=0; reg = stor(2, prec);
1.1       noro     2396:   av2=avma; lim = stack_lim(av2,2);
                   2397:   u = stoi(r); v = gdeux;
                   2398:   for(;;)
                   2399:   {
                   2400:     u1 = subii(mulii(divii(addii(u,sqd),v), v), u);
                   2401:     v1 = divii(subii(x,sqri(u1)),v); fl = egalii(v,v1);
                   2402:     if (fl || egalii(u,u1)) break;
                   2403:     reg = mulrr(reg, divri(addir(u1,rsqd),v));
                   2404:     rexp += expo(reg); setexpo(reg,0);
                   2405:     u = u1; v = v1;
                   2406:     if (rexp & ~EXPOBITS) err(muler4);
                   2407:     if (low_stack(lim, stack_lim(av2,2)))
                   2408:     {
                   2409:       GEN *gptr[3]; gptr[0]=&reg; gptr[1]=&u; gptr[2]=&v;
                   2410:       if(DEBUGMEM>1) err(warnmem,"regula");
                   2411:       gerepilemany(av2,gptr,3);
                   2412:     }
                   2413:   }
                   2414:   reg = gsqr(reg); setexpo(reg,expo(reg)-1);
                   2415:   if (fl) reg = mulrr(reg, divri(addir(u1,rsqd),v));
                   2416:   y = mplog(divri(reg,v));
                   2417:   if (rexp)
                   2418:   {
1.2     ! noro     2419:     u1 = mulsr(rexp, mplog2(prec));
1.1       noro     2420:     setexpo(u1, expo(u1)+1);
                   2421:     y = addrr(y,u1);
                   2422:   }
                   2423:   return gerepileupto(av, y);
                   2424: }
                   2425:
                   2426: /*************************************************************************/
                   2427: /**                                                                     **/
                   2428: /**                            CLASS NUMBER                             **/
                   2429: /**                                                                     **/
                   2430: /*************************************************************************/
                   2431:
                   2432: static GEN
                   2433: gclassno(GEN x)
                   2434: {
                   2435:   return garith_proto(classno,x,1);
                   2436: }
                   2437:
                   2438: static GEN
                   2439: gclassno2(GEN x)
                   2440: {
                   2441:   return garith_proto(classno2,x,1);
                   2442: }
                   2443:
                   2444: GEN
                   2445: qfbclassno0(GEN x,long flag)
                   2446: {
                   2447:   switch(flag)
                   2448:   {
                   2449:     case 0: return gclassno(x);
                   2450:     case 1: return gclassno2(x);
                   2451:     default: err(flagerr,"qfbclassno");
                   2452:   }
                   2453:   return NULL; /* not reached */
                   2454: }
                   2455:
                   2456: /* f^h = 1, return order(f) */
                   2457: static GEN
                   2458: find_order(GEN f, GEN h)
                   2459: {
                   2460:   GEN fh, p,e;
                   2461:   long i,j,lim;
                   2462:
                   2463:   p = decomp(h);
                   2464:   e =(GEN)p[2];
                   2465:   p =(GEN)p[1];
                   2466:   for (i=1; i<lg(p); i++)
                   2467:   {
                   2468:     lim = itos((GEN)e[i]);
                   2469:     for (j=1; j<=lim; j++)
                   2470:     {
                   2471:       GEN p1 = divii(h,(GEN)p[i]);
                   2472:       fh = powgi(f,p1);
                   2473:       if (!is_pm1(fh[1])) break;
                   2474:       h = p1;
                   2475:     }
                   2476:   }
                   2477:   return h;
                   2478: }
                   2479:
                   2480: static GEN
                   2481: end_classno(GEN h, GEN hin, GEN forms, long lform)
                   2482: {
                   2483:   long i,com;
                   2484:   GEN a,b,p1,q,fh,fg, f = (GEN)forms[0];
                   2485:
                   2486:   h = find_order(f,h); /* H = <f> */
                   2487:   q = ground(gdiv(hin,h)); /* approximate order of G/H */
                   2488:   for (i=1; i < lform; i++)
                   2489:   {
1.2     ! noro     2490:     gpmem_t av = avma;
1.1       noro     2491:     fg = powgi((GEN)forms[i], h);
                   2492:     fh = powgi(fg, q);
                   2493:     a = (GEN)fh[1];
                   2494:     if (is_pm1(a)) continue;
                   2495:     b = (GEN)fh[2]; p1 = fg;
                   2496:     for (com=1; ; com++)
                   2497:     {
                   2498:       if (egalii((GEN)p1[1], a) && absi_equal((GEN)p1[2], b)) break;
                   2499:       p1 = gmul(p1,fg);
                   2500:     }
                   2501:     if (signe(p1[2]) == signe(b)) com = -com;
                   2502:     /* f_i ^ h(q+com) = 1 */
                   2503:     avma = av; q = addsi(com,q);
                   2504:   }
                   2505:   return mulii(q,h);
                   2506: }
                   2507:
                   2508: static GEN
                   2509: to_form(GEN x, long f)
                   2510: {
                   2511:   return redimag(primeform(x, stoi(f), 0));
                   2512: }
                   2513:
1.2     ! noro     2514: static GEN
        !          2515: conductor_part(GEN x, GEN *ptD, GEN *ptreg, GEN *ptfa)
        !          2516: {
        !          2517:   long n,i,k,s=signe(x),fl2;
        !          2518:   GEN e,p,H,d,D,fa,reg;
        !          2519:
        !          2520:   fa = auxdecomp(absi(x),1);
        !          2521:   e = gtovecsmall((GEN)fa[2]);
        !          2522:   fa = (GEN)fa[1];
        !          2523:   n = lg(fa); d = gun;
        !          2524:   for (i=1; i<n; i++)
        !          2525:     if (e[i] & 1) d = mulii(d,(GEN)fa[i]);
        !          2526:   if (mod4(d) == 2-s) fl2 = 0;
        !          2527:   else
        !          2528:   {
        !          2529:     fl2 = (mod4(x)==0);
        !          2530:     if (!fl2) err(funder2,"classno");
        !          2531:     d = shifti(d,2);
        !          2532:   }
        !          2533:   H = gun; D = (s<0)? negi(d): d; /* d = abs(D) */
        !          2534:   /* f \prod_{p|f}  [ 1 - (D/p) p^-1 ] */
        !          2535:   for (i=1; i<n; i++)
        !          2536:   {
        !          2537:     p = (GEN)fa[i];
        !          2538:     k = e[i];
        !          2539:     if (fl2 && i==1) k -= 2; /* p = 2 */
        !          2540:     if (k >= 2)
        !          2541:     {
        !          2542:       H = mulii(H, subis(p, kronecker(D,p)));
        !          2543:       if (k>=4) H = mulii(H,gpowgs(p,(k>>1)-1));
        !          2544:     }
        !          2545:   }
        !          2546:
        !          2547:   /* divide by [ O^* : O_K^* ] */
        !          2548:   if (s < 0)
        !          2549:   {
        !          2550:     reg = NULL;
        !          2551:     if (!is_bigint(d))
        !          2552:       switch(itos(d))
        !          2553:       {
        !          2554:         case 4: H = divis(H,2); break;
        !          2555:         case 3: H = divis(H,3); break;
        !          2556:       }
        !          2557:   } else {
        !          2558:     reg = regula(D,DEFAULTPREC);
        !          2559:     if (!egalii(x,D))
        !          2560:       H = divii(H, ground(gdiv(regula(x,DEFAULTPREC), reg)));
        !          2561:   }
        !          2562:   *ptfa = fa; *ptD = D; if (ptreg) *ptreg = reg;
        !          2563:   return H;
        !          2564: }
        !          2565:
        !          2566:
1.1       noro     2567: static long
                   2568: two_rank(GEN x)
                   2569: {
                   2570:   GEN p = (GEN)decomp(absi(x))[1];
                   2571:   long l = lg(p)-1;
                   2572: #if 0 /* positive disc not needed */
                   2573:   if (signe(x) > 0)
                   2574:   {
                   2575:     long i;
                   2576:     for (i=1; i<=l; i++)
                   2577:       if (mod4((GEN)p[i]) == 3) { l--; break; }
                   2578:   }
                   2579: #endif
                   2580:   return l-1;
                   2581: }
                   2582:
                   2583: #define MAXFORM 11
1.2     ! noro     2584: #if 0 /* gcc-ism */
        !          2585: #  define _low(x) ({GEN __x=(GEN)x; modBIL(__x);})
        !          2586: #else
        !          2587: #  define _low(x) (__x = (GEN)(x), modBIL(__x))
        !          2588: #endif
1.1       noro     2589:
                   2590: /* h(x) for x<0 using Baby Step/Giant Step.
                   2591:  * Assumes G is not too far from being cyclic.
                   2592:  *
                   2593:  * Compute G^2 instead of G so as to kill most of the non-cyclicity */
                   2594: GEN
                   2595: classno(GEN x)
                   2596: {
1.2     ! noro     2597:   gpmem_t av = avma, av2, lim;
        !          2598:   long r2,c,lforms,k,l,i,j,j1,j2,com,s, forms[MAXFORM];
1.1       noro     2599:   GEN a,b,count,index,tabla,tablb,hash,p1,p2,hin,h,f,fh,fg,ftest;
1.2     ! noro     2600:   GEN Hf,D,fa;
        !          2601:   byteptr p = diffptr;
1.1       noro     2602:   GEN __x;
                   2603:
                   2604:   if (typ(x) != t_INT) err(arither1);
                   2605:   s=signe(x); if (s>=0) return classno2(x);
                   2606:
                   2607:   k=mod4(x); if (k==1 || k==2) err(funder2,"classno");
1.2     ! noro     2608:   if (cmpis(x,-12) >= 0) return gun;
1.1       noro     2609:
1.2     ! noro     2610:   Hf = conductor_part(x,&D,NULL,&fa);
        !          2611:   if (cmpis(D,-12) >= 0) return gerepilecopy(av, Hf);
        !          2612:
        !          2613:   p2 = gsqrt(absi(D),DEFAULTPREC);
1.1       noro     2614:   p1 = divrr(p2,mppi(DEFAULTPREC));
                   2615:   p2 = gtrunc(shiftr(gsqrt(p2,DEFAULTPREC),1));
                   2616:   s = 1000;
                   2617:   if (signe(p2))
                   2618:   {
                   2619:     if (is_bigint(p2)) err(talker,"discriminant too big in classno");
                   2620:     s = itos(p2); if (s < 1000) s = 1000;
                   2621:   }
1.2     ! noro     2622:   r2 = two_rank(D);
1.1       noro     2623:   c=lforms=0;
                   2624:   while (c <= s && *p)
                   2625:   {
1.2     ! noro     2626:     NEXT_PRIME_VIADIFF(c,p);
        !          2627:     k = krogs(D,c);
1.1       noro     2628:     if (!k) continue;
                   2629:
                   2630:     av2 = avma;
                   2631:     if (k > 0)
                   2632:     {
                   2633:       divrsz(mulsr(c,p1),c-1, p1);
                   2634:       if (lforms < MAXFORM && c > 2) forms[lforms++] = c;
                   2635:     }
                   2636:     else divrsz(mulsr(c,p1),c+1, p1);
                   2637:     avma = av2;
                   2638:   }
                   2639:   h = hin = shifti(ground(p1), -r2);
                   2640:   s = 2*itos(gceil(gpui(p1,ginv(stoi(4)),DEFAULTPREC)));
                   2641:   if (s>=10000) s=10000;
                   2642:
                   2643:   count = new_chunk(256); for (i=0; i<=255; i++) count[i]=0;
                   2644:   index = new_chunk(257);
                   2645:   tabla = new_chunk(10000);
                   2646:   tablb = new_chunk(10000);
                   2647:   hash  = new_chunk(10000);
1.2     ! noro     2648:   f = gsqr(to_form(D, forms[0]));
1.1       noro     2649:   p1 = fh = powgi(f, h);
                   2650:   for (i=0; i<s; i++)
                   2651:   {
                   2652:     tabla[i] = _low(p1[1]);
                   2653:     tablb[i] = _low(p1[2]);
                   2654:     count[tabla[i]&255]++; p1=compimag(p1,f);
                   2655:   }
                   2656:   index[0]=0; for (i=0; i<=254; i++) index[i+1] = index[i]+count[i];
                   2657:   for (i=0; i<s; i++) hash[index[tabla[i]&255]++]=i;
                   2658:   index[0]=0; for (i=0; i<=255; i++) index[i+1] = index[i]+count[i];
                   2659:
                   2660:   fg=gpuigs(f,s); av2=avma; lim=stack_lim(av2,2);
                   2661:   ftest=gpuigs(p1,0);
                   2662:   for (com=0; ; com++)
                   2663:   {
                   2664:     a = (GEN)ftest[1]; k = _low(a);
                   2665:     b = (GEN)ftest[2]; l = _low(b); j = k&255;
                   2666:     for (j1=index[j]; j1 < index[j+1]; j1++)
                   2667:     {
                   2668:       j2 = hash[j1];
                   2669:       if (tabla[j2] == k && tablb[j2] == l)
                   2670:       {
                   2671:         p1 = gmul(gpuigs(f,j2),fh);
                   2672:         if (egalii((GEN)p1[1], a) && absi_equal((GEN)p1[2], b))
                   2673:         { /* p1 = ftest or ftest^(-1), we are done */
                   2674:           if (signe(p1[2]) == signe(b)) com = -com;
                   2675:           h = addii(addis(h,j2), mulss(s,com));
                   2676:           forms[0] = (long)f;
                   2677:           for (i=1; i<lforms; i++)
1.2     ! noro     2678:             forms[i] = (long)gsqr(to_form(D, forms[i]));
1.1       noro     2679:           h = end_classno(h,hin,forms,lforms);
1.2     ! noro     2680:           h = mulii(h,Hf);
1.1       noro     2681:           return gerepileuptoint(av, shifti(h, r2));
                   2682:         }
                   2683:       }
                   2684:     }
                   2685:     ftest = gmul(ftest,fg);
                   2686:     if (is_pm1(ftest[1])) err(impl,"classno with too small order");
                   2687:     if (low_stack(lim, stack_lim(av2,2))) ftest = gerepileupto(av2,ftest);
                   2688:   }
                   2689: }
                   2690:
                   2691: /* use Euler products */
                   2692: GEN
                   2693: classno2(GEN x)
                   2694: {
1.2     ! noro     2695:   gpmem_t av = avma;
        !          2696:   long n,i,k,s = signe(x);
        !          2697:   GEN p1,p2,p3,p4,p5,p7,Hf,Pi,reg,logd,d,D;
1.1       noro     2698:
                   2699:   if (typ(x) != t_INT) err(arither1);
                   2700:   if (!s) err(arither2);
1.2     ! noro     2701:   if (s < 0 && cmpis(x,-12) >= 0) return gun;
1.1       noro     2702:
1.2     ! noro     2703:   Hf = conductor_part(x, &D, &reg, &p1);
        !          2704:   if (s < 0 && cmpis(D,-12) >= 0)
        !          2705:     return gerepilecopy(av, Hf); /* |D| < 12*/
        !          2706:
        !          2707:   Pi = mppi(DEFAULTPREC);
        !          2708:   d = absi(D); logd = glog(d,DEFAULTPREC);
        !          2709:   p1 = mpsqrt(gdiv(gmul(d,logd), gmul2n(Pi,1)));
        !          2710:   if (s > 0)
1.1       noro     2711:   {
1.2     ! noro     2712:     p2 = subsr(1, gmul2n(divrr(mplog(reg),logd),1));
        !          2713:     if (gcmp(gsqr(p2), divsr(2,logd)) >= 0) p1 = gmul(p2,p1);
1.1       noro     2714:   }
1.2     ! noro     2715:   p1 = gtrunc(p1);
        !          2716:   if (is_bigint(p1)) err(talker,"discriminant too large in classno");
        !          2717:   n = itos(p1);
1.1       noro     2718:
1.2     ! noro     2719:   p4 = divri(Pi,d); p7 = ginv(mpsqrt(Pi));
1.1       noro     2720:   p1 = gsqrt(d,DEFAULTPREC); p3 = gzero;
                   2721:   if (s > 0)
                   2722:   {
                   2723:     for (i=1; i<=n; i++)
                   2724:     {
1.2     ! noro     2725:       k = krogs(D,i); if (!k) continue;
        !          2726:       p2 = mulir(mulss(i,i),p4);
        !          2727:       p5 = subsr(1,mulrr(p7,incgam3(ghalf,p2,DEFAULTPREC)));
        !          2728:       p5 = addrr(divrs(mulrr(p1,p5),i), eint1(p2,DEFAULTPREC));
        !          2729:       p3 = (k>0)? addrr(p3,p5): subrr(p3,p5);
1.1       noro     2730:     }
                   2731:     p3 = shiftr(divrr(p3,reg),-1);
                   2732:   }
                   2733:   else
                   2734:   {
1.2     ! noro     2735:     p1 = gdiv(p1,Pi);
1.1       noro     2736:     for (i=1; i<=n; i++)
                   2737:     {
1.2     ! noro     2738:       k = krogs(D,i); if (!k) continue;
        !          2739:       p2 = mulir(mulss(i,i),p4);
        !          2740:       p5 = subsr(1,mulrr(p7,incgam3(ghalf,p2,DEFAULTPREC)));
        !          2741:       p5 = addrr(p5, divrr(divrs(p1,i),mpexp(p2)));
        !          2742:       p3 = (k>0)? addrr(p3,p5): subrr(p3,p5);
1.1       noro     2743:     }
                   2744:   }
1.2     ! noro     2745:   return gerepileuptoint(av, mulii(Hf,ground(p3)));
1.1       noro     2746: }
                   2747:
                   2748: GEN
                   2749: hclassno(GEN x)
                   2750: {
                   2751:   long d,a,b,h,b2,f;
                   2752:
                   2753:   d= -itos(x); if (d>0 || (d & 3) > 1) return gzero;
                   2754:   if (!d) return gdivgs(gun,-12);
                   2755:   if (-d > (VERYBIGINT>>1))
                   2756:     err(talker,"discriminant too big in hclassno. Use quadclassunit");
                   2757:   h=0; b=d&1; b2=(b-d)>>2; f=0;
                   2758:   if (!b)
                   2759:   {
                   2760:     for (a=1; a*a<b2; a++)
                   2761:       if (b2%a == 0) h++;
                   2762:     f = (a*a==b2); b=2; b2=(4-d)>>2;
                   2763:   }
                   2764:   while (b2*3+d<0)
                   2765:   {
                   2766:     if (b2%b == 0) h++;
                   2767:     for (a=b+1; a*a<b2; a++)
                   2768:       if (b2%a == 0) h+=2;
                   2769:     if (a*a==b2) h++;
                   2770:     b+=2; b2=(b*b-d)>>2;
                   2771:   }
                   2772:   if (b2*3+d==0)
                   2773:   {
                   2774:     GEN y = cgetg(3,t_FRAC);
                   2775:     y[1]=lstoi(3*h+1); y[2]=lstoi(3); return y;
                   2776:   }
                   2777:   if (f) return gaddsg(h,ghalf);
                   2778:   return stoi(h);
                   2779: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>