/* $Id: mp.c,v 1.47 2001/09/28 17:16:45 xavier Exp $ Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /***********************************************************************/ /** **/ /** MULTIPRECISION KERNEL **/ /** **/ /***********************************************************************/ /* most of the routines in this file are commented out in 68k */ /* version (#ifdef __M68K__) since they are defined in mp.s */ #include "pari.h" /* NOTE: arguments of "spec" routines (muliispec, addiispec, etc.) aren't * GENs but pairs (long *a, long na) representing a list of digits (in basis * BITS_IN_LONG) : a[0], ..., a[na-1]. [ In ordre to facilitate splitting: no * need to reintroduce codewords ] * Use speci(a,na) to visualize the coresponding GEN. */ /* z2 := z1[imin..imax].f shifted left sh bits (feeding f from the right) */ #define shift_left2(z2,z1,imin,imax,f, sh,m) {\ register ulong _l,_k = ((ulong)f)>>m;\ GEN t1 = z1 + imax, t2 = z2 + imax, T = z1 + imin;\ while (t1 > T) {\ _l = *t1--;\ *t2-- = (_l<<(ulong)sh) | _k;\ _k = _l>>(ulong)m;\ }\ *t2 = (*t1<<(ulong)sh) | _k;\ } #define shift_left(z2,z1,imin,imax,f, sh) {\ register const ulong _m = BITS_IN_LONG - sh;\ shift_left2((z2),(z1),(imin),(imax),(f),(sh),(_m));\ } /* z2 := f.z1[imin..imax-1] shifted right sh bits (feeding f from the left) */ #define shift_right2(z2,z1,imin,imax,f, sh,m) {\ register GEN t1 = z1 + imin, t2 = z2 + imin, T = z1 + imax;\ register ulong _k,_l = *t1++;\ *t2++ = (_l>>(ulong)sh) | ((ulong)f<<(ulong)m);\ while (t1 < T) {\ _k = _l<<(ulong)m; _l = *t1++;\ *t2++ = (_l>>(ulong)sh) | _k;\ }\ } #define shift_right(z2,z1,imin,imax,f, sh) {\ register const ulong _m = BITS_IN_LONG - sh;\ shift_right2((z2),(z1),(imin),(imax),(f),(sh),(_m));\ } #define MASK(x) (((ulong)(x)) & (LGEFINTBITS | SIGNBITS)) int egalii(GEN x, GEN y) { long i; if (MASK(x[1]) != MASK(y[1])) return 0; i = lgefint(x)-1; while (i>1 && x[i]==y[i]) i--; return i==1; } #undef MASK #ifdef INLINE INLINE #endif GEN addsispec(long s, GEN x, long nx) { GEN xd, zd = (GEN)avma; long lz; LOCAL_OVERFLOW; lz = nx+3; (void)new_chunk(lz); xd = x + nx; *--zd = addll(*--xd, s); if (overflow) for(;;) { if (xd == x) { *--zd = 1; break; } /* enlarge z */ *--zd = ((ulong)*--xd) + 1; if (*zd) { lz--; break; } } else lz--; while (xd > x) *--zd = *--xd; *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(long)zd; return zd; } #define swapspec(x,y, nx,ny) {long _a=nx;GEN _z=x; nx=ny; ny=_a; x=y; y=_z;} #ifdef INLINE INLINE #endif GEN addiispec(GEN x, GEN y, long nx, long ny) { GEN xd,yd,zd; long lz; LOCAL_OVERFLOW; if (nx < ny) swapspec(x,y, nx,ny); if (ny == 1) return addsispec(*y,x,nx); zd = (GEN)avma; lz = nx+3; (void)new_chunk(lz); xd = x + nx; yd = y + ny; *--zd = addll(*--xd, *--yd); while (yd > y) *--zd = addllx(*--xd, *--yd); if (overflow) for(;;) { if (xd == x) { *--zd = 1; break; } /* enlarge z */ *--zd = ((ulong)*--xd) + 1; if (*zd) { lz--; break; } } else lz--; while (xd > x) *--zd = *--xd; *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(long)zd; return zd; } /* assume x >= y */ #ifdef INLINE INLINE #endif GEN subisspec(GEN x, long s, long nx) { GEN xd, zd = (GEN)avma; long lz; LOCAL_OVERFLOW; lz = nx+2; (void)new_chunk(lz); xd = x + nx; *--zd = subll(*--xd, s); if (overflow) for(;;) { *--zd = ((ulong)*--xd) - 1; if (*xd) break; } if (xd == x) while (*zd == 0) { zd++; lz--; } /* shorten z */ else do *--zd = *--xd; while (xd > x); *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(long)zd; return zd; } /* assume x > y */ #ifdef INLINE INLINE #endif GEN subiispec(GEN x, GEN y, long nx, long ny) { GEN xd,yd,zd; long lz; LOCAL_OVERFLOW; if (ny==1) return subisspec(x,*y,nx); zd = (GEN)avma; lz = nx+2; (void)new_chunk(lz); xd = x + nx; yd = y + ny; *--zd = subll(*--xd, *--yd); while (yd > y) *--zd = subllx(*--xd, *--yd); if (overflow) for(;;) { *--zd = ((ulong)*--xd) - 1; if (*xd) break; } if (xd == x) while (*zd == 0) { zd++; lz--; } /* shorten z */ else do *--zd = *--xd; while (xd > x); *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(long)zd; return zd; } #ifndef __M68K__ /* prototype of positive small ints */ static long pos_s[] = { evaltyp(t_INT) | m_evallg(3), evalsigne(1) | evallgefint(3), 0 }; /* prototype of negative small ints */ static long neg_s[] = { evaltyp(t_INT) | m_evallg(3), evalsigne(-1) | evallgefint(3), 0 }; void affir(GEN x, GEN y) { const long s=signe(x),ly=lg(y); long lx,sh,i; if (!s) { y[1] = evalexpo(-bit_accuracy(ly)); y[2] = 0; return; } lx=lgefint(x); sh=bfffo(x[2]); y[1] = evalsigne(s) | evalexpo(bit_accuracy(lx)-sh-1); if (sh) { if (lx>ly) { shift_left(y,x,2,ly-1, x[ly],sh); } else { for (i=lx; i=ly) for (i=2; i=ly) for (i=2; i 0) { GEN z = (GEN)avma; long d = n>>TWOPOTBITS_IN_LONG; ly = lx+d; y = new_chunk(ly); for ( ; d; d--) *--z = 0; m = n & (BITS_IN_LONG-1); if (!m) for (i=2; i> sh; if (i) { ly++; y = new_chunk(1); y[2] = i; } } } else { n = -n; ly = lx - (n>>TWOPOTBITS_IN_LONG); if (ly<3) return gzero; y = new_chunk(ly); m = n & (BITS_IN_LONG-1); if (!m) for (i=2; i>TWOPOTBITS_IN_LONG) + 3; m = e & (BITS_IN_LONG-1); if (d > lg(x)) err(precer, "mptrunc (precision loss in truncation)"); y=cgeti(d); y[1] = evalsigne(s) | evallgefint(d); if (++m == BITS_IN_LONG) for (i=2; i= 0) return mptrunc(x); if ((e=expo(x)) < 0) return stoi(-1); d = (e>>TWOPOTBITS_IN_LONG) + 3; m = e & (BITS_IN_LONG-1); lx=lg(x); if (d>lx) err(precer, "mpent (precision loss in trucation)"); y = new_chunk(d); if (++m == BITS_IN_LONG) { for (i=2; i=2; i--) { y[i]++; if (y[i]) goto END; } y=new_chunk(1); y[2]=1; d++; END: y[1] = evalsigne(-1) | evallgefint(d); y[0] = evaltyp(t_INT) | evallg(d); return y; } int cmpsi(long x, GEN y) { ulong p; if (!x) return -signe(y); if (x>0) { if (signe(y)<=0) return 1; if (lgefint(y)>3) return -1; p=y[2]; if (p == (ulong)x) return 0; return p < (ulong)x ? 1 : -1; } if (signe(y)>=0) return -1; if (lgefint(y)>3) return 1; p=y[2]; if (p == (ulong)-x) return 0; return p < (ulong)(-x) ? -1 : 1; } int cmpii(GEN x, GEN y) { const long sx = signe(x), sy = signe(y); long lx,ly,i; if (sxsy) return 1; if (!sx) return 0; lx=lgefint(x); ly=lgefint(y); if (lx>ly) return sx; if (lx (ulong)y[i]) ? sx : -sx; } int cmprr(GEN x, GEN y) { const long sx = signe(x), sy = signe(y); long ex,ey,lx,ly,lz,i; if (sxsy) return 1; if (!sx) return 0; ex=expo(x); ey=expo(y); if (ex>ey) return sx; if (ex (ulong)y[i]) ? sx : -sx; if (lx>=ly) { while (i0) { pos_s[2] = x; return addsi(y,pos_s); } neg_s[2] = -x; return addsi(y,neg_s); } GEN addsi(long x, GEN y) { long sx,sy,ly; GEN z; if (!x) return icopy(y); sy=signe(y); if (!sy) return stoi(x); if (x<0) { sx=-1; x=-x; } else sx=1; if (sx==sy) { z = addsispec(x,y+2, lgefint(y)-2); setsigne(z,sy); return z; } ly=lgefint(y); if (ly==3) { const long d = y[2] - x; if (!d) return gzero; z=cgeti(3); if (y[2] < 0 || d > 0) { z[1] = evalsigne(sy) | evallgefint(3); z[2] = d; } else { z[1] = evalsigne(-sy) | evallgefint(3); z[2] =-d; } return z; } z = subisspec(y+2,x, ly-2); setsigne(z,sy); return z; } GEN addii(GEN x, GEN y) { long sx = signe(x); long sy = signe(y); long lx,ly; GEN z; if (!sx) return sy? icopy(y): gzero; if (!sy) return icopy(x); lx=lgefint(x); ly=lgefint(y); if (sx==sy) z = addiispec(x+2,y+2,lx-2,ly-2); else { /* sx != sy */ long i = lx - ly; if (i==0) { i = absi_cmp(x,y); if (!i) return gzero; } if (i<0) { sx=sy; swapspec(x,y, lx,ly); } /* ensure |x| >= |y| */ z = subiispec(x+2,y+2,lx-2,ly-2); } setsigne(z,sx); return z; } GEN addsr(long x, GEN y) { if (!x) return rcopy(y); if (x>0) { pos_s[2]=x; return addir(pos_s,y); } neg_s[2] = -x; return addir(neg_s,y); } GEN addir(GEN x, GEN y) { long e,l,ly; GEN z; if (!signe(x)) return rcopy(y); e = expo(y)-expi(x); if (!signe(y)) { #if 0 if (e>0) err(adder3); #else /* design issue: make 0.0 "absorbing" */ if (e>0) return rcopy(y); #endif z = cgetr(3 + ((-e)>>TWOPOTBITS_IN_LONG)); affir(x,z); return z; } ly=lg(y); if (e>0) { l = ly - (e>>TWOPOTBITS_IN_LONG); if (l<3) return rcopy(y); } else l = ly + ((-e)>>TWOPOTBITS_IN_LONG)+1; z=cgetr(l); affir(x,z); y=addrr(z,y); z = y+l; ly = lg(y); while (ly--) z[ly] = y[ly]; avma=(long)z; return z; } GEN addrr(GEN x, GEN y) { long sx=signe(x),sy=signe(y),ex=expo(x),ey=expo(y); long e,m,flag,i,j,f2,lx,ly,lz; GEN z; LOCAL_OVERFLOW; e = ey-ex; if (!sy) { if (!sx) { if (e > 0) ex=ey; z=cgetr(3); z[1]=evalexpo(ex); z[2]=0; return z; } if (e > 0) { z=cgetr(3); z[1]=evalexpo(ey); z[2]=0; return z; } lz = 3 + ((-e)>>TWOPOTBITS_IN_LONG); lx = lg(x); if (lz>lx) lz=lx; z = cgetr(lz); while(--lz) z[lz]=x[lz]; return z; } if (!sx) { if (e < 0) { z=cgetr(3); z[1]=evalexpo(ex); z[2]=0; return z; } lz = 3 + (e>>TWOPOTBITS_IN_LONG); ly = lg(y); if (lz>ly) lz=ly; z = cgetr(lz); while (--lz) z[lz]=y[lz]; return z; } if (e < 0) { z=x; x=y; y=z; ey=ex; i=sx; sx=sy; sy=i; e=-e; } /* now ey >= ex */ lx=lg(x); ly=lg(y); if (e) { long d = e >> TWOPOTBITS_IN_LONG, l = ly-d; if (l > lx) { flag=0; lz=lx+d+1; } else if (l > 2) { flag=1; lz=ly; lx=l; } else return rcopy(y); m = e & (BITS_IN_LONG-1); } else { if (lx > ly) lx = ly; flag=2; lz=lx; m=0; } z = cgetr(lz); if (m) { /* shift right x m bits */ const ulong sh = BITS_IN_LONG-m; GEN p1 = x; x = new_chunk(lx+1); shift_right2(x,p1,2,lx, 0,m,sh); if (flag==0) { x[lx] = p1[lx-1] << sh; if (x[lx]) { flag = 3; lx++; } } } if (sx==sy) { /* addition */ i=lz-1; avma = (long)z; if (flag==0) { z[i] = y[i]; i--; } overflow=0; for (j=lx-1; j>=2; i--,j--) z[i] = addllx(x[j],y[i]); if (overflow) for (;;) { if (i==1) { shift_right(z,z, 2,lz, 1,1); ey=evalexpo(ey+1); z[1] = evalsigne(sx) | ey; return z; } z[i] = y[i]+1; if (z[i--]) break; } for (; i>=2; i--) z[i]=y[i]; z[1] = evalsigne(sx) | evalexpo(ey); return z; } /* subtraction */ if (e) f2 = 1; else { i=2; while (i (ulong)x[i]); } /* result is non-zero. f2 = (y > x) */ i=lz-1; if (f2) { if (flag==0) { z[i] = y[i]; i--; } j=lx-1; z[i] = subll(y[i],x[j]); i--; j--; for (; j>=2; i--,j--) z[i] = subllx(y[i],x[j]); if (overflow) for (;;) { z[i] = y[i]-1; if (y[i--]) break; } for (; i>=2; i--) z[i]=y[i]; sx = sy; } else { if (flag==0) { z[i] = -y[i]; i--; overflow=1; } else overflow=0; for (; i>=2; i--) z[i]=subllx(x[i],y[i]); } x = z+2; i=0; while (!x[i]) i++; lz -= i; z += i; m = bfffo(z[2]); e = evalexpo(ey - (m | (i< 0 */ #ifdef INLINE INLINE #endif GEN mulsispec(long x, GEN y, long ny) { GEN yd, z = (GEN)avma; long lz = ny+3; LOCAL_HIREMAINDER; (void)new_chunk(lz); yd = y + ny; *--z = mulll(x, *--yd); while (yd > y) *--z = addmul(x,*--yd); if (hiremainder) *--z = hiremainder; else lz--; *--z = evalsigne(1) | evallgefint(lz); *--z = evaltyp(t_INT) | evallg(lz); avma=(long)z; return z; } GEN mului(ulong x, GEN y) { long s = signe(y); GEN z; if (!s || !x) return gzero; z = mulsispec(x, y+2, lgefint(y)-2); setsigne(z,s); return z; } /* a + b*Y, assume Y >= 0, 0 <= a,b <= VERYBIGINT */ GEN addsmulsi(long a, long b, GEN Y) { GEN yd,y,z; long ny,lz; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; if (!signe(Y)) return stoi(a); y = Y+2; z = (GEN)avma; ny = lgefint(Y)-2; lz = ny+3; (void)new_chunk(lz); yd = y + ny; *--z = addll(a, mulll(b, *--yd)); if (overflow) hiremainder++; /* can't overflow */ while (yd > y) *--z = addmul(b,*--yd); if (hiremainder) *--z = hiremainder; else lz--; *--z = evalsigne(1) | evallgefint(lz); *--z = evaltyp(t_INT) | evallg(lz); avma=(long)z; return z; } #ifndef __M68K__ GEN mulsi(long x, GEN y) { long s = signe(y); GEN z; if (!s || !x) return gzero; if (x<0) { s = -s; x = -x; } z = mulsispec(x, y+2, lgefint(y)-2); setsigne(z,s); return z; } GEN mulsr(long x, GEN y) { long lx,i,s,garde,e,sh,m; GEN z; LOCAL_HIREMAINDER; if (!x) return gzero; s = signe(y); if (!s) { if (x<0) x = -x; e = y[1] + (BITS_IN_LONG-1)-bfffo(x); if (e & ~EXPOBITS) err(muler2); z=cgetr(3); z[1]=e; z[2]=0; return z; } if (x<0) { s = -s; x = -x; } if (x==1) { z=rcopy(y); setsigne(z,s); return z; } lx = lg(y); e = expo(y); z=cgetr(lx); y--; garde=mulll(x,y[lx]); for (i=lx-1; i>=3; i--) z[i]=addmul(x,y[i]); z[2]=hiremainder; sh = bfffo(hiremainder); m = BITS_IN_LONG-sh; if (sh) shift_left2(z,z, 2,lx-1, garde,sh,m); e = evalexpo(m+e); z[1] = evalsigne(s) | e; return z; } GEN mulrr(GEN x, GEN y) { long sx = signe(x), sy = signe(y); long i,j,ly,lz,lzz,e,flag,p1; ulong garde; GEN z, y1; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; e = evalexpo(expo(x)+expo(y)); if (!sx || !sy) { z=cgetr(3); z[1]=e; z[2]=0; return z; } if (sy<0) sx = -sx; lz=lg(x); ly=lg(y); if (lz>ly) { lz=ly; z=x; x=y; y=z; flag=1; } else flag = (lz!=ly); z=cgetr(lz); z[1] = evalsigne(sx) | e; if (lz==3) { if (flag) { (void)mulll(x[2],y[3]); garde = addmul(x[2],y[2]); } else garde = mulll(x[2],y[2]); if ((long)hiremainder<0) { z[2]=hiremainder; z[1]++; } else z[2]=(hiremainder<<1) | (garde>>(BITS_IN_LONG-1)); return z; } if (flag) { (void)mulll(x[2],y[lz]); garde = hiremainder; } else garde=0; lzz=lz-1; p1=x[lzz]; if (p1) { (void)mulll(p1,y[3]); garde = addll(addmul(p1,y[2]), garde); z[lzz] = overflow+hiremainder; } else z[lzz]=0; for (j=lz-2, y1=y-j; j>=3; j--) { p1 = x[j]; y1++; if (p1) { (void)mulll(p1,y1[lz+1]); garde = addll(addmul(p1,y1[lz]), garde); for (i=lzz; i>j; i--) { hiremainder += overflow; z[i] = addll(addmul(p1,y1[i]), z[i]); } z[j] = hiremainder+overflow; } else z[j]=0; } p1=x[2]; y1++; garde = addll(mulll(p1,y1[lz]), garde); for (i=lzz; i>2; i--) { hiremainder += overflow; z[i] = addll(addmul(p1,y1[i]), z[i]); } z[2] = hiremainder+overflow; if (z[2] < 0) z[1]++; else shift_left(z,z,2,lzz,garde, 1); return z; } GEN mulir(GEN x, GEN y) { long sx=signe(x),sy,lz,lzz,ey,e,p1,i,j; ulong garde; GEN z,y1; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; if (!sx) return gzero; if (!is_bigint(x)) return mulsr(itos(x),y); sy=signe(y); ey=expo(y); if (!sy) { e = evalexpo(expi(x)+ey); z=cgetr(3); z[1]=e; z[2]=0; return z; } if (sy<0) sx = -sx; lz=lg(y); z=cgetr(lz); y1=cgetr(lz+1); affir(x,y1); x=y; y=y1; e = evalexpo(expo(y)+ey); z[1] = evalsigne(sx) | e; if (lz==3) { (void)mulll(x[2],y[3]); garde=addmul(x[2],y[2]); if ((long)hiremainder < 0) { z[2]=hiremainder; z[1]++; } else z[2]=(hiremainder<<1) | (garde>>(BITS_IN_LONG-1)); avma=(long)z; return z; } (void)mulll(x[2],y[lz]); garde=hiremainder; lzz=lz-1; p1=x[lzz]; if (p1) { (void)mulll(p1,y[3]); garde=addll(addmul(p1,y[2]),garde); z[lzz] = overflow+hiremainder; } else z[lzz]=0; for (j=lz-2, y1=y-j; j>=3; j--) { p1=x[j]; y1++; if (p1) { (void)mulll(p1,y1[lz+1]); garde = addll(addmul(p1,y1[lz]), garde); for (i=lzz; i>j; i--) { hiremainder += overflow; z[i] = addll(addmul(p1,y1[i]), z[i]); } z[j] = hiremainder+overflow; } else z[j]=0; } p1=x[2]; y1++; garde = addll(mulll(p1,y1[lz]), garde); for (i=lzz; i>2; i--) { hiremainder += overflow; z[i] = addll(addmul(p1,y1[i]), z[i]); } z[2] = hiremainder+overflow; if (z[2] < 0) z[1]++; else shift_left(z,z,2,lzz,garde, 1); avma=(long)z; return z; } /* written by Bruno Haible following an idea of Robert Harley */ long vals(ulong z) { static char tab[64]={-1,0,1,12,2,6,-1,13,3,-1,7,-1,-1,-1,-1,14,10,4,-1,-1,8,-1,-1,25,-1,-1,-1,-1,-1,21,27,15,31,11,5,-1,-1,-1,-1,-1,9,-1,-1,24,-1,-1,20,26,30,-1,-1,-1,-1,23,-1,19,29,-1,22,18,28,17,16,-1}; #ifdef LONG_IS_64BIT long s; #endif if (!z) return -1; #ifdef LONG_IS_64BIT if (! (z&0xffffffff)) { s = 32; z >>=32; } else s = 0; #endif z |= ~z + 1; z += z << 4; z += z << 6; z ^= z << 16; /* or z -= z<<16 */ #ifdef LONG_IS_64BIT return s + tab[(z&0xffffffff)>>26]; #else return tab[z>>26]; #endif } GEN modss(long x, long y) { LOCAL_HIREMAINDER; if (!y) err(moder1); if (y<0) y=-y; hiremainder=0; divll(labs(x),y); if (!hiremainder) return gzero; return (x < 0) ? stoi(y-hiremainder) : stoi(hiremainder); } GEN resss(long x, long y) { LOCAL_HIREMAINDER; if (!y) err(reser1); hiremainder=0; divll(labs(x),labs(y)); return (x < 0) ? stoi(-((long)hiremainder)) : stoi(hiremainder); } GEN divsi(long x, GEN y) { long p1, s = signe(y); LOCAL_HIREMAINDER; if (!s) err(diver2); if (!x || lgefint(y)>3 || ((long)y[2])<0) { hiremainder=x; SAVE_HIREMAINDER; return gzero; } hiremainder=0; p1=divll(labs(x),y[2]); if (x<0) { hiremainder = -((long)hiremainder); p1 = -p1; } if (s<0) p1 = -p1; SAVE_HIREMAINDER; return stoi(p1); } #endif GEN modui(ulong x, GEN y) { LOCAL_HIREMAINDER; if (!signe(y)) err(diver2); if (!x || lgefint(y)>3) hiremainder=x; else { hiremainder=0; (void)divll(x,y[2]); } return utoi(hiremainder); } ulong umodiu(GEN y, ulong x) { long sy=signe(y),ly,i; LOCAL_HIREMAINDER; if (!x) err(diver4); if (!sy) return 0; ly = lgefint(y); if (x <= (ulong)y[2]) hiremainder=0; else { if (ly==3) return (sy > 0)? (ulong)y[2]: x - (ulong)y[2]; hiremainder=y[2]; ly--; y++; } for (i=2; i 0)? hiremainder: x - hiremainder; } GEN modiu(GEN y, ulong x) { return utoi(umodiu(y,x)); } #ifndef __M68K__ GEN modsi(long x, GEN y) { long s = signe(y); GEN p1; LOCAL_HIREMAINDER; if (!s) err(diver2); if (!x || lgefint(y)>3 || ((long)y[2])<0) hiremainder=x; else { hiremainder=0; (void)divll(labs(x),y[2]); if (x<0) hiremainder = -((long)hiremainder); } if (!hiremainder) return gzero; if (x>0) return stoi(hiremainder); if (s<0) { setsigne(y,1); p1=addsi(hiremainder,y); setsigne(y,-1); } else p1=addsi(hiremainder,y); return p1; } GEN divis(GEN y, long x) { long sy=signe(y),ly,s,i; GEN z; LOCAL_HIREMAINDER; if (!x) err(diver4); if (!sy) { hiremainder=0; SAVE_HIREMAINDER; return gzero; } if (x<0) { s = -sy; x = -x; } else s=sy; ly = lgefint(y); if ((ulong)x <= (ulong)y[2]) hiremainder=0; else { if (ly==3) { hiremainder=itos(y); SAVE_HIREMAINDER; return gzero; } hiremainder=y[2]; ly--; y++; } z = cgeti(ly); z[1] = evallgefint(ly) | evalsigne(s); for (i=2; i0? y[2]: -y[2]); lx=lg(x); z=cgetr(lx); av=avma; yr=cgetr(lx+1); affir(y,yr); affrr(divrr(x,yr),z); avma=av; return z; } void diviiz(GEN x, GEN y, GEN z) { long av=avma,lz; GEN xr,yr; if (typ(z)==t_INT) { affii(divii(x,y),z); avma=av; return; } lz=lg(z); xr=cgetr(lz); affir(x,xr); yr=cgetr(lz); affir(y,yr); affrr(divrr(xr,yr),z); avma=av; } void mpdivz(GEN x, GEN y, GEN z) { long av=avma; if (typ(z)==t_INT) { if (typ(x)==t_REAL || typ(y)==t_REAL) err(divzer1); affii(divii(x,y),z); avma=av; return; } if (typ(x)==t_INT) { GEN xr,yr; long lz; if (typ(y)==t_REAL) { affrr(divir(x,y),z); avma=av; return; } lz=lg(z); xr=cgetr(lz); affir(x,xr); yr=cgetr(lz); affir(y,yr); affrr(divrr(xr,yr),z); avma=av; return; } if (typ(y)==t_REAL) { affrr(divrr(x,y),z); avma=av; return; } affrr(divri(x,y),z); avma=av; } GEN divsr(long x, GEN y) { long av,ly; GEN p1,z; if (!signe(y)) err(diver3); if (!x) return gzero; ly=lg(y); z=cgetr(ly); av=avma; p1=cgetr(ly+1); affsr(x,p1); affrr(divrr(p1,y),z); avma=av; return z; } GEN modii(GEN x, GEN y) { switch(signe(x)) { case 0: return gzero; case 1: return resii(x,y); default: { long av = avma; (void)new_chunk(lgefint(y)); x = resii(x,y); avma=av; if (x==gzero) return x; return subiispec(y+2,x+2,lgefint(y)-2,lgefint(x)-2); } } } void modiiz(GEN x, GEN y, GEN z) { const long av = avma; affii(modii(x,y),z); avma=av; } GEN divrs(GEN x, long y) { long i,lx,ex,garde,sh,s=signe(x); GEN z; LOCAL_HIREMAINDER; if (!y) err(diver6); if (!s) { z=cgetr(3); z[1] = x[1] - (BITS_IN_LONG-1) + bfffo(y); if (z[1]<0) err(diver7); z[2]=0; return z; } if (y<0) { s = -s; y = -y; } if (y==1) { z=rcopy(x); setsigne(z,s); return z; } z=cgetr(lx=lg(x)); hiremainder=0; for (i=2; i garde */ garde=divll(0,y); sh=bfffo(z[2]); ex=evalexpo(expo(x)-sh); if (sh) shift_left(z,z, 2,lx-1, garde,sh); z[1] = evalsigne(s) | ex; return z; } GEN divrr(GEN x, GEN y) { long sx=signe(x), sy=signe(y), lx,ly,lz,e,i,j; ulong si,saux; GEN z,x1; if (!sy) err(diver9); e = evalexpo(expo(x) - expo(y)); if (!sx) { z=cgetr(3); z[1]=e; z[2]=0; return z; } if (sy<0) sx = -sx; e = evalsigne(sx) | e; lx=lg(x); ly=lg(y); if (ly==3) { ulong k = x[2], l = (lx>3)? x[3]: 0; LOCAL_HIREMAINDER; if (k < (ulong)y[2]) e--; else { l >>= 1; if (k&1) l |= HIGHBIT; k >>= 1; } z=cgetr(3); z[1]=e; hiremainder=k; z[2]=divll(l,y[2]); return z; } lz = (lx<=ly)? lx: ly; x1 = (z=new_chunk(lz))-1; x1[1]=0; for (i=2; ilz)? x[lz]: 0; x=z; si=y[2]; saux=y[3]; for (i=0; i si) /* can't happen if i=0 */ { GEN y1 = y+1; overflow=0; for (j=lz-i; j>0; j--) x1[j] = subllx(x1[j],y1[j]); j=i; do x[--j]++; while (j && !x[j]); } hiremainder=x1[1]; overflow=0; qp=divll(x1[2],si); k=hiremainder; } if (!overflow) { long k3 = subll(mulll(qp,saux), x1[3]); long k4 = subllx(hiremainder,k); while (!overflow && k4) { qp--; k3=subll(k3,saux); k4=subllx(k4,si); } } j = lz-i+1; if (j1; j--) { x1[j] = subll(x1[j], addmul(qp,y[j])); hiremainder += overflow; } if ((ulong)x1[1] != hiremainder) { if ((ulong)x1[1] < hiremainder) { qp--; overflow=0; for (j=lz-i; j>1; j--) x1[j]=addllx(x1[j], y[j]); } else { x1[1] -= hiremainder; while (x1[1]) { qp++; if (!qp) { j=i; do x[--j]++; while (j && !x[j]); } overflow=0; for (j=lz-i; j>1; j--) x1[j]=subllx(x1[j],y[j]); x1[1] -= overflow; } } } x1[1]=qp; x1++; } x1 = x-1; for (j=lz-1; j>=2; j--) x[j]=x1[j]; if (*x) { shift_right(x,x, 2,lz, 1,1); } else e--; x[0]=evaltyp(t_REAL)|evallg(lz); x[1]=e; return x; } #endif /* !defined(__M68K__) */ /* The following ones are not in mp.s (mulii is, with a different algorithm) */ /* Integer division x / y: * if z = ONLY_REM return remainder, otherwise return quotient * if z != NULL set *z to remainder * *z is the last object on stack (and thus can be disposed of with cgiv * instead of gerepile) * If *z is zero, we put gzero here and no copy. * space needed: lx + ly */ GEN dvmdii(GEN x, GEN y, GEN *z) { long sx=signe(x),sy=signe(y); long av,lx,ly,lz,i,j,sh,k,lq,lr; ulong si,qp,saux, *xd,*rd,*qd; GEN r,q,x1; if (!sy) err(dvmer1); if (!sx) { if (!z || z == ONLY_REM) return gzero; *z=gzero; return gzero; } lx=lgefint(x); ly=lgefint(y); lz=lx-ly; if (lz <= 0) { if (lz == 0) { for (i=2; i (ulong)y[i]) goto DIVIDE; goto TRIVIAL; } if (z == ONLY_REM) return gzero; if (z) *z = gzero; if (sx < 0) sy = -sy; return stoi(sy); } TRIVIAL: if (z == ONLY_REM) return icopy(x); if (z) *z = icopy(x); return gzero; } DIVIDE: /* quotient is non-zero */ av=avma; if (sx<0) sy = -sy; if (ly==3) { LOCAL_HIREMAINDER; si = y[2]; if (si <= (ulong)x[2]) hiremainder=0; else { hiremainder = x[2]; lx--; x++; } q = new_chunk(lx); for (i=2; i> m; } else { x1[1]=0; for (j=2; j1; j--) { x1[j] = subll(x1[j], addmul(qp,y[j])); hiremainder+=overflow; } if ((ulong)x1[1] < hiremainder) { overflow=0; qp--; for (j=ly-1; j>1; j--) x1[j] = addllx(x1[j],y[j]); } x1[1]=qp; x1++; } lq = lz+2; if (!z) { qd = (ulong*)av; xd = (ulong*)(x + lq); if (x[1]) { lz++; lq++; } while (lz--) *--qd = *--xd; *--qd = evalsigne(sy) | evallgefint(lq); *--qd = evaltyp(t_INT) | evallg(lq); avma = (long)qd; return (GEN)qd; } j=lq; while (j> sh; *--rd = l | (*--xd << shl); } l = *xd >> sh; if (l) *--rd = l; else lr--; } *--rd = evalsigne(sx) | evallgefint(lr); *--rd = evaltyp(t_INT) | evallg(lr); avma = (long)rd; return (GEN)rd; } lr = lz+2; rd = NULL; /* gcc -Wall */ if (lz) { /* non zero remainder: initialize rd */ xd = (ulong*)(x + lx); if (!sh) { rd = (ulong*)avma; (void)new_chunk(lr); while (lz--) *--rd = *--xd; } else { /* shift remainder right by sh bits */ const ulong shl = BITS_IN_LONG - sh; ulong l; rd = (ulong*)x; /* overwrite shifted y */ xd--; while (--lz) { l = *xd >> sh; *--rd = l | (*--xd << shl); } l = *xd >> sh; if (l) *--rd = l; else lr--; } *--rd = evalsigne(sx) | evallgefint(lr); *--rd = evaltyp(t_INT) | evallg(lr); rd += lr; } qd = (ulong*)av; xd = (ulong*)(x + lq); if (x[1]) lq++; j = lq-2; while (j--) *--qd = *--xd; *--qd = evalsigne(sy) | evallgefint(lq); *--qd = evaltyp(t_INT) | evallg(lq); q = (GEN)qd; if (lr==2) *z = gzero; else { /* rd has been properly initialized: we had lz > 0 */ while (lr--) *--qd = *--rd; *z = (GEN)qd; } avma = (long)qd; return q; } /* assume y > x > 0. return y mod x */ ulong mppgcd_resiu(GEN y, ulong x) { long i, ly = lgefint(y); LOCAL_HIREMAINDER; hiremainder = 0; for (i=2; iy>0, both of them odd. return x-y if x=y mod 4, x+y otherwise */ void mppgcd_plus_minus(GEN x, GEN y, GEN res) { long av = avma; long lx = lgefint(x)-1; long ly = lgefint(y)-1, lt,m,i; GEN t; if ((x[lx]^y[ly]) & 3) /* x != y mod 4*/ t = addiispec(x+2,y+2,lx-1,ly-1); else t = subiispec(x+2,y+2,lx-1,ly-1); lt = lgefint(t)-1; while (!t[lt]) lt--; m = vals(t[lt]); lt++; if (m == 0) /* 2^32 | t */ { for (i = 2; i < lt; i++) res[i] = t[i]; } else if (t[2] >> m) { shift_right(res,t, 2,lt, 0,m); } else { lt--; t++; shift_right(res,t, 2,lt, t[1],m); } res[1] = evalsigne(1)|evallgefint(lt); avma = av; } /* private version of mulss */ ulong smulss(ulong x, ulong y, ulong *rem) { LOCAL_HIREMAINDER; x=mulll(x,y); *rem=hiremainder; return x; } #ifdef LONG_IS_64BIT # define DIVCONVI 7 #else # define DIVCONVI 14 #endif /* convert integer --> base 10^9 [assume x > 0] */ GEN convi(GEN x) { ulong av=avma, lim; long lz; GEN z,p1; lz = 3 + ((lgefint(x)-2)*15)/DIVCONVI; z=new_chunk(lz); z[1] = -1; p1 = z+2; lim = stack_lim(av,1); for(;;) { x = divis(x,1000000000); *p1++ = hiremainder; if (!signe(x)) { avma=av; return p1; } if (low_stack(lim, stack_lim(av,1))) x = gerepileuptoint((long)z,x); } } #undef DIVCONVI /* convert fractional part --> base 10^9 [assume expo(x) < 0] */ GEN confrac(GEN x) { long lx=lg(x), ex = -expo(x)-1, d,m,ly,ey,lr,i,j; GEN y,y1; ey = ex + bit_accuracy(lx); ly = 1 + ((ey-1) >> TWOPOTBITS_IN_LONG); d = ex >> TWOPOTBITS_IN_LONG; m = ex & (BITS_IN_LONG-1); y = new_chunk(ly); y1 = y + (d-2); while (d--) y[d]=0; if (!m) for (i=2; i>m)|k; k = l<=0; i--) y[i]=addmul(y[i],1000000000); y1[j]=hiremainder; } return y1; } GEN truedvmdii(GEN x, GEN y, GEN *z) { long av = avma; GEN r, q = dvmdii(x,y,&r); /* assume that r is last on stack */ GEN *gptr[2]; if (signe(r)>=0) { if (z == ONLY_REM) return gerepileuptoint(av,r); if (z) *z = r; else cgiv(r); return q; } if (z == ONLY_REM) { r = subiispec(y+2,r+2, lgefint(y)-2,lgefint(r)-2); return gerepileuptoint(av, r); } q = addsi(-signe(y),q); if (!z) return gerepileuptoint(av, q); *z = subiispec(y+2,r+2, lgefint(y)-2,lgefint(r)-2); gptr[0]=&q; gptr[1]=z; gerepilemanysp(av,(long)r,gptr,2); return q; } /* EXACT INTEGER DIVISION */ /* Find c such that 1=c*b mod 2^BITS_IN_LONG, assuming b odd (unchecked) */ static ulong invrev(ulong b) { ulong x; switch(b & 7) { case 3: case 5: x = b+8; break; default: x = b; break; } /* x = b^(-1) mod 2^4 */ x = x*(2-b*x); x = x*(2-b*x); x = x*(2-b*x); /* b^(-1) mod 2^32 (Newton applied to 1/x - b = 0) */ #ifdef LONG_IS_64BIT x = x*(2-b*x); /* b^(-1) mod 2^64 */ #endif return x; } /* assume xy>0, y odd */ GEN diviuexact(GEN x, ulong y) { long i,lz,lx; ulong q, yinv; GEN z, z0, x0, x0min; if (y == 1) return icopy(x); lx = lgefint(x); if (lx == 3) return stoi((ulong)x[2] / y); yinv = invrev(y); lz = (y <= (ulong)x[2]) ? lx : lx-1; z = new_chunk(lz); z0 = z + lz; x0 = x + lx; x0min = x + lx-lz+2; while (x0 > x0min) { *--z0 = q = yinv*((ulong)*--x0); /* i-th quotient */ if (!q) continue; /* x := x - q * y */ { /* update neither lowest word (could set it to 0) nor highest ones */ register GEN x1 = x0 - 1; LOCAL_HIREMAINDER; (void)mulll(q,y); if (hiremainder) { if ((ulong)*x1 < hiremainder) { *x1 -= hiremainder; do (*--x1)--; while ((ulong)*x1 == MAXULONG); } else *x1 -= hiremainder; } } } i=2; while(!z[i]) i++; z += i-2; lz -= i-2; z[0] = evaltyp(t_INT)|evallg(lz); z[1] = evalsigne(1)|evallg(lz); avma = (ulong)z; return z; } /* Find z such that x=y*z, knowing that y | x (unchecked) * Method: y0 z0 = x0 mod B = 2^BITS_IN_LONG ==> z0 = 1/y0 mod B. * Set x := (x - z0 y) / B, updating only relevant words, and repeat */ GEN diviiexact(GEN x, GEN y) { long av,lx,ly,lz,vy,i,ii,sx = signe(x), sy = signe(y); ulong y0inv,q; GEN z; if (!sy) err(dvmer1); if (!sx) return gzero; vy = vali(y); av = avma; (void)new_chunk(lgefint(x)); /* enough room for z */ if (vy) { /* make y odd */ #if 0 if (vali(x) < vy) err(talker,"impossible division in diviiexact"); #endif y = shifti(y,-vy); x = shifti(x,-vy); } else x = icopy(x); /* necessary because we destroy x */ avma = av; /* will erase our x,y when exiting */ /* now y is odd */ ly = lgefint(y); if (ly == 3) { x = diviuexact(x,(ulong)y[2]); if (signe(x)) setsigne(x,sx*sy); /* should have x != 0 at this point */ return x; } lx = lgefint(x); if (ly>lx) err(talker,"impossible division in diviiexact"); y0inv = invrev(y[ly-1]); i=2; while (i=2; i--,ii--) { long limj; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; z[i] = q = y0inv*((ulong)x[ii]); /* i-th quotient */ if (!q) continue; /* x := x - q * y */ (void)mulll(q,y[0]); limj = max(lx - lz, ii+3-ly); { /* update neither lowest word (could set it to 0) nor highest ones */ register GEN x0 = x + (ii - 1), y0 = y - 1, xlim = x + limj; for (; x0 >= xlim; x0--, y0--) { *x0 = subll(*x0, addmul(q,*y0)); hiremainder += overflow; } if (hiremainder && limj != lx - lz) { if ((ulong)*x0 < hiremainder) { *x0 -= hiremainder; do (*--x0)--; while ((ulong)*x0 == MAXULONG); } else *x0 -= hiremainder; } } } #if 0 i=2; while(ily) return 1; if (lx (ulong)y[i])? 1: -1; } /* x and y are reals. Return sign(|x| - |y|) */ int absr_cmp(GEN x, GEN y) { long ex,ey,lx,ly,lz,i; if (!signe(x)) return signe(y)? -1: 0; if (!signe(y)) return 1; ex=expo(x); ey=expo(y); if (ex>ey) return 1; if (ex (ulong)y[i])? 1: -1; if (lx>=ly) { while (i= ny = num. of digits of x, y (not GEN, see mulii) */ #ifdef INLINE INLINE #endif GEN muliispec(GEN x, GEN y, long nx, long ny) { GEN z2e,z2d,yd,xd,ye,zd; long p1,lz; LOCAL_HIREMAINDER; if (!ny) return gzero; zd = (GEN)avma; lz = nx+ny+2; (void)new_chunk(lz); xd = x + nx; yd = y + ny; ye = yd; p1 = *--xd; *--zd = mulll(p1, *--yd); z2e = zd; while (yd > y) *--zd = addmul(p1, *--yd); *--zd = hiremainder; while (xd > x) { LOCAL_OVERFLOW; yd = ye; p1 = *--xd; z2d = --z2e; *z2d = addll(mulll(p1, *--yd), *z2d); z2d--; while (yd > y) { hiremainder += overflow; *z2d = addll(addmul(p1, *--yd), *z2d); z2d--; } *--zd = hiremainder + overflow; } if (*zd == 0) { zd++; lz--; } /* normalize */ *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(long)zd; return zd; } #ifdef INLINE INLINE #endif GEN sqrispec(GEN x, long nx) { GEN z2e,z2d,yd,xd,zd,x0,z0; long p1,lz; LOCAL_HIREMAINDER; if (!nx) return gzero; zd = (GEN)avma; lz = (nx+1) << 1; z0 = new_chunk(lz); if (nx == 1) { *--zd = mulll(*x, *x); *--zd = hiremainder; goto END; } xd = x + nx; /* compute double products --> zd */ p1 = *--xd; yd = xd; --zd; *--zd = mulll(p1, *--yd); z2e = zd; while (yd > x) *--zd = addmul(p1, *--yd); *--zd = hiremainder; x0 = x+1; while (xd > x0) { LOCAL_OVERFLOW; p1 = *--xd; yd = xd; z2e -= 2; z2d = z2e; *z2d = addll(mulll(p1, *--yd), *z2d); z2d--; while (yd > x) { hiremainder += overflow; *z2d = addll(addmul(p1, *--yd), *z2d); z2d--; } *--zd = hiremainder + overflow; } /* multiply zd by 2 (put result in zd - 1) */ zd[-1] = ((*zd & HIGHBIT) != 0); shift_left(zd, zd, 0, (nx<<1)-3, 0, 1); /* add the squares */ xd = x + nx; zd = z0 + lz; p1 = *--xd; zd--; *zd = mulll(p1,p1); zd--; *zd = addll(hiremainder, *zd); while (xd > x) { p1 = *--xd; zd--; *zd = addll(mulll(p1,p1)+ overflow, *zd); zd--; *zd = addll(hiremainder + overflow, *zd); } END: if (*zd == 0) { zd++; lz--; } /* normalize */ *--zd = evalsigne(1) | evallgefint(lz); *--zd = evaltyp(t_INT) | evallg(lz); avma=(long)zd; return zd; } /* return (x shifted left d words) + y. Assume d > 0, x > 0 and y >= 0 */ static GEN addshiftw(GEN x, GEN y, long d) { GEN z,z0,y0,yd, zd = (GEN)avma; long a,lz,ly = lgefint(y); z0 = new_chunk(d); a = ly-2; yd = y+ly; if (a >= d) { y0 = yd-d; while (yd > y0) *--zd = *--yd; /* copy last d words of y */ a -= d; if (a) z = addiispec(x+2, y+2, lgefint(x)-2, a); else z = icopy(x); } else { y0 = yd-a; while (yd > y0) *--zd = *--yd; /* copy last a words of y */ while (zd >= z0) *--zd = 0; /* complete with 0s */ z = icopy(x); } lz = lgefint(z)+d; z[1] = evalsigne(1) | evallgefint(lz); z[0] = evaltyp(t_INT) | evallg(lz); return z; } /* Fast product (Karatsuba) of integers. a and b are "special" GENs * c,c0,c1,c2 are genuine GENs. */ static GEN quickmulii(GEN a, GEN b, long na, long nb) { GEN a0,c,c0; long av,n0,n0a,i; if (na < nb) swapspec(a,b, na,nb); if (nb == 1) return mulsispec(*b, a, na); if (nb == 0) return gzero; if (nb < KARATSUBA_MULI_LIMIT) return muliispec(a,b,na,nb); i=(na>>1); n0=na-i; na=i; av=avma; a0=a+na; n0a=n0; while (!*a0 && n0a) { a0++; n0a--; } if (n0a && nb > n0) { /* nb <= na <= n0 */ GEN b0,c1,c2; long n0b; nb -= n0; c = quickmulii(a,b,na,nb); b0 = b+nb; n0b = n0; while (!*b0 && n0b) { b0++; n0b--; } if (n0b) { c0 = quickmulii(a0,b0, n0a,n0b); c2 = addiispec(a0,a, n0a,na); c1 = addiispec(b0,b, n0b,nb); c1 = quickmulii(c1+2,c2+2, lgefint(c1)-2,lgefint(c2)-2); c2 = addiispec(c0+2, c+2, lgefint(c0)-2,lgefint(c) -2); c1 = subiispec(c1+2,c2+2, lgefint(c1)-2,lgefint(c2)-2); } else { c0 = gzero; c1 = quickmulii(a0,b, n0a,nb); } c = addshiftw(c,c1, n0); } else { c = quickmulii(a,b,na,nb); c0 = quickmulii(a0,b,n0a,nb); } return gerepileuptoint(av, addshiftw(c,c0, n0)); } /* actual operations will take place on a+2 and b+2: we strip the codewords */ GEN mulii(GEN a,GEN b) { long sa,sb; GEN z; sa=signe(a); if (!sa) return gzero; sb=signe(b); if (!sb) return gzero; if (sb<0) sa = -sa; z = quickmulii(a+2,b+2, lgefint(a)-2,lgefint(b)-2); setsigne(z,sa); return z; } GEN resiimul(GEN x, GEN sy) { GEN r, q, y = (GEN)sy[1], invy; long av = avma, k; k = cmpii(x, y); if (k <= 0) return k? icopy(x): gzero; invy = (GEN)sy[2]; q = mulir(x,invy); q = mptrunc(q); /* <= divii(x, y) (at most 1 less) */ r = subii(x, mulii(y,q)); /* resii(x,y) + y >= r >= resii(x,y) */ k = cmpii(r, y); if (k >= 0) { if (k == 0) { avma = av; return gzero; } r = subiispec(r+2, y+2, lgefint(r)-2, lgefint(y)-2); } #if 0 q = subii(r,resii(x,y)); if (signe(q)) err(talker,"bug in resiimul: x = %Z\ny = %Z\ndif = %Z", x,y,q); #endif return gerepileuptoint(av, r); /* = resii(x, y) */ } /* x % (2^n), assuming x, n >= 0 */ GEN resmod2n(GEN x, long n) { long hi,l,k,lx,ly; GEN z, xd, zd; if (!signe(x) || !n) return gzero; l = n & (BITS_IN_LONG-1); /* n % BITS_IN_LONG */ k = n >> TWOPOTBITS_IN_LONG; /* n / BITS_IN_LONG */ lx = lgefint(x); if (lx < k+3) return icopy(x); xd = x + (lx-k-1); /* x = |_|...|#|1|...|k| : copy the last l bits of # and the last k words * ^--- initial xd */ hi = *xd & ((1<>1); n0=na-i; na=i; av=avma; a0=a+na; n0a=n0; while (!*a0 && n0a) { a0++; n0a--; } c = quicksqri(a,na); if (n0a) { GEN t, c1, c0 = quicksqri(a0,n0a); #if 0 c1 = shifti(quickmulii(a0,a, n0a,na),1); #else /* slower !!! */ t = addiispec(a0,a,n0a,na); t = quicksqri(t+2,lgefint(t)-2); c1= addiispec(c0+2,c+2, lgefint(c0)-2, lgefint(c)-2); c1= subiispec(t+2, c1+2, lgefint(t)-2, lgefint(c1)-2); #endif c = addshiftw(c,c1, n0); c = addshiftw(c,c0, n0); } else c = addshiftw(c,gzero,n0<<1); return gerepileuptoint(av, c); } GEN sqri(GEN a) { return quicksqri(a+2, lgefint(a)-2); } #define MULRR_LIMIT 32 #define MULRR2_LIMIT 32 #if 0 GEN karamulrr1(GEN x, GEN y) { long sx,sy; long i,i1,i2,lx=lg(x),ly=lg(y),e,flag,garde; long lz2,lz3,lz4; GEN z,lo1,lo2,hi; /* ensure that lg(y) >= lg(x) */ if (lx>ly) { lx=ly; z=x; x=y; y=z; flag=1; } else flag = (lx!=ly); if (lx < MULRR_LIMIT) return mulrr(x,y); sx=signe(x); sy=signe(y); e = evalexpo(expo(x)+expo(y)); if (!sx || !sy) { z=cgetr(3); z[2]=0; z[1]=e; return z; } if (sy<0) sx = -sx; ly=lx+flag; z=cgetr(lx); lz2 = (lx>>1); lz3 = lx-lz2; x += 2; lx -= 2; y += 2; ly -= 2; hi = quickmulii(x,y,lz2,lz2); i1=lz2; while (i10) hi = addiispec(hi+2,lo2+2, lgefint(hi)-2,lz4); if (hi[2] < 0) { e++; garde=hi[lx+2]; for (i=lx+1; i>=2 ; i--) z[i]=hi[i]; } else { garde = (hi[lx+2] << 1); shift_left(z,hi,2,lx+1, garde, 1); } z[1]=evalsigne(sx) | e; if (garde < 0) { /* round to nearest */ i=lx+2; do z[--i]++; while (z[i]==0); if (i==1) z[2]=HIGHBIT; } avma=(long)z; return z; } GEN karamulrr2(GEN x, GEN y) { long sx,sy,i,lx=lg(x),ly=lg(y),e,flag,garde; GEN z,hi; if (lx>ly) { lx=ly; z=x; x=y; y=z; flag=1; } else flag = (lx!=ly); if (lx < MULRR2_LIMIT) return mulrr(x,y); ly=lx+flag; sx=signe(x); sy=signe(y); e = evalexpo(expo(x)+expo(y)); if (!sx || !sy) { z=cgetr(3); z[2]=0; z[1]=e; return z; } if (sy<0) sx = -sx; z=cgetr(lx); hi=quickmulii(y+2,x+2,ly-2,lx-2); if (hi[2] < 0) { e++; garde=hi[lx]; for (i=2; i