Code coverage tests

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

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

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

LCOV - code coverage report
Current view: top level - kernel/none - mp.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31041-bd73e9fcdd) Lines: 96.6 % 1153 1114
Test Date: 2026-07-22 22:45:42 Functions: 97.1 % 70 68
Legend: Lines:     hit not hit

            Line data    Source code
       1              : #line 2 "../src/kernel/none/mp.c"
       2              : /* Copyright (C) 2000-2003 The PARI group.
       3              : 
       4              : This file is part of the PARI/GP package.
       5              : 
       6              : PARI/GP is free software; you can redistribute it and/or modify it under the
       7              : terms of the GNU General Public License as published by the Free Software
       8              : Foundation; either version 2 of the License, or (at your option) any later
       9              : version. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      15              : 
      16              : /***********************************************************************/
      17              : /**                                                                   **/
      18              : /**                       MULTIPRECISION KERNEL                       **/
      19              : /**                                                                   **/
      20              : /***********************************************************************/
      21              : #include "pari.h"
      22              : #include "paripriv.h"
      23              : #include "../src/kernel/none/tune-gen.h"
      24              : 
      25              : void
      26          795 : pari_kernel_init(void) { }
      27              : void
      28          795 : pari_kernel_close(void) { }
      29              : const char *
      30            0 : pari_kernel_version(void) { return ""; }
      31              : 
      32              : /* NOTE: arguments of "spec" routines (muliispec, addiispec, etc.) aren't
      33              :  * GENs but pairs (long *a, long na) representing a list of digits (in basis
      34              :  * BITS_IN_LONG) : a[0], ..., a[na-1]. In order to facilitate splitting: no
      35              :  * need to reintroduce codewords. */
      36              : 
      37              : #define LIMBS(x)  ((x)+2)
      38              : #define NLIMBS(x) (lgefint(x)-2)
      39              : 
      40              : /* Normalize a nonnegative integer */
      41              : GEN
      42    872939919 : int_normalize(GEN x, long known_zero_words)
      43              : {
      44    872939919 :   long i, lx = lgefint(x);
      45              :   GEN x0;
      46    872939919 :   if (lx == 2) { x[1] = evalsigne(0) | evallgefint(2); return x; }
      47    872939919 :   if (!known_zero_words && x[2]) return x;
      48   3546003423 :   for (i = 2+known_zero_words; i < lx; i++)
      49   3478058727 :     if (x[i]) break;
      50    333836655 :   x0 = x; i -= 2; x += i;
      51    333836655 :   if (x0 == (GEN)avma) set_avma((pari_sp)x);
      52    199850193 :   else stackdummy((pari_sp)(x0+i), (pari_sp)x0);
      53    333836655 :   lx -= i;
      54    333836655 :   x[0] = evaltyp(t_INT) | evallg(lx);
      55    333836655 :   if (lx == 2) x[1] = evalsigne(0) | evallgefint(lx);
      56    265891959 :   else         x[1] = evalsigne(1) | evallgefint(lx);
      57    333836655 :   return x;
      58              : }
      59              : 
      60              : /***********************************************************************/
      61              : /**                                                                   **/
      62              : /**                      ADDITION / SUBTRACTION                       **/
      63              : /**                                                                   **/
      64              : /***********************************************************************/
      65              : 
      66              : GEN
      67      2248461 : setloop(GEN a)
      68              : {
      69      2248461 :   pari_sp av = avma;
      70      2248461 :   (void)cgetg(lgefint(a) + 3, t_VECSMALL);
      71      2248461 :   return icopy_avma(a, av); /* two cells of extra space before a */
      72              : }
      73              : 
      74              : /* we had a = setloop(?), then some incloops. Reset a to b */
      75              : GEN
      76       130695 : resetloop(GEN a, GEN b) {
      77       130695 :   long lb = lgefint(b);
      78       130695 :   a += lgefint(a) - lb;
      79       130695 :   a[0] = evaltyp(t_INT) | evallg(lb);
      80       130695 :   affii(b, a); return a;
      81              : }
      82              : 
      83              : /* assume a > 0, initialized by setloop. Do a++ */
      84              : static GEN
      85     34965198 : incpos(GEN a)
      86              : {
      87     34965198 :   long i, l = lgefint(a);
      88     34965201 :   for (i=l-1; i>1; i--)
      89     34965198 :     if (++a[i]) return a;
      90            3 :   l++; a--; /* use extra cell */
      91            3 :   a[0]=evaltyp(t_INT) | _evallg(l);
      92            3 :   a[1]=evalsigne(1) | evallgefint(l);
      93            3 :   a[2]=1; return a;
      94              : }
      95              : 
      96              : /* assume a < 0, initialized by setloop. Do a++ */
      97              : static GEN
      98        50013 : incneg(GEN a)
      99              : {
     100        50013 :   long i, l = lgefint(a)-1;
     101        50013 :   if (uel(a,l)--)
     102              :   {
     103        50010 :     if (l == 2 && !a[2])
     104              :     {
     105         1485 :       a++; /* save one cell */
     106         1485 :       a[0] = evaltyp(t_INT) | _evallg(2);
     107         1485 :       a[1] = evalsigne(0) | evallgefint(2);
     108              :     }
     109        50010 :     return a;
     110              :   }
     111            3 :   for (i = l-1;; i--) /* finishes since a[2] != 0 */
     112            3 :     if (uel(a,i)--) break;
     113            3 :   if (!a[2])
     114              :   {
     115            3 :     a++; /* save one cell */
     116            3 :     a[0] = evaltyp(t_INT) | _evallg(l);
     117            3 :     a[1] = evalsigne(-1) | evallgefint(l);
     118              :   }
     119            3 :   return a;
     120              : }
     121              : 
     122              : /* assume a initialized by setloop. Do a++ */
     123              : GEN
     124     35267697 : incloop(GEN a)
     125              : {
     126     35267697 :   switch(signe(a))
     127              :   {
     128       252486 :     case 0: a--; /* use extra cell */
     129       252486 :       a[0]=evaltyp(t_INT) | _evallg(3);
     130       252486 :       a[1]=evalsigne(1) | evallgefint(3);
     131       252486 :       a[2]=1; return a;
     132        50013 :     case -1: return incneg(a);
     133     34965198 :     default: return incpos(a);
     134              :   }
     135              : }
     136              : 
     137              : INLINE GEN
     138   2427110015 : adduispec(ulong s, GEN x, long nx)
     139              : {
     140   2427110015 :   GEN xd, zd = (GEN)avma;
     141              :   long lz;
     142              : 
     143   2427110015 :   if (nx == 1) return adduu(s, uel(x,0));
     144    881191287 :   lz = nx+3; (void)new_chunk(lz);
     145    881191287 :   xd = x + nx;
     146    881191287 :   *--zd = (ulong)*--xd + s;
     147    881191287 :   if ((ulong)*zd < s)
     148              :     for(;;)
     149              :     {
     150    263879367 :       if (xd == x) { *--zd = 1; break; } /* enlarge z */
     151    260137500 :       *--zd = ((ulong)*--xd) + 1;
     152    260137500 :       if (*zd) { lz--; break; }
     153              :     }
     154    624395649 :   else lz--;
     155   2213299092 :   while (xd > x) *--zd = *--xd;
     156    881191287 :   *--zd = evalsigne(1) | evallgefint(lz);
     157    881191287 :   *--zd = evaltyp(t_INT) | evallg(lz);
     158    881191287 :   return gc_const((pari_sp)zd, zd);
     159              : }
     160              : 
     161              : GEN
     162    492446313 : adduispec_offset(ulong s, GEN x, long offset, long nx)
     163              : {
     164    492446313 :   GEN xd = x+lgefint(x)-nx-offset;
     165    607552392 :   while (nx && *xd==0) {xd++; nx--;}
     166    492446313 :   if (!nx) return utoi(s);
     167    460974381 :   return adduispec(s,xd,nx);
     168              : }
     169              : 
     170              : static GEN
     171   4696823898 : addiispec(GEN x, GEN y, long nx, long ny)
     172              : {
     173              :   GEN xd, yd, zd;
     174   4696823898 :   long lz, i = -2;
     175              :   LOCAL_OVERFLOW;
     176              : 
     177   4696823898 :   if (nx < ny) swapspec(x,y, nx,ny);
     178   4696823898 :   if (ny == 1) return adduispec(*y,x,nx);
     179   2798361009 :   zd = (GEN)avma;
     180   2798361009 :   lz = nx+3; (void)new_chunk(lz);
     181   2798361009 :   xd = x + nx;
     182   2798361009 :   yd = y + ny;
     183   2798361009 :   zd[-1] = addll(xd[-1], yd[-1]);
     184              : #ifdef addllx8
     185   2489404098 :   for (  ; i-8 > -ny; i-=8)
     186   1556617095 :     addllx8(xd+i, yd+i, zd+i, overflow);
     187              : #endif
     188  39410337957 :   for (  ; i >= -ny; i--) zd[i] = addllx(xd[i], yd[i]);
     189   2798361009 :   if (overflow)
     190              :     for(;;)
     191              :     {
     192    566966058 :       if (i < -nx) { zd[i] = 1; i--; break; } /* enlarge z */
     193    377942343 :       zd[i] = uel(xd,i) + 1;
     194    377942343 :       if (zd[i]) { i--; lz--; break; }
     195     66279741 :       i--;
     196              :     }
     197   2297674692 :   else lz--;
     198  21305181540 :   for (; i >= -nx; i--) zd[i] = xd[i];
     199   2798361009 :   zd += i+1;
     200   2798361009 :   *--zd = evalsigne(1) | evallgefint(lz);
     201   2798361009 :   *--zd = evaltyp(t_INT) | evallg(lz);
     202   2798361009 :   return gc_const((pari_sp)zd, zd);
     203              : }
     204              : 
     205              : /* assume x >= s */
     206              : INLINE GEN
     207   1622744372 : subiuspec(GEN x, ulong s, long nx)
     208              : {
     209   1622744372 :   GEN xd, zd = (GEN)avma;
     210              :   long lz;
     211              :   LOCAL_OVERFLOW;
     212              : 
     213   1622744372 :   if (nx == 1) return utoi(x[0] - s);
     214              : 
     215    369914275 :   lz = nx+2; (void)new_chunk(lz);
     216    369914275 :   xd = x + nx;
     217    369914275 :   *--zd = subll(*--xd, s);
     218    369914275 :   if (overflow)
     219              :     for(;;)
     220              :     {
     221    163159791 :       *--zd = ((ulong)*--xd) - 1;
     222    163159791 :       if (*xd) break;
     223              :     }
     224    369914275 :   if (xd == x)
     225    270197460 :     while (*zd == 0) { zd++; lz--; } /* shorten z */
     226              :   else
     227   4769095892 :     do  *--zd = *--xd; while (xd > x);
     228    369914275 :   *--zd = evalsigne(1) | evallgefint(lz);
     229    369914275 :   *--zd = evaltyp(t_INT) | evallg(lz);
     230    369914275 :   return gc_const((pari_sp)zd, zd);
     231              : }
     232              : 
     233              : /* assume x > y */
     234              : static GEN
     235   3521063172 : subiispec(GEN x, GEN y, long nx, long ny)
     236              : {
     237              :   GEN xd,yd,zd;
     238   3521063172 :   long lz, i = -2;
     239              :   LOCAL_OVERFLOW;
     240              : 
     241   3521063172 :   if (ny==1) return subiuspec(x,*y,nx);
     242   2060950547 :   zd = (GEN)avma;
     243   2060950547 :   lz = nx+2; (void)new_chunk(lz);
     244   2060950547 :   xd = x + nx;
     245   2060950547 :   yd = y + ny;
     246   2060950547 :   zd[-1] = subll(xd[-1], yd[-1]);
     247              : #ifdef subllx8
     248   2258183106 :   for (  ; i-8 > -ny; i-=8)
     249   1571199590 :     subllx8(xd+i, yd+i, zd+i, overflow);
     250              : #endif
     251  35387107279 :   for (  ; i >= -ny; i--) zd[i] = subllx(xd[i], yd[i]);
     252   2060950547 :   if (overflow)
     253              :     for(;;)
     254              :     {
     255   1000203389 :       zd[i] = uel(xd,i) - 1;
     256   1000203389 :       if (xd[i--]) break;
     257              :     }
     258   2060950547 :   if (i>=-nx)
     259   4601732897 :     for (; i >= -nx; i--) zd[i] = xd[i];
     260              :   else
     261   2458168319 :     while (zd[i+1] == 0) { i++; lz--; } /* shorten z */
     262   2060950547 :   zd += i+1;
     263   2060950547 :   *--zd = evalsigne(1) | evallgefint(lz);
     264   2060950547 :   *--zd = evaltyp(t_INT) | evallg(lz);
     265   2060950547 :   return gc_const((pari_sp)zd, zd);
     266              : }
     267              : 
     268              : static void
     269    465886688 : roundr_up_ip(GEN x, long l)
     270              : {
     271    465886688 :   long i = l;
     272              :   for(;;)
     273              :   {
     274    466855688 :     if (++uel(x,--i)) break;
     275      1305834 :     if (i == 2) { x[2] = (long)HIGHBIT; shiftr_inplace(x, 1); break; }
     276              :   }
     277    465886688 : }
     278              : 
     279              : void
     280    338479326 : affir(GEN x, GEN y)
     281              : {
     282    338479326 :   const long s = signe(x), ly = lg(y);
     283              :   long lx, sh, i;
     284              : 
     285    338479326 :   if (!s)
     286              :   {
     287     33146966 :     y[1] = evalexpo(-bit_accuracy(ly));
     288     33146966 :     return;
     289              :   }
     290              : 
     291    305332360 :   lx = lgefint(x); sh = bfffo(x[2]);
     292    305332360 :   y[1] = evalsigne(s) | evalexpo(bit_accuracy(lx)-sh-1);
     293    305332360 :   if (sh) {
     294    300012568 :     if (lx <= ly)
     295              :     {
     296    782767336 :       for (i=lx; i<ly; i++) y[i]=0;
     297    213596455 :       shift_left(y,x,2,lx-1, 0,sh);
     298    213596455 :       return;
     299              :     }
     300     86416113 :     shift_left(y,x,2,ly-1, x[ly],sh);
     301              :     /* lx > ly: round properly */
     302     86416113 :     if ((uel(x,ly)<<sh) & HIGHBIT) roundr_up_ip(y, ly);
     303              :   }
     304              :   else {
     305      5319792 :     if (lx <= ly)
     306              :     {
     307      4951047 :       for (i=2; i<lx; i++) y[i]=x[i];
     308      4002102 :       for (   ; i<ly; i++) y[i]=0;
     309      1359327 :       return;
     310              :     }
     311      9999855 :     for (i=2; i<ly; i++) y[i]=x[i];
     312              :     /* lx > ly: round properly */
     313      3960465 :     if (uel(x,ly) & HIGHBIT) roundr_up_ip(y, ly);
     314              :   }
     315              : }
     316              : 
     317              : INLINE GEN
     318   1302732264 : shiftispec(GEN x, long nx, long n)
     319              : {
     320              :   long ny, i, m;
     321              :   GEN y, yd;
     322   1302732264 :   if (!n)  return icopyspec(x, nx);
     323              : 
     324   1214012290 :   if (n > 0)
     325              :   {
     326    750576182 :     GEN z = (GEN)avma;
     327    750576182 :     long d = dvmdsBIL(n, &m);
     328              : 
     329    750576182 :     ny = nx+d; y = new_chunk(ny + 2); yd = y + 2;
     330   6789546239 :     for ( ; d; d--) *--z = 0;
     331   1929681689 :     if (!m) for (i=0; i<nx; i++) yd[i]=x[i];
     332              :     else
     333              :     {
     334    729457001 :       const ulong sh = BITS_IN_LONG - m;
     335    729457001 :       shift_left(yd,x, 0,nx-1, 0,m);
     336    729457001 :       i = uel(x,0) >> sh;
     337              :       /* Extend y on the left? */
     338    729457001 :       if (i) { ny++; y = new_chunk(1); y[2] = i; }
     339              :     }
     340              :   }
     341              :   else
     342              :   {
     343    463436108 :     ny = nx - dvmdsBIL(-n, &m);
     344    463436108 :     if (ny<1) return gen_0;
     345    462141182 :     y = new_chunk(ny + 2); yd = y + 2;
     346    462141182 :     if (m) {
     347    283084382 :       shift_right(yd,x, 0,ny, 0,m);
     348    283084382 :       if (yd[0] == 0)
     349              :       {
     350     33572448 :         if (ny==1) return gc_const((pari_sp)(y+3), gen_0);
     351     25809363 :         ny--; set_avma((pari_sp)(++y));
     352              :       }
     353              :     } else {
     354   7459962147 :       for (i=0; i<ny; i++) yd[i]=x[i];
     355              :     }
     356              :   }
     357   1204954279 :   y[1] = evalsigne(1)|evallgefint(ny + 2);
     358   1204954279 :   y[0] = evaltyp(t_INT)|evallg(ny + 2); return y;
     359              : }
     360              : 
     361              : GEN
     362     49675274 : mantissa2nr(GEN x, long n)
     363              : { /*This is a kludge since x is not an integer*/
     364     49675274 :   long s = signe(x);
     365              :   GEN y;
     366              : 
     367     49675274 :   if(s == 0) return gen_0;
     368     49674347 :   y = shiftispec(x + 2, lg(x) - 2, n);
     369     49674347 :   if (signe(y)) setsigne(y, s);
     370     49674347 :   return y;
     371              : }
     372              : 
     373              : GEN
     374      6223995 : truncr(GEN x)
     375              : {
     376              :   long d,e,i,s,m;
     377              :   GEN y;
     378              : 
     379      6223995 :   if ((s=signe(x)) == 0 || (e=expo(x)) < 0) return gen_0;
     380      4497351 :   d = nbits2lg(e+1); m = remsBIL(e);
     381      4497351 :   if (d > lg(x)) pari_err_PREC( "truncr (precision loss in truncation)");
     382              : 
     383      4497348 :   y=cgeti(d); y[1] = evalsigne(s) | evallgefint(d);
     384      4497348 :   if (++m == BITS_IN_LONG)
     385          828 :     for (i=2; i<d; i++) y[i]=x[i];
     386              :   else
     387      4496997 :     shift_right(y,x, 2,d,0, BITS_IN_LONG - m);
     388      4497348 :   return y;
     389              : }
     390              : 
     391              : /* integral part */
     392              : GEN
     393      5424084 : floorr(GEN x)
     394              : {
     395              :   long d,e,i,lx,m;
     396              :   GEN y;
     397              : 
     398      5424084 :   if (signe(x) >= 0) return truncr(x);
     399      3211134 :   if ((e=expo(x)) < 0) return gen_m1;
     400      2664714 :   d = nbits2lg(e+1); m = remsBIL(e);
     401      2664714 :   lx=lg(x); if (d>lx) pari_err_PREC( "floorr (precision loss in truncation)");
     402      2664714 :   y = new_chunk(d);
     403      2664714 :   if (++m == BITS_IN_LONG)
     404              :   {
     405          504 :     for (i=2; i<d; i++) y[i]=x[i];
     406          225 :     i=d; while (i<lx && !x[i]) i++;
     407          177 :     if (i==lx) goto END;
     408              :   }
     409              :   else
     410              :   {
     411      2664537 :     shift_right(y,x, 2,d,0, BITS_IN_LONG - m);
     412      2664537 :     if (uel(x,d-1)<<m == 0)
     413              :     {
     414       322167 :       i=d; while (i<lx && !x[i]) i++;
     415        86799 :       if (i==lx) goto END;
     416              :     }
     417              :   }
     418              :   /* set y:=y+1 */
     419      2605872 :   for (i=d-1; i>=2; i--) { uel(y,i)++; if (y[i]) goto END; }
     420            0 :   y=new_chunk(1); y[2]=1; d++;
     421      2664714 : END:
     422      2664714 :   y[1] = evalsigne(-1) | evallgefint(d);
     423      2664714 :   y[0] = evaltyp(t_INT) | evallg(d); return y;
     424              : }
     425              : 
     426              : INLINE int
     427   4266455255 : cmpiispec(GEN x, GEN y, long lx, long ly)
     428              : {
     429              :   long i;
     430   4266455255 :   if (lx < ly) return -1;
     431   3968110615 :   if (lx > ly) return  1;
     432   3950269936 :   i = 0; while (i<lx && x[i]==y[i]) i++;
     433   3437329731 :   if (i==lx) return 0;
     434   3208686650 :   return (uel(x,i) > uel(y,i))? 1: -1;
     435              : }
     436              : 
     437              : INLINE int
     438    229666920 : equaliispec(GEN x, GEN y, long lx, long ly)
     439              : {
     440              :   long i;
     441    229666920 :   if (lx != ly) return 0;
     442    428975706 :   i = ly-1; while (i>=0 && x[i]==y[i]) i--;
     443    229581240 :   return i < 0;
     444              : }
     445              : 
     446              : /***********************************************************************/
     447              : /**                                                                   **/
     448              : /**                          MULTIPLICATION                           **/
     449              : /**                                                                   **/
     450              : /***********************************************************************/
     451              : /* assume ny > 0 */
     452              : INLINE GEN
     453   4949982978 : muluispec(ulong x, GEN y, long ny)
     454              : {
     455   4949982978 :   GEN yd, z = (GEN)avma;
     456   4949982978 :   long lz = ny+3;
     457              :   LOCAL_HIREMAINDER;
     458              : 
     459   4949982978 :   (void)new_chunk(lz);
     460   4949982978 :   yd = y + ny; *--z = mulll(x, *--yd);
     461  16367746881 :   while (yd > y) *--z = addmul(x,*--yd);
     462   4949982978 :   if (hiremainder) *--z = hiremainder; else lz--;
     463   4949982978 :   *--z = evalsigne(1) | evallgefint(lz);
     464   4949982978 :   *--z = evaltyp(t_INT) | evallg(lz);
     465   4949982978 :   return gc_const((pari_sp)z, z);
     466              : }
     467              : 
     468              : /* a + b*|Y| */
     469              : GEN
     470            0 : addumului(ulong a, ulong b, GEN Y)
     471              : {
     472              :   GEN yd,y,z;
     473              :   long ny,lz;
     474              :   LOCAL_HIREMAINDER;
     475              :   LOCAL_OVERFLOW;
     476              : 
     477            0 :   if (!b || !signe(Y)) return utoi(a);
     478              : 
     479            0 :   y = LIMBS(Y); z = (GEN)avma;
     480            0 :   ny = NLIMBS(Y);
     481            0 :   lz = ny+3;
     482              : 
     483            0 :   (void)new_chunk(lz);
     484            0 :   yd = y + ny; *--z = addll(a, mulll(b, *--yd));
     485            0 :   if (overflow) hiremainder++; /* can't overflow */
     486            0 :   while (yd > y) *--z = addmul(b,*--yd);
     487            0 :   if (hiremainder) *--z = hiremainder; else lz--;
     488            0 :   *--z = evalsigne(1) | evallgefint(lz);
     489            0 :   *--z = evaltyp(t_INT) | evallg(lz);
     490            0 :   return gc_const((pari_sp)z, z);
     491              : }
     492              : 
     493              : /***********************************************************************/
     494              : /**                                                                   **/
     495              : /**                          DIVISION                                 **/
     496              : /**                                                                   **/
     497              : /***********************************************************************/
     498              : 
     499              : ulong
     500   1436816004 : umodiu(GEN y, ulong x)
     501              : {
     502   1436816004 :   long sy=signe(y),ly,i;
     503              :   ulong xi;
     504              :   LOCAL_HIREMAINDER;
     505              : 
     506   1436816004 :   if (!x) pari_err_INV("umodiu",gen_0);
     507   1436816004 :   if (!sy) return 0;
     508   1128280289 :   ly = lgefint(y);
     509   1128280289 :   if (x <= uel(y,2))
     510              :   {
     511    340378074 :     hiremainder=0;
     512    340378074 :     if (ly==3)
     513              :     {
     514    308464542 :       hiremainder=uel(y,2)%x;
     515    308464542 :       if (!hiremainder) return 0;
     516    256999452 :       return (sy > 0)? hiremainder: x - hiremainder;
     517              :     }
     518              :   }
     519              :   else
     520              :   {
     521    787902215 :     if (ly==3) return (sy > 0)? uel(y,2): x - uel(y,2);
     522    100093191 :     hiremainder=uel(y,2); ly--; y++;
     523              :   }
     524    132006723 :   xi = get_Fl_red(x);
     525    972447888 :   for (i=2; i<ly; i++) (void)divll_pre(y[i],x,xi);
     526    132006723 :   if (!hiremainder) return 0;
     527    125976906 :   return (sy > 0)? hiremainder: x - hiremainder;
     528              : }
     529              : 
     530              : /* return |y| \/ x */
     531              : GEN
     532    240933174 : absdiviu_rem(GEN y, ulong x, ulong *rem)
     533              : {
     534              :   long ly,i;
     535              :   GEN z;
     536              :   ulong xi;
     537              :   LOCAL_HIREMAINDER;
     538              : 
     539    240933174 :   if (!x) pari_err_INV("absdiviu_rem",gen_0);
     540    240933174 :   if (!signe(y)) { *rem = 0; return gen_0; }
     541              : 
     542    240356844 :   ly = lgefint(y);
     543    240356844 :   if (x <= uel(y,2))
     544              :   {
     545    222924819 :     hiremainder=0;
     546    222924819 :     if (ly==3)
     547              :     {
     548    198190866 :       z = cgetipos(3);
     549    198190866 :       z[2] = divll(uel(y,2),x);
     550    198190866 :       *rem = hiremainder; return z;
     551              :     }
     552              :   }
     553              :   else
     554              :   {
     555     17432025 :     if (ly==3) { *rem = uel(y,2); return gen_0; }
     556      7132599 :     hiremainder = uel(y,2); ly--; y++;
     557              :   }
     558     31866552 :   xi = get_Fl_red(x);
     559     31866552 :   z = cgetipos(ly);
     560    170173593 :   for (i=2; i<ly; i++) z[i]=divll_pre(y[i],x,xi);
     561     31866552 :   *rem = hiremainder; return z;
     562              : }
     563              : 
     564              : GEN
     565     66007341 : divis_rem(GEN y, long x, long *rem)
     566              : {
     567     66007341 :   long sy=signe(y),ly,s,i;
     568              :   GEN z;
     569              :   ulong xi;
     570              :   LOCAL_HIREMAINDER;
     571              : 
     572     66007341 :   if (!x) pari_err_INV("divis_rem",gen_0);
     573     66007341 :   if (!sy) { *rem=0; return gen_0; }
     574     46410576 :   if (x<0) { s = -sy; x = -x; } else s = sy;
     575              : 
     576     46410576 :   ly = lgefint(y);
     577     46410576 :   if ((ulong)x <= uel(y,2))
     578              :   {
     579     31849422 :     hiremainder=0;
     580     31849422 :     if (ly==3)
     581              :     {
     582     31544202 :       z = cgeti(3); z[1] = evallgefint(3) | evalsigne(s);
     583     31544202 :       z[2] = divll(uel(y,2),x);
     584     31544202 :       if (sy<0) hiremainder = - ((long)hiremainder);
     585     31544202 :       *rem = (long)hiremainder; return z;
     586              :     }
     587              :   }
     588              :   else
     589              :   {
     590     14561154 :     if (ly==3) { *rem = itos(y); return gen_0; }
     591       255132 :     hiremainder = uel(y,2); ly--; y++;
     592              :   }
     593       560352 :   xi = get_Fl_red(x);
     594       560352 :   z = cgeti(ly); z[1] = evallgefint(ly) | evalsigne(s);
     595      2993745 :   for (i=2; i<ly; i++) z[i]=divll_pre(y[i],x,xi);
     596       560352 :   if (sy<0) hiremainder = - ((long)hiremainder);
     597       560352 :   *rem = (long)hiremainder; return z;
     598              : }
     599              : 
     600              : GEN
     601       245295 : divis(GEN y, long x)
     602              : {
     603       245295 :   long sy=signe(y),ly,s,i;
     604              :   ulong xi;
     605              :   GEN z;
     606              :   LOCAL_HIREMAINDER;
     607              : 
     608       245295 :   if (!x) pari_err_INV("divis",gen_0);
     609       245295 :   if (!sy) return gen_0;
     610       245256 :   if (x<0) { s = -sy; x = -x; } else s = sy;
     611              : 
     612       245256 :   ly = lgefint(y);
     613       245256 :   if ((ulong)x <= uel(y,2))
     614              :   {
     615       236214 :     hiremainder=0;
     616       236214 :     if (ly==3)
     617              :     {
     618       166521 :       z = cgeti(3); z[1] = evallgefint(3) | evalsigne(s);
     619       166521 :       z[2] = divll(y[2],x);
     620       166521 :       return z;
     621              :     }
     622              :   }
     623              :   else
     624              :   {
     625         9042 :     if (ly==3) return gen_0;
     626         8808 :     hiremainder=y[2]; ly--; y++;
     627              :   }
     628        78501 :   xi = get_Fl_red(x);
     629        78501 :   z = cgeti(ly); z[1] = evallgefint(ly) | evalsigne(s);
     630       593844 :   for (i=2; i<ly; i++) z[i]=divll_pre(y[i],x, xi);
     631        78501 :   return z;
     632              : }
     633              : 
     634              : GEN
     635    141583263 : divrr(GEN x, GEN y)
     636              : {
     637    141583263 :   long sx=signe(x), sy=signe(y), lx,ly,lr,e,i,j;
     638              :   ulong y0,y1;
     639              :   GEN r, r1;
     640              : 
     641    141583263 :   if (!sy) pari_err_INV("divrr",y);
     642    141583263 :   e = expo(x) - expo(y);
     643    141583263 :   if (!sx) return real_0_bit(e);
     644    140672232 :   if (sy<0) sx = -sx;
     645              : 
     646    140672232 :   lx=lg(x); ly=lg(y);
     647    140672232 :   if (ly==3)
     648              :   {
     649     24530634 :     ulong k = x[2], l = (lx>3)? x[3]: 0;
     650              :     LOCAL_HIREMAINDER;
     651     24530634 :     if (k < uel(y,2)) e--;
     652              :     else
     653              :     {
     654      7203213 :       l >>= 1; if (k&1) l |= HIGHBIT;
     655      7203213 :       k >>= 1;
     656              :     }
     657     24530634 :     hiremainder = k; k = divll(l,y[2]);
     658     24530634 :     if (hiremainder > (uel(y,2) >> 1) && !++k) { k = HIGHBIT; e++; }
     659     24530634 :     r = cgetg(3, t_REAL);
     660     24530634 :     r[1] = evalsigne(sx) | evalexpo(e);
     661     24530634 :     r[2] = k; return r;
     662              :   }
     663              : 
     664    116141598 :   lr = minss(lx,ly); r = new_chunk(lr);
     665    116141598 :   r1 = r-1;
     666    792830739 :   r1[1] = 0; for (i=2; i<lr; i++) r1[i]=x[i];
     667    116141598 :   r1[lr] = (lx>ly)? x[lr]: 0;
     668    116141598 :   y0 = y[2]; y1 = y[3];
     669    908972337 :   for (i=0; i<lr-1; i++)
     670              :   { /* r1 = r + (i-1), OK up to r1[2] (accesses at most r[lr]) */
     671              :     ulong k, qp;
     672              :     LOCAL_HIREMAINDER;
     673              :     LOCAL_OVERFLOW;
     674              : 
     675    792830739 :     if (uel(r1,1) == y0) { qp = ULONG_MAX; k = addll(y0,r1[2]); }
     676              :     else
     677              :     {
     678    791190933 :       if (uel(r1,1) > y0) /* can't happen if i=0 */
     679              :       {
     680            0 :         GEN y1 = y+1;
     681            0 :         j = lr-i; r1[j] = subll(r1[j],y1[j]);
     682            0 :         for (j--; j>0; j--) r1[j] = subllx(r1[j],y1[j]);
     683            0 :         j=i; do uel(r,--j)++; while (j && !uel(r,j));
     684              :       }
     685    791190933 :       hiremainder = r1[1]; overflow = 0;
     686    791190933 :       qp = divll(r1[2],y0); k = hiremainder;
     687              :     }
     688    792830739 :     j = lr-i+1;
     689    792830739 :     if (!overflow)
     690              :     {
     691              :       long k3, k4;
     692    791536257 :       k3 = mulll(qp,y1);
     693    791536257 :       if (j == 3) /* i = lr - 2 maximal, r1[3] undefined -> 0 */
     694    116069022 :         k4 = subll(hiremainder,k);
     695              :       else
     696              :       {
     697    675467235 :         k3 = subll(k3, r1[3]);
     698    675467235 :         k4 = subllx(hiremainder,k);
     699              :       }
     700   1047667762 :       while (!overflow && k4) { qp--; k3 = subll(k3,y1); k4 = subllx(k4,y0); }
     701              :     }
     702    792830739 :     if (j<ly) (void)mulll(qp,y[j]); else { hiremainder = 0 ; j = ly; }
     703   5133017559 :     for (j--; j>1; j--)
     704              :     {
     705   4340186820 :       r1[j] = subll(r1[j], addmul(qp,y[j]));
     706   4340186820 :       hiremainder += overflow;
     707              :     }
     708    792830739 :     if (uel(r1,1) != hiremainder)
     709              :     {
     710       657828 :       if (uel(r1,1) < hiremainder)
     711              :       {
     712       657828 :         qp--;
     713       657828 :         j = lr-i-(lr-i>=ly); r1[j] = addll(r1[j], y[j]);
     714      3518232 :         for (j--; j>1; j--) r1[j] = addllx(r1[j], y[j]);
     715              :       }
     716              :       else
     717              :       {
     718            0 :         r1[1] -= hiremainder;
     719            0 :         while (r1[1])
     720              :         {
     721            0 :           qp++; if (!qp) { j=i; do uel(r,--j)++; while (j && !r[j]); }
     722            0 :           j = lr-i-(lr-i>=ly); r1[j] = subll(r1[j],y[j]);
     723            0 :           for (j--; j>1; j--) r1[j] = subllx(r1[j],y[j]);
     724            0 :           r1[1] -= overflow;
     725              :         }
     726              :       }
     727              :     }
     728    792830739 :     *++r1 = qp;
     729              :   }
     730              :   /* i = lr-1 */
     731              :   /* round correctly */
     732    116141598 :   if (uel(r1,1) > (y0>>1))
     733              :   {
     734     57148794 :     j=i; do uel(r,--j)++; while (j && !r[j]);
     735              :   }
     736    792830739 :   r1 = r-1; for (j=i; j>=2; j--) r[j]=r1[j];
     737    116141598 :   if (r[0] == 0) e--;
     738     49010550 :   else if (r[0] == 1) { shift_right(r,r, 2,lr, 1,1); }
     739              :   else { /* possible only when rounding up to 0x2 0x0 ... */
     740            6 :     r[2] = (long)HIGHBIT; e++;
     741              :   }
     742    116141598 :   r[0] = evaltyp(t_REAL)|evallg(lr);
     743    116141598 :   r[1] = evalsigne(sx) | evalexpo(e);
     744    116141598 :   return r;
     745              : }
     746              : 
     747              : GEN
     748    121880001 : divri(GEN x, GEN y)
     749              : {
     750    121880001 :   long lx, s = signe(y);
     751              :   pari_sp av;
     752              :   GEN z;
     753              : 
     754    121880001 :   if (!s) pari_err_INV("divri",y);
     755    121880001 :   if (!signe(x)) return real_0_bit(expo(x) - expi(y));
     756    121694871 :   if (!is_bigint(y)) {
     757     97220382 :     GEN z = divru(x, y[2]);
     758     97220382 :     if (s < 0) togglesign(z);
     759     97220382 :     return z;
     760              :   }
     761     24474489 :   lx = lg(x); z = cgetg(lx, t_REAL); av = avma;
     762     24474489 :   affrr(divrr(x, itor(y, lg2prec(lx+1))), z);
     763     24474489 :   return gc_const(av, z);
     764              : }
     765              : 
     766              : /* Integer division x / y: such that sign(r) = sign(x)
     767              :  *   if z = ONLY_REM return remainder, otherwise return quotient
     768              :  *   if z != NULL set *z to remainder
     769              :  *   *z is the last object on stack (and can be disposed of with cgiv
     770              :  * If *z is zero, we put gen_0 here and no copy.
     771              :  * space needed: lx + ly */
     772              : GEN
     773   1700752707 : dvmdii(GEN x, GEN y, GEN *z)
     774              : {
     775   1700752707 :   long sx = signe(x), sy = signe(y);
     776   1700752707 :   long lx, ly = lgefint(y), lz, i, j, sh, lq, lr;
     777              :   pari_sp av;
     778              :   ulong y0,y0i,y1, *xd,*rd,*qd;
     779              :   GEN q, r, r1;
     780              : 
     781   1700752707 :   if (!sx)
     782              :   {
     783     54656034 :     if (ly < 3) pari_err_INV("dvmdii",gen_0);
     784     54656031 :     if (!z || z == ONLY_REM) return gen_0;
     785     32721936 :     *z=gen_0; return gen_0;
     786              :   }
     787   1646096673 :   if (ly <= 3)
     788              :   {
     789              :     ulong rem;
     790    662713413 :     if (ly < 3) pari_err_INV("dvmdii",gen_0);
     791    662713413 :     if (z == ONLY_REM)
     792              :     {
     793    449094399 :       rem = umodiu(x,uel(y,2));
     794    449094399 :       if (!rem) return gen_0;
     795    405472260 :       return (sx < 0)? utoineg(uel(y,2) - rem): utoipos(rem);
     796              :     }
     797    213619014 :     q = absdiviu_rem(x, uel(y,2), &rem);
     798    213619014 :     if (sx != sy) togglesign(q);
     799    213619014 :     if (!z) return q;
     800    209568831 :     if (!rem) *z = gen_0;
     801     61606899 :     else *z = sx < 0? utoineg(rem): utoipos(rem);
     802    209568831 :     return q;
     803              :   }
     804    983383260 :   lx=lgefint(x);
     805    983383260 :   lz=lx-ly;
     806    983383260 :   if (lz <= 0)
     807              :   {
     808    450148623 :     if (lz == 0)
     809              :     {
     810    342290124 :       for (i=2; i<lx; i++)
     811    341669211 :         if (x[i] != y[i])
     812              :         {
     813    324916287 :           if (uel(x,i) > uel(y,i)) goto DIVIDE;
     814     45561888 :           goto TRIVIAL;
     815              :         }
     816       620913 :       if (z == ONLY_REM) return gen_0;
     817        66168 :       if (z) *z = gen_0;
     818        66168 :       if (sx < 0) sy = -sy;
     819        66168 :       return stoi(sy);
     820              :     }
     821    124611423 : TRIVIAL:
     822    170173311 :     if (z == ONLY_REM) return icopy(x);
     823      2215110 :     if (z) *z = icopy(x);
     824      2215110 :     return gen_0;
     825              :   }
     826    533234637 : DIVIDE: /* quotient is nonzero */
     827    812589036 :   av=avma; if (sx<0) sy = -sy;
     828    812589036 :   r1 = new_chunk(lx); sh = bfffo(y[2]);
     829    812589036 :   if (sh)
     830              :   { /* normalize so that highbit(y) = 1 (shift left x and y by sh bits)*/
     831    803532363 :     const ulong m = BITS_IN_LONG - sh;
     832    803532363 :     r = new_chunk(ly);
     833    803532363 :     shift_left(r, y,2,ly-1, 0,sh); y = r;
     834    803532363 :     shift_left(r1,x,2,lx-1, 0,sh);
     835    803532363 :     r1[1] = uel(x,2) >> m;
     836              :   }
     837              :   else
     838              :   {
     839     96964746 :     r1[1] = 0; for (j=2; j<lx; j++) r1[j] = x[j];
     840              :   }
     841    812589036 :   x = r1;
     842    812589036 :   y0 = y[2]; y0i = get_Fl_red(y0);
     843    812589036 :   y1 = y[3];
     844   3305797500 :   for (i=0; i<=lz; i++)
     845              :   { /* r1 = x + i */
     846              :     ulong k, qp;
     847              :     LOCAL_HIREMAINDER;
     848              :     LOCAL_OVERFLOW;
     849              : 
     850   2493208464 :     if (uel(r1,1) == y0)
     851              :     {
     852        49956 :       qp = ULONG_MAX; k = addll(y0,r1[2]);
     853              :     }
     854              :     else
     855              :     {
     856   2493158508 :       hiremainder = r1[1]; overflow = 0;
     857   2493158508 :       qp = divll_pre(r1[2],y0,y0i); k = hiremainder;
     858              :     }
     859   2493208464 :     if (!overflow)
     860              :     {
     861   2493157674 :       long k3 = subll(mulll(qp,y1), r1[3]);
     862   2493157674 :       long k4 = subllx(hiremainder,k);
     863   3041802787 :       while (!overflow && k4) { qp--; k3 = subll(k3,y1); k4 = subllx(k4,y0); }
     864              :     }
     865   2493208464 :     hiremainder = 0; j = ly;
     866  65337346578 :     for (j--; j>1; j--)
     867              :     {
     868  62844138114 :       r1[j] = subll(r1[j], addmul(qp,y[j]));
     869  62844138114 :       hiremainder += overflow;
     870              :     }
     871   2493208464 :     if (uel(r1,1) < hiremainder)
     872              :     {
     873      6137838 :       qp--;
     874      6137838 :       j = ly-1; r1[j] = addll(r1[j],y[j]);
     875     32124053 :       for (j--; j>1; j--) r1[j] = addllx(r1[j],y[j]);
     876              :     }
     877   2493208464 :     *++r1 = qp;
     878              :   }
     879              : 
     880    812589036 :   lq = lz+2;
     881    812589036 :   if (!z)
     882              :   {
     883      2810940 :     qd = (ulong*)av;
     884      2810940 :     xd = (ulong*)(x + lq);
     885      2810940 :     if (x[1]) { lz++; lq++; }
     886     34977768 :     while (lz--) *--qd = *--xd;
     887      2810940 :     *--qd = evalsigne(sy) | evallgefint(lq);
     888      2810940 :     *--qd = evaltyp(t_INT) | evallg(lq);
     889      2810940 :     return gc_const((pari_sp)qd, (GEN)qd);
     890              :   }
     891              : 
     892    912468051 :   j=lq; while (j<lx && !x[j]) j++;
     893    809778096 :   lz = lx-j;
     894    809778096 :   if (z == ONLY_REM)
     895              :   {
     896    519885951 :     if (lz==0) return gc_const(av, gen_0);
     897    509877474 :     rd = (ulong*)av; lr = lz+2;
     898    509877474 :     xd = (ulong*)(x + lx);
     899    543903102 :     if (!sh) while (lz--) *--rd = *--xd;
     900              :     else
     901              :     { /* shift remainder right by sh bits */
     902    501713841 :       const ulong shl = BITS_IN_LONG - sh;
     903              :       ulong l;
     904    501713841 :       xd--;
     905   1499995452 :       while (--lz) /* fill r[3..] */
     906              :       {
     907    998281611 :         l = *xd >> sh;
     908    998281611 :         *--rd = l | (*--xd << shl);
     909              :       }
     910    501713841 :       l = *xd >> sh;
     911    501713841 :       if (l) *--rd = l; else lr--;
     912              :     }
     913    509877474 :     *--rd = evalsigne(sx) | evallgefint(lr);
     914    509877474 :     *--rd = evaltyp(t_INT) | evallg(lr);
     915    509877474 :     return gc_const((pari_sp)rd, (GEN)rd);
     916              :   }
     917              : 
     918    289892145 :   lr = lz+2;
     919    289892145 :   rd = NULL; /* gcc -Wall */
     920    289892145 :   if (lz)
     921              :   { /* non zero remainder: initialize rd */
     922    284520900 :     xd = (ulong*)(x + lx);
     923    284520900 :     if (!sh)
     924              :     {
     925       588114 :       rd = (ulong*)avma; (void)new_chunk(lr);
     926      5991525 :       while (lz--) *--rd = *--xd;
     927              :     }
     928              :     else
     929              :     { /* shift remainder right by sh bits */
     930    283932786 :       const ulong shl = BITS_IN_LONG - sh;
     931              :       ulong l;
     932    283932786 :       rd = (ulong*)x; /* overwrite shifted y */
     933    283932786 :       xd--;
     934   1263478455 :       while (--lz)
     935              :       {
     936    979545669 :         l = *xd >> sh;
     937    979545669 :         *--rd = l | (*--xd << shl);
     938              :       }
     939    283932786 :       l = *xd >> sh;
     940    283932786 :       if (l) *--rd = l; else lr--;
     941              :     }
     942    284520900 :     *--rd = evalsigne(sx) | evallgefint(lr);
     943    284520900 :     *--rd = evaltyp(t_INT) | evallg(lr);
     944    284520900 :     rd += lr;
     945              :   }
     946    289892145 :   qd = (ulong*)av;
     947    289892145 :   xd = (ulong*)(x + lq);
     948    289892145 :   if (x[1]) lq++;
     949    907836795 :   j = lq-2; while (j--) *--qd = *--xd;
     950    289892145 :   *--qd = evalsigne(sy) | evallgefint(lq);
     951    289892145 :   *--qd = evaltyp(t_INT) | evallg(lq);
     952    289892145 :   q = (GEN)qd;
     953    289892145 :   if (lr==2) *z = gen_0;
     954              :   else
     955              :   { /* rd has been properly initialized: we had lz > 0 */
     956   1936013969 :     while (lr--) *--qd = *--rd;
     957    284520900 :     *z = (GEN)qd;
     958              :   }
     959    289892145 :   return gc_const((pari_sp)qd, q);
     960              : }
     961              : 
     962              : /* Montgomery reduction.
     963              :  * N has k words, assume T >= 0 has less than 2k.
     964              :  * Return res := T / B^k mod N, where B = 2^BIL
     965              :  * such that 0 <= res < T/B^k + N  and  res has less than k words */
     966              : GEN
     967     36218139 : red_montgomery(GEN T, GEN N, ulong inv)
     968              : {
     969              :   pari_sp av;
     970              :   GEN Te, Td, Ne, Nd, scratch;
     971     36218139 :   ulong i, j, m, t, d, k = NLIMBS(N);
     972              :   int carry;
     973              :   LOCAL_HIREMAINDER;
     974              :   LOCAL_OVERFLOW;
     975              : 
     976     36218139 :   if (k == 0) return gen_0;
     977     36218139 :   d = NLIMBS(T); /* <= 2*k */
     978     36218139 :   if (d == 0) return gen_0;
     979              : #ifdef DEBUG
     980              :   if (d > 2*k) pari_err_BUG("red_montgomery");
     981              : #endif
     982     36218130 :   if (k == 1)
     983              :   { /* as below, special cased for efficiency */
     984       163341 :     ulong n = uel(N,2);
     985       163341 :     if (d == 1) {
     986       163194 :       hiremainder = uel(T,2);
     987       163194 :       m = hiremainder * inv;
     988       163194 :       (void)addmul(m, n); /* t + m*n = 0 */
     989       163194 :       return utoi(hiremainder);
     990              :     } else { /* d = 2 */
     991          147 :       hiremainder = uel(T,3);
     992          147 :       m = hiremainder * inv;
     993          147 :       (void)addmul(m, n); /* t + m*n = 0 */
     994          147 :       t = addll(hiremainder, uel(T,2));
     995          147 :       if (overflow) t -= n; /* t > n doesn't fit in 1 word */
     996          147 :       return utoi(t);
     997              :     }
     998              :   }
     999              :   /* assume k >= 2 */
    1000     36054789 :   av = avma; scratch = new_chunk(k<<1); /* >= k + 2: result fits */
    1001              : 
    1002              :   /* copy T to scratch space (pad with zeroes to 2k words) */
    1003     36054789 :   Td = (GEN)av;
    1004     36054789 :   Te = T + (d+2);
    1005    784472676 :   for (i=0; i < d     ; i++) *--Td = *--Te;
    1006     61065600 :   for (   ; i < (k<<1); i++) *--Td = 0;
    1007              : 
    1008     36054789 :   Te = (GEN)av; /* 1 beyond end of current T mantissa (in scratch) */
    1009     36054789 :   Ne = N + k+2; /* 1 beyond end of N mantissa */
    1010              : 
    1011     36054789 :   carry = 0;
    1012    422769138 :   for (i=0; i<k; i++) /* set T := T/B nod N, k times */
    1013              :   {
    1014    386714349 :     Td = Te; /* one beyond end of (new) T mantissa */
    1015    386714349 :     Nd = Ne;
    1016    386714349 :     hiremainder = *--Td;
    1017    386714349 :     m = hiremainder * inv; /* solve T + m N = O(B) */
    1018              : 
    1019              :     /* set T := (T + mN) / B */
    1020    386714349 :     Te = Td;
    1021    386714349 :     (void)addmul(m, *--Nd); /* = 0 */
    1022   6389079759 :     for (j=1; j<k; j++)
    1023              :     {
    1024   6002365410 :       t = addll(addmul(m, *--Nd), *--Td);
    1025   6002365410 :       *Td = t;
    1026   6002365410 :       hiremainder += overflow;
    1027              :     }
    1028    386714349 :     t = addll(hiremainder, *--Td); *Td = t + carry;
    1029    386714349 :     carry = (overflow || (carry && *Td == 0));
    1030              :   }
    1031     36054789 :   if (carry)
    1032              :   { /* Td > N overflows (k+1 words), set Td := Td - N */
    1033       453672 :     Td = Te;
    1034       453672 :     Nd = Ne;
    1035       453672 :     t = subll(*--Td, *--Nd); *Td = t;
    1036      7866927 :     while (Td > scratch) { t = subllx(*--Td, *--Nd); *Td = t; }
    1037              :   }
    1038              : 
    1039              :   /* copy result */
    1040     36054789 :   Td = (GEN)av;
    1041     39845859 :   while (*scratch == 0 && Te > scratch) scratch++; /* strip leading 0s */
    1042    418978068 :   while (Te > scratch) *--Td = *--Te;
    1043     36054789 :   k = (GEN)av - Td; if (!k) return gc_const(av, gen_0);
    1044     36054789 :   k += 2;
    1045     36054789 :   *--Td = evalsigne(1) | evallgefint(k);
    1046     36054789 :   *--Td = evaltyp(t_INT) | evallg(k);
    1047              : #ifdef DEBUG
    1048              : {
    1049              :   long l = NLIMBS(N), s = BITS_IN_LONG*l;
    1050              :   GEN R = int2n(s);
    1051              :   GEN res = remii(mulii(T, Fp_inv(R, N)), N);
    1052              :   if (k > lgefint(N)
    1053              :     || !equalii(remii(Td,N),res)
    1054              :     || cmpii(Td, addii(shifti(T, -s), N)) >= 0) pari_err_BUG("red_montgomery");
    1055              : }
    1056              : #endif
    1057     36054789 :   return gc_const((pari_sp)Td, Td);
    1058              : }
    1059              : 
    1060              : /* EXACT INTEGER DIVISION */
    1061              : 
    1062              : /* assume xy>0, the division is exact and y is odd. Destroy x */
    1063              : static GEN
    1064     29911257 : diviuexact_i(GEN x, ulong y)
    1065              : {
    1066              :   long i, lz, lx;
    1067              :   ulong q, yinv;
    1068              :   GEN z, z0, x0, x0min;
    1069              : 
    1070     29911257 :   if (y == 1) return icopy(x);
    1071     24049347 :   lx = lgefint(x);
    1072     24049347 :   if (lx == 3)
    1073              :   {
    1074       860463 :     q = uel(x,2) / y;
    1075       860463 :     if (!q) pari_err_OP("exact division", x, utoi(y));
    1076       860463 :     return utoipos(q);
    1077              :   }
    1078     23188884 :   yinv = invmod2BIL(y);
    1079     23188884 :   lz = (y <= uel(x,2)) ? lx : lx-1;
    1080     23188884 :   z = new_chunk(lz);
    1081     23188884 :   z0 = z + lz;
    1082     23188884 :   x0 = x + lx; x0min = x + lx-lz+2;
    1083              : 
    1084     84624135 :   while (x0 > x0min)
    1085              :   {
    1086     61435251 :     *--z0 = q = yinv*uel(--x0,0); /* i-th quotient */
    1087     61435251 :     if (!q) continue;
    1088              :     /* x := x - q * y */
    1089              :     { /* update neither lowest word (could set it to 0) nor highest ones */
    1090     60906021 :       GEN x1 = x0 - 1;
    1091              :       LOCAL_HIREMAINDER;
    1092     60906021 :       (void)mulll(q,y);
    1093     60906021 :       if (hiremainder)
    1094              :       {
    1095     48764691 :         if (uel(x1,0) < hiremainder)
    1096              :         {
    1097       141360 :           uel(x1,0) -= hiremainder;
    1098       149697 :           do uel(--x1,0)--; while (uel(x1,0) == ULONG_MAX);
    1099              :         }
    1100              :         else
    1101     48623331 :           uel(x1,0) -= hiremainder;
    1102              :       }
    1103              :     }
    1104              :   }
    1105     23188884 :   i=2; while(!z[i]) i++;
    1106     23188884 :   z += i-2; lz -= i-2;
    1107     23188884 :   z[0] = evaltyp(t_INT)|evallg(lz);
    1108     23188884 :   z[1] = evalsigne(1)|evallg(lz);
    1109     23188884 :   if (lz == 2) pari_err_OP("exact division", x, utoi(y));
    1110     23188884 :   return gc_const((pari_sp)z, z);
    1111              : }
    1112              : 
    1113              : /* assume y != 0 and the division is exact */
    1114              : GEN
    1115     22492209 : diviuexact(GEN x, ulong y)
    1116              : {
    1117              :   pari_sp av;
    1118     22492209 :   long lx, vy, s = signe(x);
    1119              :   GEN z;
    1120              : 
    1121     22492209 :   if (!s) return gen_0;
    1122     21447936 :   if (y == 1) return icopy(x);
    1123     18454026 :   lx = lgefint(x);
    1124     18454026 :   if (lx == 3) {
    1125     14007201 :     ulong q = uel(x,2) / y;
    1126     14007201 :     if (!q) pari_err_OP("exact division", x, utoi(y));
    1127     14007201 :     return (s > 0)? utoipos(q): utoineg(q);
    1128              :   }
    1129      4446825 :   av = avma; (void)new_chunk(lx); vy = vals(y);
    1130      4446825 :   if (vy) {
    1131      1797663 :     y >>= vy;
    1132      1797663 :     if (y == 1) { set_avma(av); return shifti(x, -vy); }
    1133       846027 :     x = shifti(x, -vy);
    1134       846027 :     if (lx == 3) {
    1135            0 :       ulong q = uel(x,2) / y;
    1136            0 :       set_avma(av);
    1137            0 :       if (!q) pari_err_OP("exact division", x, utoi(y));
    1138            0 :       return (s > 0)? utoipos(q): utoineg(q);
    1139              :     }
    1140      2649162 :   } else x = icopy(x);
    1141      3495189 :   set_avma(av);
    1142      3495189 :   z = diviuexact_i(x, y);
    1143      3495189 :   setsigne(z, s); return z;
    1144              : }
    1145              : 
    1146              : /* Find z such that x=y*z, knowing that y | x (unchecked)
    1147              :  * Method: y0 z0 = x0 mod B = 2^BITS_IN_LONG ==> z0 = 1/y0 mod B.
    1148              :  *    Set x := (x - z0 y) / B, updating only relevant words, and repeat */
    1149              : GEN
    1150    392220945 : diviiexact(GEN x, GEN y)
    1151              : {
    1152    392220945 :   long lx, ly, lz, vy, i, ii, sx = signe(x), sy = signe(y);
    1153              :   pari_sp av;
    1154              :   ulong y0inv,q;
    1155              :   GEN z;
    1156              : 
    1157    392220945 :   if (!sy) pari_err_INV("diviiexact",gen_0);
    1158    392220945 :   if (!sx) return gen_0;
    1159    322964085 :   lx = lgefint(x);
    1160    322964085 :   if (lx == 3) {
    1161    259073406 :     q = uel(x,2) / uel(y,2);
    1162    259073406 :     if (!q) pari_err_OP("exact division", x, y);
    1163    259073406 :     return (sx+sy) ? utoipos(q): utoineg(q);
    1164              :   }
    1165     63890679 :   vy = vali(y); av = avma;
    1166     63890679 :   (void)new_chunk(lx); /* enough room for z */
    1167     63890679 :   if (vy)
    1168              :   { /* make y odd */
    1169     32805369 :     y = shifti(y,-vy);
    1170     32805369 :     x = shifti(x,-vy); lx = lgefint(x);
    1171              :   }
    1172     31085310 :   else x = icopy(x); /* necessary because we destroy x */
    1173     63890679 :   set_avma(av); /* will erase our x,y when exiting */
    1174              :   /* now y is odd */
    1175     63890679 :   ly = lgefint(y);
    1176     63890679 :   if (ly == 3)
    1177              :   {
    1178     26416068 :     z = diviuexact_i(x,uel(y,2)); /* x != 0 */
    1179     26416068 :     setsigne(z, (sx+sy)? 1: -1); return z;
    1180              :   }
    1181     37474611 :   y0inv = invmod2BIL(y[ly-1]);
    1182     61239348 :   i=2; while (i<ly && y[i]==x[i]) i++;
    1183     37474611 :   lz = (i==ly || uel(y,i) < uel(x,i)) ? lx-ly+3 : lx-ly+2;
    1184     37474611 :   z = new_chunk(lz);
    1185              : 
    1186     37474611 :   y += ly - 1; /* now y[-i] = i-th word of y */
    1187    174970509 :   for (ii=lx-1,i=lz-1; i>=2; i--,ii--)
    1188              :   {
    1189              :     long limj;
    1190              :     LOCAL_HIREMAINDER;
    1191              :     LOCAL_OVERFLOW;
    1192              : 
    1193    137495898 :     z[i] = q = y0inv*uel(x,ii); /* i-th quotient */
    1194    137495898 :     if (!q) continue;
    1195              : 
    1196              :     /* x := x - q * y */
    1197    137363742 :     (void)mulll(q,y[0]); limj = maxss(lx - lz, ii+3-ly);
    1198              :     { /* update neither lowest word (could set it to 0) nor highest ones */
    1199    137363742 :       GEN x0 = x + (ii - 1), y0 = y - 1, xlim = x + limj;
    1200   3009155964 :       for (; x0 >= xlim; x0--, y0--)
    1201              :       {
    1202   2871792222 :         *x0 = subll(*x0, addmul(q,*y0));
    1203   2871792222 :         hiremainder += overflow;
    1204              :       }
    1205    137363742 :       if (hiremainder && limj != lx - lz)
    1206              :       {
    1207     72510576 :         if ((ulong)*x0 < hiremainder)
    1208              :         {
    1209       834336 :           *x0 -= hiremainder;
    1210       834354 :           do (*--x0)--; while ((ulong)*x0 == ULONG_MAX);
    1211              :         }
    1212              :         else
    1213     71676240 :           *x0 -= hiremainder;
    1214              :       }
    1215              :     }
    1216              :   }
    1217     37474611 :   i=2; while(!z[i]) i++;
    1218     37474611 :   z += i-2; lz -= (i-2);
    1219     37474611 :   z[0] = evaltyp(t_INT)|evallg(lz);
    1220     37474611 :   z[1] = evalsigne((sx+sy)? 1: -1) | evallg(lz);
    1221     37474611 :   if (lz == 2) pari_err_OP("exact division", x, y);
    1222     37474611 :   return gc_const((pari_sp)z, z);
    1223              : }
    1224              : 
    1225              : /* assume yz != and yz | x */
    1226              : GEN
    1227       150054 : diviuuexact(GEN x, ulong y, ulong z)
    1228              : {
    1229              :   long tmp[4];
    1230              :   ulong t;
    1231              :   LOCAL_HIREMAINDER;
    1232       150054 :   t = mulll(y, z);
    1233       150054 :   if (!hiremainder) return diviuexact(x, t);
    1234            0 :   tmp[0] = evaltyp(t_INT)|_evallg(4);
    1235            0 :   tmp[1] = evalsigne(1)|evallgefint(4);
    1236            0 :   tmp[2] = hiremainder;
    1237            0 :   tmp[3] = t;
    1238            0 :   return diviiexact(x, tmp);
    1239              : }
    1240              : 
    1241              : /********************************************************************/
    1242              : /**                                                                **/
    1243              : /**               INTEGER MULTIPLICATION (BASECASE)                **/
    1244              : /**                                                                **/
    1245              : /********************************************************************/
    1246              : /* nx >= ny = num. of digits of x, y (not GEN, see mulii) */
    1247              : INLINE GEN
    1248   5269019361 : muliispec_basecase(GEN x, GEN y, long nx, long ny)
    1249              : {
    1250              :   GEN z2e,z2d,yd,xd,ye,zd;
    1251              :   long p1,lz;
    1252              :   LOCAL_HIREMAINDER;
    1253              : 
    1254   5269019361 :   if (ny == 1) return muluispec((ulong)*y, x, nx);
    1255   1165411905 :   if (ny == 0) return gen_0;
    1256   1164166644 :   zd = (GEN)avma; lz = nx+ny+2;
    1257   1164166644 :   (void)new_chunk(lz);
    1258   1164166644 :   xd = x + nx;
    1259   1164166644 :   yd = y + ny;
    1260   1164166644 :   ye = yd; p1 = *--xd;
    1261              : 
    1262   1164166644 :   *--zd = mulll(p1, *--yd); z2e = zd;
    1263   9751944981 :   while (yd > y) *--zd = addmul(p1, *--yd);
    1264   1164166644 :   *--zd = hiremainder;
    1265              : 
    1266  11266203471 :   while (xd > x)
    1267              :   {
    1268              :     LOCAL_OVERFLOW;
    1269  10102036827 :     yd = ye; p1 = *--xd;
    1270              : 
    1271  10102036827 :     z2d = --z2e;
    1272  10102036827 :     *z2d = addll(mulll(p1, *--yd), *z2d); z2d--;
    1273  >12717*10^7 :     while (yd > y)
    1274              :     {
    1275  >11706*10^7 :       hiremainder += overflow;
    1276  >11706*10^7 :       *z2d = addll(addmul(p1, *--yd), *z2d); z2d--;
    1277              :     }
    1278  10102036827 :     *--zd = hiremainder + overflow;
    1279              :   }
    1280   1164166644 :   if (*zd == 0) { zd++; lz--; } /* normalize */
    1281   1164166644 :   *--zd = evalsigne(1) | evallgefint(lz);
    1282   1164166644 :   *--zd = evaltyp(t_INT) | evallg(lz);
    1283   1164166644 :   return gc_const((pari_sp)zd, zd);
    1284              : }
    1285              : 
    1286              : INLINE GEN
    1287    943504476 : sqrispec_basecase(GEN x, long nx)
    1288              : {
    1289              :   GEN z2e,z2d,yd,xd,zd,x0,z0;
    1290              :   long p1,lz;
    1291              :   LOCAL_HIREMAINDER;
    1292              :   LOCAL_OVERFLOW;
    1293              : 
    1294    943504476 :   if (nx == 1) return sqru((ulong)*x);
    1295    629262582 :   if (nx == 0) return gen_0;
    1296    225513504 :   zd = (GEN)avma; lz = (nx+1) << 1;
    1297    225513504 :   z0 = new_chunk(lz);
    1298    225513504 :   if (nx == 1)
    1299              :   {
    1300            0 :     *--zd = mulll(*x, *x);
    1301            0 :     *--zd = hiremainder; goto END;
    1302              :   }
    1303    225513504 :   xd = x + nx;
    1304              : 
    1305              :   /* compute double products --> zd */
    1306    225513504 :   p1 = *--xd; yd = xd; --zd;
    1307    225513504 :   *--zd = mulll(p1, *--yd); z2e = zd;
    1308   1349503872 :   while (yd > x) *--zd = addmul(p1, *--yd);
    1309    225513504 :   *--zd = hiremainder;
    1310              : 
    1311    225513504 :   x0 = x+1;
    1312   1349503872 :   while (xd > x0)
    1313              :   {
    1314              :     LOCAL_OVERFLOW;
    1315   1123990368 :     p1 = *--xd; yd = xd;
    1316              : 
    1317   1123990368 :     z2e -= 2; z2d = z2e;
    1318   1123990368 :     *z2d = addll(mulll(p1, *--yd), *z2d); z2d--;
    1319  10442928612 :     while (yd > x)
    1320              :     {
    1321   9318938244 :       hiremainder += overflow;
    1322   9318938244 :       *z2d = addll(addmul(p1, *--yd), *z2d); z2d--;
    1323              :     }
    1324   1123990368 :     *--zd = hiremainder + overflow;
    1325              :   }
    1326              :   /* multiply zd by 2 (put result in zd - 1) */
    1327    225513504 :   zd[-1] = ((*zd & HIGHBIT) != 0);
    1328    225513504 :   shift_left(zd, zd, 0, (nx<<1)-3, 0, 1);
    1329              : 
    1330              :   /* add the squares */
    1331    225513504 :   xd = x + nx; zd = z0 + lz;
    1332    225513504 :   p1 = *--xd;
    1333    225513504 :   zd--; *zd = mulll(p1,p1);
    1334    225513504 :   zd--; *zd = addll(hiremainder, *zd);
    1335   1575017376 :   while (xd > x)
    1336              :   {
    1337   1349503872 :     p1 = *--xd;
    1338   1349503872 :     zd--; *zd = addll(mulll(p1,p1)+ overflow, *zd);
    1339   1349503872 :     zd--; *zd = addll(hiremainder + overflow, *zd);
    1340              :   }
    1341              : 
    1342    225513504 : END:
    1343    225513504 :   if (*zd == 0) { zd++; lz--; } /* normalize */
    1344    225513504 :   *--zd = evalsigne(1) | evallgefint(lz);
    1345    225513504 :   *--zd = evaltyp(t_INT) | evallg(lz);
    1346    225513504 :   return gc_const((pari_sp)zd, zd);
    1347              : }
    1348              : 
    1349              : /********************************************************************/
    1350              : /**                                                                **/
    1351              : /**               INTEGER MULTIPLICATION (FFT)                     **/
    1352              : /**                                                                **/
    1353              : /********************************************************************/
    1354              : 
    1355              : /*
    1356              :  Compute parameters for FFT:
    1357              :    len: result length
    1358              :    k: FFT depth.
    1359              :    n: number of blocks (2^k)
    1360              :    bs: block size
    1361              :    mod: Modulus is M=2^(BIL*mod)+1
    1362              :    ord: order of 2 in Z/MZ.
    1363              :  We must have:
    1364              :    bs*n >= l
    1365              :    2^(BIL*mod) > nb*2^(2*BIL*bs)
    1366              :    2^k | 2*BIL*mod
    1367              : */
    1368              : static void
    1369        85563 : mulliifft_params(long len, long *k, long *mod, long *bs, long *n, ulong *ord)
    1370              : {
    1371              :   long r;
    1372        85563 :   *k = expu((3*len)>>2)-3;
    1373              :   do {
    1374        85566 :     (*k)--;
    1375        85566 :     r  = *k-(TWOPOTBITS_IN_LONG+2);
    1376        85566 :     *n = 1L<<*k;
    1377        85566 :     *bs = (len+*n-1)>>*k;
    1378        85566 :     *mod= 2**bs+1;
    1379        85566 :     if (r>0)
    1380         5202 :       *mod=((*mod+(1L<<r)-1)>>r)<<r;
    1381        85566 :   } while(*mod>=3**bs);
    1382        85563 :   *ord= 4**mod*BITS_IN_LONG;
    1383        85563 : }
    1384              : 
    1385              : /* Zf_: arithmetic in ring Z/MZ where M= 2^(BITS_IN_LONG*mod)+1
    1386              :  * for some mod.
    1387              :  * Do not garbage collect.
    1388              :  */
    1389              : 
    1390              : static GEN
    1391    188282304 : Zf_add(GEN a, GEN b, GEN M)
    1392              : {
    1393    188282304 :   GEN y, z = addii(a,b);
    1394    188282304 :   long mod = lgefint(M)-3;
    1395    188282304 :   long l = NLIMBS(z);
    1396    188282304 :   if (l<=mod) return z;
    1397     72982293 :   y = subiu(z, 1);
    1398     72982293 :   if (NLIMBS(y)<=mod) return z;
    1399     72982293 :   return int_normalize(y,1);
    1400              : }
    1401              : 
    1402              : static GEN
    1403    191720967 : Zf_sub(GEN a, GEN b, GEN M)
    1404              : {
    1405    191720967 :   GEN z = subii(a,b);
    1406    191720967 :   return signe(z)>=0? z: addii(M,z);
    1407              : }
    1408              : 
    1409              : /* destroy z */
    1410              : static GEN
    1411    400764429 : Zf_red_destroy(GEN z, GEN M)
    1412              : {
    1413    400764429 :   long mod = lgefint(M)-3;
    1414    400764429 :   long l = NLIMBS(z);
    1415              :   GEN y;
    1416    400764429 :   if (l<=mod) return z;
    1417    177894792 :   y = shifti(z, -mod*BITS_IN_LONG);
    1418    177894792 :   z = int_normalize(z, NLIMBS(y));
    1419    177894792 :   y = Zf_red_destroy(y, M);
    1420    177894792 :   z = subii(z, y);
    1421    177894792 :   if (signe(z)<0) z = addii(z, M);
    1422    177894792 :   return z;
    1423              : }
    1424              : 
    1425              : INLINE GEN
    1426    207026949 : Zf_shift(GEN a, ulong s, GEN M) { return Zf_red_destroy(shifti(a, s), M); }
    1427              : 
    1428              : /*
    1429              :  Multiply by sqrt(2)^s
    1430              :  We use the formula sqrt(2)=z_8*(1-z_4)) && z_8=2^(ord/16) [2^(ord/4)+1]
    1431              : */
    1432              : 
    1433              : static GEN
    1434    188282304 : Zf_mulsqrt2(GEN a, ulong s, ulong ord, GEN M)
    1435              : {
    1436    188282304 :   ulong hord = ord>>1;
    1437    188282304 :   if (!signe(a)) return gen_0;
    1438    184306935 :   if (odd(s)) /* Multiply by 2^(s/2) */
    1439              :   {
    1440      3438663 :     GEN az8  = Zf_shift(a,   ord>>4, M);
    1441      3438663 :     GEN az83 = Zf_shift(az8, ord>>3, M);
    1442      3438663 :     a = Zf_sub(az8, az83, M);
    1443      3438663 :     s--;
    1444              :   }
    1445    184306935 :   if (s < hord)
    1446    136911207 :     return Zf_shift(a, s>>1, M);
    1447              :   else
    1448     47395728 :     return subii(M,Zf_shift(a, (s-hord)>>1, M));
    1449              : }
    1450              : 
    1451              : INLINE GEN
    1452       456960 : Zf_sqr(GEN a, GEN M) { return Zf_red_destroy(sqri(a), M); }
    1453              : 
    1454              : INLINE GEN
    1455     15385728 : Zf_mul(GEN a, GEN b, GEN M) { return Zf_red_destroy(mulii(a,b), M); }
    1456              : 
    1457              : /* In place, bit reversing FFT */
    1458              : static void
    1459     31058994 : muliifft_dit(ulong o, ulong ord, GEN M, GEN FFT, long d, long step)
    1460              : {
    1461     31058994 :   pari_sp av = avma;
    1462              :   long i;
    1463     31058994 :   ulong j, no = (o<<1)%ord;
    1464     31058994 :   long hstep=step>>1;
    1465    155911986 :   for (i = d+1, j = 0; i <= d+hstep; ++i, j =(j+o)%ord)
    1466              :   {
    1467    124852992 :     GEN a = Zf_add(gel(FFT,i), gel(FFT,i+hstep), M);
    1468    124852992 :     GEN b = Zf_mulsqrt2(Zf_sub(gel(FFT,i), gel(FFT,i+hstep), M), j, ord, M);
    1469    124852992 :     affii(a,gel(FFT,i));
    1470    124852992 :     affii(b,gel(FFT,i+hstep));
    1471    124852992 :     set_avma(av);
    1472              :   }
    1473     31058994 :   if (hstep>1)
    1474              :   {
    1475     15444786 :     muliifft_dit(no, ord, M, FFT, d, hstep);
    1476     15444786 :     muliifft_dit(no, ord, M, FFT, d+hstep, hstep);
    1477              :   }
    1478     31058994 : }
    1479              : 
    1480              : /* In place, bit reversed FFT, inverse of muliifft_dit */
    1481              : static void
    1482     15757125 : muliifft_dis(ulong o, ulong ord, GEN M, GEN FFT, long d, long step)
    1483              : {
    1484     15757125 :   pari_sp av = avma;
    1485              :   long i;
    1486     15757125 :   ulong j, no = (o<<1)%ord;
    1487     15757125 :   long hstep=step>>1;
    1488     15757125 :   if (hstep>1)
    1489              :   {
    1490      7835781 :     muliifft_dis(no, ord, M, FFT, d, hstep);
    1491      7835781 :     muliifft_dis(no, ord, M, FFT, d+hstep, hstep);
    1492              :   }
    1493     79186437 :   for (i = d+1, j = 0; i <= d+hstep; ++i, j =(j+o)%ord)
    1494              :   {
    1495     63429312 :     GEN z = Zf_mulsqrt2(gel(FFT,i+hstep), j, ord, M);
    1496     63429312 :     GEN a = Zf_add(gel(FFT,i), z, M);
    1497     63429312 :     GEN b = Zf_sub(gel(FFT,i), z, M);
    1498     63429312 :     affii(a,gel(FFT,i));
    1499     63429312 :     affii(b,gel(FFT,i+hstep));
    1500     63429312 :     set_avma(av);
    1501              :   }
    1502     15757125 : }
    1503              : 
    1504              : static GEN
    1505       169422 : muliifft_spliti(GEN a, long na, long bs, long n, long mod)
    1506              : {
    1507       169422 :   GEN ap = a+na-1;
    1508       169422 :   GEN c  = cgetg(n+1, t_VEC);
    1509              :   long i,j;
    1510     31397838 :   for(i=1;i<=n;i++)
    1511              :   {
    1512     31228416 :     GEN z = cgeti(mod+3);
    1513     31228416 :     if (na)
    1514              :     {
    1515     15376551 :       long m = minss(bs, na), v=0;
    1516     15376551 :       GEN zp, aa=ap-m+1;
    1517     83133975 :       while (!*aa && v<m) {aa++; v++;}
    1518     15376551 :       zp = z+m-v+1;
    1519    383149560 :       for (j=v; j < m; j++)
    1520    367773009 :         *zp-- = *ap--;
    1521     15376551 :       ap -= v; na -= m;
    1522     15376551 :       z[1] = evalsigne(m!=v) | evallgefint(m-v+2);
    1523              :     } else
    1524     15851865 :       z[1] = evalsigne(0) | evallgefint(2);
    1525     31228416 :     gel(c, i) = z;
    1526              :   }
    1527       169422 :   return c;
    1528              : }
    1529              : 
    1530              : static GEN
    1531        85563 : muliifft_unspliti(GEN V, long bs, long len)
    1532              : {
    1533        85563 :   long s, i, j, l = lg(V);
    1534        85563 :   GEN a = cgeti(len);
    1535        85563 :   a[1] = evalsigne(1)|evallgefint(len);
    1536    442546890 :   for(i=2;i<len;i++)
    1537    442461327 :     a[i] = 0;
    1538     15928251 :   for(i=1, s=0; i<l; i++, s+=bs)
    1539              :   {
    1540     15842688 :     GEN  u = gel(V,i);
    1541     15842688 :     if (signe(u))
    1542              :     {
    1543     15268533 :       GEN ap = int_W(a,s);
    1544     15268533 :       GEN up = int_LSW(u);
    1545     15268533 :       long lu = NLIMBS(u);
    1546              :       LOCAL_OVERFLOW;
    1547     15268533 :       *ap = addll(*ap, *up--); ap--;
    1548    865804125 :       for (j=1; j<lu; j++)
    1549    850535592 :        { *ap = addllx(*ap, *up--); ap--; }
    1550     15271098 :       while (overflow)
    1551         2565 :        { *ap = addll(*ap, 1); ap--; }
    1552              :     }
    1553              :   }
    1554        85563 :   return int_normalize(a,0);
    1555              : }
    1556              : 
    1557              : static GEN
    1558         1704 : sqrispec_fft(GEN a, long na)
    1559              : {
    1560         1704 :   pari_sp av, ltop = avma;
    1561         1704 :   long len = 2*na;
    1562              :   long k, mod, bs, n;
    1563              :   GEN  FFT, M;
    1564              :   long i;
    1565              :   ulong o, ord;
    1566              : 
    1567         1704 :   mulliifft_params(len,&k,&mod,&bs,&n,&ord);
    1568         1704 :   o = ord>>k;
    1569         1704 :   M = int2n(mod*BITS_IN_LONG);
    1570         1704 :   M[2+mod] = 1;
    1571         1704 :   FFT = muliifft_spliti(a, na, bs, n, mod);
    1572         1704 :   muliifft_dit(o, ord, M, FFT, 0, n);
    1573         1704 :   av = avma;
    1574       458664 :   for(i=1; i<=n; i++)
    1575              :   {
    1576       456960 :     affii(Zf_sqr(gel(FFT,i), M), gel(FFT,i));
    1577       456960 :     set_avma(av);
    1578              :   }
    1579         1704 :   muliifft_dis(ord-o, ord, M, FFT, 0, n);
    1580       458664 :   for(i=1; i<=n; i++)
    1581              :   {
    1582       456960 :     affii(Zf_shift(gel(FFT,i), (ord>>1)-k, M), gel(FFT,i));
    1583       456960 :     set_avma(av);
    1584              :   }
    1585         1704 :   return gc_INT(ltop, muliifft_unspliti(FFT,bs,2+len));
    1586              : }
    1587              : 
    1588              : static GEN
    1589        83859 : muliispec_fft(GEN a, GEN b, long na, long nb)
    1590              : {
    1591        83859 :   pari_sp av, av2, ltop = avma;
    1592        83859 :   long len = na+nb;
    1593              :   long k, mod, bs, n;
    1594              :   GEN FFT, FFTb, M;
    1595              :   long i;
    1596              :   ulong o, ord;
    1597              : 
    1598        83859 :   mulliifft_params(len,&k,&mod,&bs,&n,&ord);
    1599        83859 :   o = ord>>k;
    1600        83859 :   M = int2n(mod*BITS_IN_LONG);
    1601        83859 :   M[2+mod] = 1;
    1602        83859 :   FFT = muliifft_spliti(a, na, bs, n, mod);
    1603        83859 :   av=avma;
    1604        83859 :   muliifft_dit(o, ord, M, FFT, 0, n);
    1605        83859 :   FFTb = muliifft_spliti(b, nb, bs, n, mod);
    1606        83859 :   av2 = avma;
    1607        83859 :   muliifft_dit(o, ord, M, FFTb, 0, n);
    1608     15469587 :   for(i=1; i<=n; i++)
    1609              :   {
    1610     15385728 :     affii(Zf_mul(gel(FFT,i), gel(FFTb,i), M), gel(FFT,i));
    1611     15385728 :     set_avma(av2);
    1612              :   }
    1613        83859 :   set_avma(av);
    1614        83859 :   muliifft_dis(ord-o, ord, M, FFT, 0, n);
    1615     15469587 :   for(i=1; i<=n; i++)
    1616              :   {
    1617     15385728 :     affii(Zf_shift(gel(FFT,i),(ord>>1)-k,M), gel(FFT,i));
    1618     15385728 :     set_avma(av);
    1619              :   }
    1620        83859 :   return gc_INT(ltop, muliifft_unspliti(FFT,bs,2+len));
    1621              : }
    1622              : 
    1623              : /********************************************************************/
    1624              : /**                                                                **/
    1625              : /**               INTEGER MULTIPLICATION (KARATSUBA)               **/
    1626              : /**                                                                **/
    1627              : /********************************************************************/
    1628              : 
    1629              : /* return (x shifted left d words) + y. Assume d > 0, x > 0 and y >= 0 */
    1630              : static GEN
    1631    728095263 : addshiftw(GEN x, GEN y, long d)
    1632              : {
    1633    728095263 :   GEN z,z0,y0,yd, zd = (GEN)avma;
    1634    728095263 :   long a,lz,ly = lgefint(y);
    1635              : 
    1636    728095263 :   z0 = new_chunk(d);
    1637    728095263 :   a = ly-2; yd = y+ly;
    1638    728095263 :   if (a >= d)
    1639              :   {
    1640  13168964175 :     y0 = yd-d; while (yd > y0) *--zd = *--yd; /* copy last d words of y */
    1641    723428520 :     a -= d;
    1642    723428520 :     if (a)
    1643    482659926 :       z = addiispec(LIMBS(x), LIMBS(y), NLIMBS(x), a);
    1644              :     else
    1645    240768594 :       z = icopy(x);
    1646              :   }
    1647              :   else
    1648              :   {
    1649     16945635 :     y0 = yd-a; while (yd > y0) *--zd = *--yd; /* copy last a words of y */
    1650     70496934 :     while (zd > z0) *--zd = 0;    /* complete with 0s */
    1651      4666743 :     z = icopy(x);
    1652              :   }
    1653    728095263 :   lz = lgefint(z)+d;
    1654    728095263 :   z[1] = evalsigne(1) | evallgefint(lz);
    1655    728095263 :   z[0] = evaltyp(t_INT) | evallg(lz); return z;
    1656              : }
    1657              : 
    1658              : /* Fast product (Karatsuba) of integers. a and b are "special" GENs
    1659              :  * c,c0,c1,c2 are genuine GENs.
    1660              :  */
    1661              : GEN
    1662   5503593867 : muliispec(GEN a, GEN b, long na, long nb)
    1663              : {
    1664              :   GEN a0,c,c0;
    1665              :   long n0, n0a, i;
    1666              :   pari_sp av;
    1667              : 
    1668   5503593867 :   if (na < nb) swapspec(a,b, na,nb);
    1669   5503593867 :   if (nb < MULII_KARATSUBA_LIMIT) return muliispec_basecase(a,b,na,nb);
    1670    234574506 :   if (nb >= MULII_FFT_LIMIT)      return muliispec_fft(a,b,na,nb);
    1671    234490647 :   i=(na>>1); n0=na-i; na=i;
    1672    234490647 :   av=avma; a0=a+na; n0a=n0;
    1673    353011251 :   while (n0a && !*a0) { a0++; n0a--; }
    1674              : 
    1675    234490647 :   if (n0a && nb > n0)
    1676    230923791 :   { /* nb <= na <= n0 */
    1677              :     GEN b0,c1,c2;
    1678              :     long n0b;
    1679              : 
    1680    230923791 :     nb -= n0;
    1681    230923791 :     c = muliispec(a,b,na,nb);
    1682    230923791 :     b0 = b+nb; n0b = n0;
    1683    333486438 :     while (n0b && !*b0) { b0++; n0b--; }
    1684    230923791 :     if (n0b)
    1685              :     {
    1686    230147175 :       c0 = muliispec(a0,b0, n0a,n0b);
    1687              : 
    1688    230147175 :       c2 = addiispec(a0,a, n0a,na);
    1689    230147175 :       c1 = addiispec(b0,b, n0b,nb);
    1690    230147175 :       c1 = muliispec(LIMBS(c1),LIMBS(c2), NLIMBS(c1),NLIMBS(c2));
    1691    230147175 :       c2 = addiispec(LIMBS(c0),LIMBS(c),  NLIMBS(c0),NLIMBS(c));
    1692              : 
    1693    230147175 :       c1 = subiispec(LIMBS(c1),LIMBS(c2), NLIMBS(c1),NLIMBS(c2));
    1694              :     }
    1695              :     else
    1696              :     {
    1697       776616 :       c0 = gen_0;
    1698       776616 :       c1 = muliispec(a0,b, n0a,nb);
    1699              :     }
    1700    230923791 :     c = addshiftw(c,c1, n0);
    1701              :   }
    1702              :   else
    1703              :   {
    1704      3566856 :     c = muliispec(a,b,na,nb);
    1705      3566856 :     c0 = muliispec(a0,b,n0a,nb);
    1706              :   }
    1707    234490647 :   return gc_INT(av, addshiftw(c,c0, n0));
    1708              : }
    1709              : GEN
    1710       166722 : muluui(ulong x, ulong y, GEN z)
    1711              : {
    1712       166722 :   long t, s = signe(z);
    1713              :   GEN r;
    1714              :   LOCAL_HIREMAINDER;
    1715              : 
    1716       166722 :   if (!x || !y || !signe(z)) return gen_0;
    1717       166425 :   t = mulll(x,y);
    1718       166425 :   if (!hiremainder)
    1719       166425 :     r = muluispec(t, z+2, lgefint(z)-2);
    1720              :   else
    1721              :   {
    1722              :     long tmp[2];
    1723            0 :     tmp[0] = hiremainder;
    1724            0 :     tmp[1] = t;
    1725            0 :     r = muliispec(z+2,tmp,lgefint(z)-2,2);
    1726              :   }
    1727       166425 :   setsigne(r,s); return r;
    1728              : }
    1729              : 
    1730              : #define sqrispec_mirror sqrispec
    1731              : #define muliispec_mirror muliispec
    1732              : 
    1733              : /* x % (2^n), assuming n >= 0 */
    1734              : GEN
    1735     20443817 : remi2n(GEN x, long n)
    1736              : {
    1737     20443817 :   long hi,l,k,lx,ly, sx = signe(x);
    1738              :   GEN z, xd, zd;
    1739              : 
    1740     20443817 :   if (!sx || !n) return gen_0;
    1741              : 
    1742     20418821 :   k = dvmdsBIL(n, &l);
    1743     20418821 :   lx = lgefint(x);
    1744     20418821 :   if (lx < k+3) return icopy(x);
    1745              : 
    1746     20002439 :   xd = x + (lx-k-1);
    1747              :   /* x = |_|...|#|1|...|k| : copy the last l bits of # and the last k words
    1748              :    *            ^--- initial xd  */
    1749     20002439 :   hi = ((ulong)*xd) & ((1UL<<l)-1); /* last l bits of # = top bits of result */
    1750     20002439 :   if (!hi)
    1751              :   { /* strip leading zeroes from result */
    1752      1483542 :     xd++; while (k && !*xd) { k--; xd++; }
    1753      1446606 :     if (!k) return gen_0;
    1754       684501 :     ly = k+2; xd--;
    1755              :   }
    1756              :   else
    1757     18555833 :     ly = k+3;
    1758              : 
    1759     19240334 :   zd = z = cgeti(ly);
    1760     19240334 :   *++zd = evalsigne(sx) | evallgefint(ly);
    1761     19240334 :   if (hi) *++zd = hi;
    1762    109914749 :   for ( ;k; k--) *++zd = *++xd;
    1763     19240334 :   return z;
    1764              : }
    1765              : 
    1766              : GEN
    1767    953515977 : sqrispec(GEN a, long na)
    1768              : {
    1769              :   GEN a0,c;
    1770              :   long n0, n0a, i;
    1771              :   pari_sp av;
    1772              : 
    1773    953515977 :   if (na < SQRI_KARATSUBA_LIMIT) return sqrispec_basecase(a,na);
    1774     10011501 :   if (na >= SQRI_FFT_LIMIT) return sqrispec_fft(a,na);
    1775     10009797 :   i=(na>>1); n0=na-i; na=i;
    1776     10009797 :   av=avma; a0=a+na; n0a=n0;
    1777     15041871 :   while (n0a && !*a0) { a0++; n0a--; }
    1778     10009797 :   c = sqrispec(a,na);
    1779     10009797 :   if (n0a)
    1780              :   {
    1781     10001046 :     GEN t, c1, c0 = sqrispec(a0,n0a);
    1782              : #if 0
    1783              :     c1 = shifti(muliispec(a0,a, n0a,na),1);
    1784              : #else /* faster */
    1785     10001046 :     t = addiispec(a0,a,n0a,na);
    1786     10001046 :     t = sqrispec(LIMBS(t),NLIMBS(t));
    1787     10001046 :     c1= addiispec(LIMBS(c0),LIMBS(c), NLIMBS(c0), NLIMBS(c));
    1788     10001046 :     c1= subiispec(LIMBS(t),LIMBS(c1), NLIMBS(t), NLIMBS(c1));
    1789              : #endif
    1790     10001046 :     c = addshiftw(c,c1, n0);
    1791     10001046 :     c = addshiftw(c,c0, n0);
    1792              :   }
    1793              :   else
    1794         8751 :     c = addshiftw(c,gen_0,n0<<1);
    1795     10009797 :   return gc_INT(av, c);
    1796              : }
    1797              : 
    1798              : /********************************************************************/
    1799              : /**                                                                **/
    1800              : /**                    KARATSUBA SQUARE ROOT                       **/
    1801              : /**      adapted from Paul Zimmermann's implementation of          **/
    1802              : /**      his algorithm in GMP (mpn_sqrtrem)                        **/
    1803              : /**                                                                **/
    1804              : /********************************************************************/
    1805              : 
    1806              : /* Square roots table */
    1807              : static const unsigned char approx_tab[192] = {
    1808              :   128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,
    1809              :   143,144,144,145,146,147,148,149,150,150,151,152,153,154,155,155,
    1810              :   156,157,158,159,160,160,161,162,163,163,164,165,166,167,167,168,
    1811              :   169,170,170,171,172,173,173,174,175,176,176,177,178,178,179,180,
    1812              :   181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,191,
    1813              :   192,192,193,193,194,195,195,196,197,197,198,199,199,200,201,201,
    1814              :   202,203,203,204,204,205,206,206,207,208,208,209,209,210,211,211,
    1815              :   212,212,213,214,214,215,215,216,217,217,218,218,219,219,220,221,
    1816              :   221,222,222,223,224,224,225,225,226,226,227,227,228,229,229,230,
    1817              :   230,231,231,232,232,233,234,234,235,235,236,236,237,237,238,238,
    1818              :   239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,
    1819              :   247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255
    1820              : };
    1821              : 
    1822              : /* N[0], assume N[0] >= 2^(BIL-2).
    1823              :  * Return r,s such that s^2 + r = N, 0 <= r <= 2s */
    1824              : static void
    1825     98723220 : p_sqrtu1(ulong *N, ulong *ps, ulong *pr)
    1826              : {
    1827     98723220 :   ulong prec, r, s, q, u, n0 = N[0];
    1828              : 
    1829     98723220 :   q = n0 >> (BITS_IN_LONG - 8);
    1830              :   /* 2^6 = 64 <= q < 256 = 2^8 */
    1831     98723220 :   s = approx_tab[q - 64];                                /* 128 <= s < 255 */
    1832     98723220 :   r = (n0 >> (BITS_IN_LONG - 16)) - s * s;                /* r <= 2*s */
    1833     98723220 :   if (r > (s << 1)) { r -= (s << 1) | 1; s++; }
    1834              : 
    1835              :   /* 8-bit approximation from the high 8-bits of N[0] */
    1836     98723220 :   prec = 8;
    1837     98723220 :   n0 <<= 2 * prec;
    1838    296169660 :   while (2 * prec < BITS_IN_LONG)
    1839              :   { /* invariant: s has prec bits, and r <= 2*s */
    1840    197446440 :     r = (r << prec) + (n0 >> (BITS_IN_LONG - prec));
    1841    197446440 :     n0 <<= prec;
    1842    197446440 :     u = 2 * s;
    1843    197446440 :     q = r / u; u = r - q * u;
    1844    197446440 :     s = (s << prec) + q;
    1845    197446440 :     u = (u << prec) + (n0 >> (BITS_IN_LONG - prec));
    1846    197446440 :     q = q * q;
    1847    197446440 :     r = u - q;
    1848    197446440 :     if (u < q) { s--; r += (s << 1) | 1; }
    1849    197446440 :     n0 <<= prec;
    1850    197446440 :     prec = 2 * prec;
    1851              :   }
    1852     98723220 :   *ps = s;
    1853     98723220 :   *pr = r;
    1854     98723220 : }
    1855              : 
    1856              : /* N[0..1], assume N[0] >= 2^(BIL-2).
    1857              :  * Return 1 if remainder overflows, 0 otherwise */
    1858              : static int
    1859     96009198 : p_sqrtu2(ulong *N, ulong *ps, ulong *pr)
    1860              : {
    1861     96009198 :   ulong cc, qhl, r, s, q, u, n1 = N[1];
    1862              :   LOCAL_OVERFLOW;
    1863              : 
    1864     96009198 :   p_sqrtu1(N, &s, &r); /* r <= 2s */
    1865    143649876 :   qhl = 0; while (r >= s) { qhl++; r -= s; }
    1866              :   /* now r < s < 2^(BIL/2) */
    1867     96009198 :   r = (r << BITS_IN_HALFULONG) | (n1 >> BITS_IN_HALFULONG);
    1868     96009198 :   u = s << 1;
    1869     96009198 :   q = r / u; u = r - q * u;
    1870     96009198 :   q += (qhl & 1) << (BITS_IN_HALFULONG - 1);
    1871     96009198 :   qhl >>= 1;
    1872              :   /* (initial r)<<(BIL/2) + n1>>(BIL/2) = (qhl<<(BIL/2) + q) * 2s + u */
    1873     96009198 :   s = ((s + qhl) << BITS_IN_HALFULONG) + q;
    1874     96009198 :   cc = u >> BITS_IN_HALFULONG;
    1875     96009198 :   r = (u << BITS_IN_HALFULONG) | (n1 & LOWMASK);
    1876     96009198 :   r = subll(r, q * q);
    1877     96009198 :   cc -= overflow + qhl;
    1878              :   /* now subtract 2*q*2^(BIL/2) + 2^BIL if qhl is set */
    1879     96009198 :   if ((long)cc < 0)
    1880              :   {
    1881     24467361 :     if (s) {
    1882     24402066 :       r = addll(r, s);
    1883     24402066 :       cc += overflow;
    1884     24402066 :       s--;
    1885              :     } else {
    1886        65295 :       cc++;
    1887        65295 :       s = ~0UL;
    1888              :     }
    1889     24467361 :     r = addll(r, s);
    1890     24467361 :     cc += overflow;
    1891              :   }
    1892     96009198 :   *ps = s;
    1893     96009198 :   *pr = r; return cc;
    1894              : }
    1895              : 
    1896              : static void
    1897     94950939 : xmpn_zero(GEN x, long n)
    1898              : {
    1899    719041290 :   while (--n >= 0) x[n]=0;
    1900     94950939 : }
    1901              : static void
    1902   1108173174 : xmpn_copy(GEN z, GEN x, long n)
    1903              : {
    1904   1108173174 :   long k = n;
    1905   4338395741 :   while (--k >= 0) z[k] = x[k];
    1906   1108173174 : }
    1907              : /* a[0..la-1] * 2^(lb BIL) | b[0..lb-1] */
    1908              : static GEN
    1909    485339964 : catii(GEN a, long la, GEN b, long lb)
    1910              : {
    1911    485339964 :   long l = la + lb + 2;
    1912    485339964 :   GEN z = cgetipos(l);
    1913    485339964 :   xmpn_copy(LIMBS(z), a, la);
    1914    485339964 :   xmpn_copy(LIMBS(z) + la, b, lb);
    1915    485339964 :   return int_normalize(z, 0);
    1916              : }
    1917              : 
    1918              : /* sqrt n[0..1], assume n normalized */
    1919              : static GEN
    1920     95737992 : sqrtispec2(GEN n, GEN *pr)
    1921              : {
    1922              :   ulong s, r;
    1923     95737992 :   int hi = p_sqrtu2((ulong*)n, &s, &r);
    1924     95737992 :   GEN S = utoi(s);
    1925     95737992 :   *pr = hi? uutoi(1,r): utoi(r);
    1926     95737992 :   return S;
    1927              : }
    1928              : 
    1929              : /* sqrt n[0], _dont_ assume n normalized */
    1930              : static GEN
    1931      2714022 : sqrtispec1_sh(GEN n, GEN *pr)
    1932              : {
    1933              :   GEN S;
    1934      2714022 :   ulong r, s, u0 = uel(n,0);
    1935      2714022 :   int sh = bfffo(u0) & ~1UL;
    1936      2714022 :   if (sh) u0 <<= sh;
    1937      2714022 :   p_sqrtu1(&u0, &s, &r);
    1938              :   /* s^2 + r = u0, s < 2^(BIL/2). Rescale back:
    1939              :    * 2^(2k) n = S^2 + R
    1940              :    * so 2^(2k) n = (S - s0)^2 + (2*S*s0 - s0^2 + R), s0 = S mod 2^k. */
    1941      2714022 :   if (sh) {
    1942      1622748 :     int k = sh >> 1;
    1943      1622748 :     ulong s0 = s & ((1L<<k) - 1);
    1944      1622748 :     r += s * (s0<<1);
    1945      1622748 :     s >>= k;
    1946      1622748 :     r >>= sh;
    1947              :   }
    1948      2714022 :   S = utoi(s);
    1949      2714022 :   if (pr) *pr = utoi(r);
    1950      2714022 :   return S;
    1951              : }
    1952              : 
    1953              : /* sqrt n[0..1], _dont_ assume n normalized */
    1954              : static GEN
    1955       271206 : sqrtispec2_sh(GEN n, GEN *pr)
    1956              : {
    1957              :   GEN S;
    1958       271206 :   ulong U[2], r, s, u0 = uel(n,0), u1 = uel(n,1);
    1959       271206 :   int hi, sh = bfffo(u0) & ~1UL;
    1960       271206 :   if (sh) {
    1961       243213 :     u0 = (u0 << sh) | (u1 >> (BITS_IN_LONG-sh));
    1962       243213 :     u1 <<= sh;
    1963              :   }
    1964       271206 :   U[0] = u0;
    1965       271206 :   U[1] = u1; hi = p_sqrtu2(U, &s, &r);
    1966              :   /* s^2 + R = u0|u1. Rescale back:
    1967              :    * 2^(2k) n = S^2 + R
    1968              :    * so 2^(2k) n = (S - s0)^2 + (2*S*s0 - s0^2 + R), s0 = S mod 2^k. */
    1969       271206 :   if (sh) {
    1970       243213 :     int k = sh >> 1;
    1971       243213 :     ulong s0 = s & ((1L<<k) - 1);
    1972              :     LOCAL_HIREMAINDER;
    1973              :     LOCAL_OVERFLOW;
    1974       243213 :     r = addll(r, mulll(s, (s0<<1)));
    1975       243213 :     if (overflow) hiremainder++;
    1976       243213 :     hiremainder += hi; /* + 0 or 1 */
    1977       243213 :     s >>= k;
    1978       243213 :     r = (r>>sh) | (hiremainder << (BITS_IN_LONG-sh));
    1979       243213 :     hi = (hiremainder & (1L<<sh));
    1980              :   }
    1981       271206 :   S = utoi(s);
    1982       271206 :   if (pr) *pr = hi? uutoi(1,r): utoi(r);
    1983       271206 :   return S;
    1984              : }
    1985              : 
    1986              : /* Let N = N[0..2n-1]. Return S (and set R) s.t S^2 + R = N, 0 <= R <= 2S
    1987              :  * Assume N normalized */
    1988              : static GEN
    1989    338407974 : sqrtispec(GEN N, long n, GEN *r)
    1990              : {
    1991              :   GEN S, R, q, z, u;
    1992              :   long l, h;
    1993              : 
    1994    338407974 :   if (n == 1) return sqrtispec2(N, r);
    1995    242669982 :   l = n >> 1;
    1996    242669982 :   h = n - l; /* N = a3(h) | a2(h) | a1(l) | a0(l words) */
    1997    242669982 :   S = sqrtispec(N, h, &R); /* S^2 + R = a3|a2 */
    1998              : 
    1999    242669982 :   z = catii(LIMBS(R), NLIMBS(R), N + 2*h, l); /* = R | a1(l) */
    2000    242669982 :   q = dvmdii(z, shifti(S,1), &u);
    2001    242669982 :   z = catii(LIMBS(u), NLIMBS(u), N + n + h, l); /* = u | a0(l) */
    2002              : 
    2003    242669982 :   S = addshiftw(S, q, l);
    2004    242669982 :   R = subii(z, sqri(q));
    2005    242669982 :   if (signe(R) < 0)
    2006              :   {
    2007     41391614 :     GEN S2 = shifti(S,1);
    2008     41391614 :     R = addis(subiispec(LIMBS(S2),LIMBS(R), NLIMBS(S2),NLIMBS(R)), -1);
    2009     41391614 :     S = addis(S, -1);
    2010              :   }
    2011    242669982 :   *r = R; return S;
    2012              : }
    2013              : 
    2014              : /* Return S (and set R) s.t S^2 + R = N, 0 <= R <= 2S.
    2015              :  * As for dvmdii, R is last on stack and guaranteed to be gen_0 in case the
    2016              :  * remainder is 0. R = NULL is allowed. */
    2017              : GEN
    2018      3772836 : sqrtremi(GEN N, GEN *r)
    2019              : {
    2020              :   pari_sp av;
    2021      3772836 :   GEN S, R, n = N+2;
    2022      3772836 :   long k, l2, ln = NLIMBS(N);
    2023              :   int sh;
    2024              : 
    2025      3772836 :   if (ln <= 2)
    2026              :   {
    2027      2985783 :     if (ln == 2) return sqrtispec2_sh(n, r);
    2028      2714577 :     if (ln == 1) return sqrtispec1_sh(n, r);
    2029          555 :     if (r) *r = gen_0;
    2030          555 :     return gen_0;
    2031              :   }
    2032       787053 :   av = avma;
    2033       787053 :   sh = bfffo(n[0]) >> 1;
    2034       787053 :   l2 = (ln + 1) >> 1;
    2035       787053 :   if (sh || (ln & 1)) { /* normalize n, so that n[0] >= 2^BIL / 4 */
    2036       786381 :     GEN s0, t = new_chunk(ln + 1);
    2037       786381 :     t[ln] = 0;
    2038       786381 :     if (sh)
    2039       784533 :       shift_left(t, n, 0,ln-1, 0, sh << 1);
    2040              :     else
    2041         1848 :       xmpn_copy(t, n, ln);
    2042       786381 :     S = sqrtispec(t, l2, &R); /* t normalized, 2 * l2 words */
    2043              :     /* Rescale back:
    2044              :      * 2^(2k) n = S^2 + R, k = sh + (ln & 1)*BIL/2
    2045              :      * so 2^(2k) n = (S - s0)^2 + (2*S*s0 - s0^2 + R), s0 = S mod 2^k. */
    2046       786381 :     k = sh + (ln & 1) * (BITS_IN_LONG/2);
    2047       786381 :     s0 = remi2n(S, k);
    2048       786381 :     R = addii(shifti(R,-1), mulii(s0, S));
    2049       786381 :     R = shifti(R, 1 - (k<<1));
    2050       786381 :     S = shifti(S, -k);
    2051              :   }
    2052              :   else
    2053          672 :     S = sqrtispec(n, l2, &R);
    2054              : 
    2055       787053 :   if (!r) { set_avma((pari_sp)S); return gc_INT(av, S); }
    2056       723495 :   *r = R; return gc_all(av, 2, &S, r);
    2057              : }
    2058              : 
    2059              : /* compute sqrt(|a|), assuming a != 0 */
    2060              : 
    2061              : #if 1
    2062              : GEN
    2063     94950939 : sqrtr_abs(GEN x)
    2064              : {
    2065     94950939 :   long l = lg(x) - 2, e = expo(x), er = e>>1;
    2066     94950939 :   GEN b, c, res = cgetg(2 + l, t_REAL);
    2067     94950939 :   res[1] = evalsigne(1) | evalexpo(er);
    2068     94950939 :   if (e&1) {
    2069     42540459 :     b = new_chunk(l << 1);
    2070     42540459 :     xmpn_copy(b, x+2, l);
    2071     42540459 :     xmpn_zero(b + l,l);
    2072     42540459 :     b = sqrtispec(b, l, &c);
    2073     42540459 :     xmpn_copy(res+2, b+2, l);
    2074     42540459 :     if (cmpii(c, b) > 0) roundr_up_ip(res, l+2);
    2075              :   } else {
    2076              :     ulong u;
    2077     52410480 :     b = new_chunk(2 + (l << 1));
    2078     52410480 :     shift_left(b+1, x+2, 0,l-1, 0, BITS_IN_LONG-1);
    2079     52410480 :     b[0] = uel(x,2)>>1;
    2080     52410480 :     xmpn_zero(b + l+1,l+1);
    2081     52410480 :     b = sqrtispec(b, l+1, &c);
    2082     52410480 :     xmpn_copy(res+2, b+2, l);
    2083     52410480 :     u = uel(b,l+2);
    2084     52410480 :     if ( u&HIGHBIT || (u == ~HIGHBIT && cmpii(c,b) > 0))
    2085     25835270 :       roundr_up_ip(res, l+2);
    2086              :   }
    2087     94950939 :   return gc_const((pari_sp)res, res);
    2088              : }
    2089              : 
    2090              : #else /* use t_REAL: currently much slower (quadratic division) */
    2091              : 
    2092              : #ifdef LONG_IS_64BIT
    2093              : /* 64 bits of b = sqrt(a[0] * 2^64 + a[1])  [ up to 1ulp ] */
    2094              : static ulong
    2095              : sqrtu2(ulong *a)
    2096              : {
    2097              :   ulong c, b = dblmantissa( sqrt((double)a[0]) );
    2098              :   LOCAL_HIREMAINDER;
    2099              :   LOCAL_OVERFLOW;
    2100              : 
    2101              :   /* > 32 correct bits, 1 Newton iteration to reach 64 */
    2102              :   if (b <= a[0]) return HIGHBIT | (a[0] >> 1);
    2103              :   hiremainder = a[0]; c = divll(a[1], b);
    2104              :   return (addll(c, b) >> 1) | HIGHBIT;
    2105              : }
    2106              : /* 64 bits of sqrt(a[0] * 2^63) */
    2107              : static ulong
    2108              : sqrtu2_1(ulong *a)
    2109              : {
    2110              :   ulong t[2];
    2111              :   t[0] = (a[0] >> 1);
    2112              :   t[1] = (a[0] << (BITS_IN_LONG-1)) | (a[1] >> 1);
    2113              :   return sqrtu2(t);
    2114              : }
    2115              : #else
    2116              : /* 32 bits of sqrt(a[0] * 2^32) */
    2117              : static ulong
    2118              : sqrtu2(ulong *a)   { return dblmantissa( sqrt((double)a[0]) ); }
    2119              : /* 32 bits of sqrt(a[0] * 2^31) */
    2120              : static ulong
    2121              : sqrtu2_1(ulong *a) { return dblmantissa( sqrt(2. * a[0]) ); }
    2122              : #endif
    2123              : 
    2124              : GEN
    2125              : sqrtr_abs(GEN x)
    2126              : {
    2127              :   long l1, i, l = lg(x), ex = expo(x);
    2128              :   GEN a, t, y = cgetg(l, t_REAL);
    2129              :   pari_sp av, av0 = avma;
    2130              : 
    2131              :   a = rtor(x, lg2prec(l+1));
    2132              :   t = cgetg(l+1, t_REAL);
    2133              :   if (ex & 1) { /* odd exponent */
    2134              :     a[1] = evalsigne(1) | _evalexpo(1);
    2135              :     t[2] = (long)sqrtu2((ulong*)a + 2);
    2136              :   } else { /* even exponent */
    2137              :     a[1] = evalsigne(1) | _evalexpo(0);
    2138              :     t[2] = (long)sqrtu2_1((ulong*)a + 2);
    2139              :   }
    2140              :   t[1] = evalsigne(1) | _evalexpo(0);
    2141              :   for (i = 3; i <= l; i++) t[i] = 0;
    2142              : 
    2143              :   /* |x| = 2^(ex/2) a, t ~ sqrt(a) */
    2144              :   l--; l1 = 1; av = avma;
    2145              :   while (l1 < l) { /* let t := (t + a/t)/2 */
    2146              :     l1 <<= 1; if (l1 > l) l1 = l;
    2147              :     setlg(a, l1 + 2);
    2148              :     setlg(t, l1 + 2);
    2149              :     affrr(addrr(t, divrr(a,t)), t); shiftr_inplace(t, -1);
    2150              :     set_avma(av);
    2151              :   }
    2152              :   affrr(t,y); shiftr_inplace(y, (ex>>1));
    2153              :   return gc_const(av0, y);
    2154              : }
    2155              : 
    2156              : #endif
    2157              : 
    2158              : /*******************************************************************
    2159              :  *                                                                 *
    2160              :  *                           Base Conversion                       *
    2161              :  *                                                                 *
    2162              :  *******************************************************************/
    2163              : 
    2164              : static void
    2165       751632 : convi_dac(GEN x, ulong l, ulong *res)
    2166              : {
    2167       751632 :   pari_sp ltop=avma;
    2168              :   ulong m;
    2169              :   GEN x1,x2;
    2170       751632 :   if (l==1) { *res=itou(x); return; }
    2171       356082 :   m=l>>1;
    2172       356082 :   x1=dvmdii(x,powuu(1000000000UL,m),&x2);
    2173       356082 :   convi_dac(x1,l-m,res+m);
    2174       356082 :   convi_dac(x2,m,res);
    2175       356082 :   set_avma(ltop);
    2176              : }
    2177              : 
    2178              : /* convert integer --> base 10^9 [not memory clean] */
    2179              : ulong *
    2180       323785 : convi(GEN x, long *l)
    2181              : {
    2182       323785 :   long lz, lx = lgefint(x);
    2183              :   ulong *z;
    2184       323785 :   if (lx == 3 && uel(x,2) < 1000000000UL) {
    2185       284317 :     z = (ulong*)new_chunk(1);
    2186       284317 :     *z = x[2];
    2187       284317 :     *l = 1; return z+1;
    2188              :   }
    2189        39468 :   lz = 1 + (long)bit_accuracy_mul(lx, LOG10_2/9);
    2190        39468 :   z = (ulong*)new_chunk(lz);
    2191        39468 :   convi_dac(x,(ulong)lz,z);
    2192        70815 :   while (z[lz-1]==0) lz--;
    2193        39468 :   *l=lz; return z+lz;
    2194              : }
    2195              : 
        

Generated by: LCOV version 2.0-1