/***********************************************************************/ /** **/ /** MULTIPRECISION KERNEL **/ /** **/ /***********************************************************************/ /* $Id: mp.c,v 1.1.1.1 1999/09/16 13:47:57 karim Exp $ */ /* 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" /* 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 _i,_l,_k = ((ulong)f)>>m;\ for (_i=imax; _i>imin; _i--) {\ _l = z1[_i];\ z2[_i] = (_l<<(ulong)sh) | _k;\ _k = _l>>(ulong)m;\ }\ z2[imin]=(z1[imin]<<(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 ulong _i,_k,_l = z1[2];\ z2[imin] = (_l>>(ulong)sh) | ((ulong)f<<(ulong)m);\ for (_i=imin+1; _i>(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));\ } #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(truer2); 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(truer2); 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); if (!signe(y)) { l=lgefint(x)-(expo(y)>>TWOPOTBITS_IN_LONG); if (l<3) err(adder3); z=cgetr(l); affir(x,z); return z; } e = expo(y)-expi(x); 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); if (ey & ~EXPOBITS) err(adder4); 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; } #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); if (e & ~EXPOBITS) err(muler2); 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 (e & ~EXPOBITS) err(muler4); 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); if (e & ~EXPOBITS) err(muler6); 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); if (e & ~EXPOBITS) err(muler4); 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); } GEN modiu(GEN y, ulong x) { long sy=signe(y),ly,i; LOCAL_HIREMAINDER; if (!x) err(diver4); if (!sy) return gzero; ly = lgefint(y); if (x <= (ulong)y[2]) hiremainder=0; else { if (ly==3) return utoi((sy > 0)? (ulong)y[2]: x - (ulong)y[2]); hiremainder=y[2]; ly--; y++; } for (i=2; i 0)? hiremainder: x - hiremainder); } #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 (ex & ~EXPOBITS) err(diver7); 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 (e & ~EXPOBITS) err(diver11); 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 (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; } lz = lx-j; lr = lz+2; if (lz) { xd = (ulong*)(x + lx); if (!sh) { rd = (ulong*)avma; r = 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 { 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 /* Conversion entier --> 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 /* Conversion partie fractionnaire --> base 10^9 (expo(x)<0) */ GEN confrac(GEN x) { long lx=lg(x), ex = -expo(x)-1, d,m,ly,ey,lr,nbdec,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,tetpil; GEN res, qu = dvmdii(x,y,&res); GEN *gptr[2]; if (signe(res)>=0) { if (z == ONLY_REM) return gerepileuptoint(av,res); if (z) *z = res; else cgiv(res); return qu; } tetpil=avma; if (z == ONLY_REM) { res = subiispec(y+2,res+2, lgefint(y)-2,lgefint(res)-2); return gerepile(av,tetpil,res); } qu = addsi(-signe(y),qu); if (!z) return gerepile(av,tetpil,qu); *z = subiispec(y+2,res+2, lgefint(y)-2,lgefint(res)-2); gptr[0]=&qu; gptr[1]=z; gerepilemanysp(av,tetpil,gptr,2); return qu; } #if 0 /* Exact integer division */ static ulong invrev(ulong b) /* Find c such that 1=c*b mod B (where B = 2^32 or 2^64), assuming b odd, which is not checked */ { int r; ulong x; r=b&7; x=(r==3 || r==5)? b+8: b; /* x=b^(-1) mod 2^4 */ x=x*(2-b*x); x=x*(2-b*x); x=x*(2-b*x); /* x=b^(-1) mod 2^32 */ #ifdef LONG_IS_64BIT x=x*(2-b*x); /* x=b^(-1) mod 2^64 */ #endif return x; } #define divllrev(a,b) (((ulong)a)*invrev(b)) /* 2-adic division */ GEN diviirev(GEN x, GEN y, long a) /* Find z such that |x|=|y|*z mod B^a, where a<=lgefint(x)-2 */ { long lx,lgx,ly,vy,av=avma,tetpil,i,j,ii; ulong binv,q; GEN z; if (!signe(y)) err(dvmer1); if (!signe(x)) return gzero; /* make y odd */ vy=vali(y); if (vy) { if (vali(x)>TWOPOTBITS_IN_LONG); } else x=icopy(x); /* necessary because we destroy x */ /* improve the above by touching only a words */ if (a<=0) {avma=a;return gzero;} /* now y is odd */ lx=a+2; ly=lgefint(y); lgx=lgefint(x); if (lx>lgx) err(talker,"3rd parameter too large in diviirev"); binv=invrev(y[ly-1]); z=cgeti(lx); for (ii=lgx-1,i=lx-1; i>=2; i--,ii--) { long limj; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; z[i]=q=binv*((ulong)x[ii]); /* this is the i-th quotient */ limj=max(lgx-a,3+ii-ly); mulll(q,y[ly-1]); overflow=0; for (j=ii-1; j>=limj; j--) x[j]=subllx(x[j],addmul(q,y[j+ly-ii-1])); } tetpil=avma; i=2; while((ilx) err(talker,"impossible division in diviirev"); binv=invrev(y[ly-1]); i=2; while (i=2; i--,ii--) { long limj; LOCAL_HIREMAINDER; LOCAL_OVERFLOW; z[i]=q=binv*((ulong)x[ii]); /* this is the i-th quotient */ limj=max(lx-lz+2,3+ii-ly); mulll(q,y[ly-1]); overflow=0; for (j=ii-1; j>=limj; j--) x[j]=subllx(x[j],addmul(q,y[j+ly-ii-1])); } tetpil=avma; i=2; while((ilpr+2) { long lp1cut,lynew,lp2; GEN p1cut,p2,ynew; LOCAL_OVERFLOW; lp1cut=min(lp1-lpr,lpr+2); p1cut=cgeti(lp1cut); p1cut[1]=evalsigne(1) | evallgefint(lp1cut); overflow=0; for (i=lp1cut-1; i>=2; i--) p1cut[i]=subllx(0,p1[i+lp1-lpr-lp1cut]); p2=mulii(p1cut,yinv); lp2=lgefint(p2); lynew=(lp2<=lpr+2) ? lpr+lp2 : 2*lpr+2; ynew=cgeti(lynew); ynew[1]=evalsigne(1) | evallgefint(lynew); for (i=lynew-1; i>=lynew-lpr; i--) ynew[i]=yinv[i+lyinv-lynew]; for (i=lynew-lpr-1; i>=2; i--) ynew[i]=p2[i+lp2+lpr-lynew]; yinv=ynew; } lpr<<=1; } lyinv=lgefint(yinv); lzs=min(lz,lyinv); z=cgeti(lzs); z[1]=evalsigne(1) | evallgefint(lzs); for(i=2; 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; } /* 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,b. These are not real GENs, a+2 * and b+2 were sent instead. na, nb = number of digits of a, b. * 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 < MULII_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; } static GEN quicksqri(GEN a, long na) { GEN a0,c,c0,c1; long av,n0,n0a,i; if (na>1); n0=na-i; na=i; av=avma; a0=a+na; n0a=n0; while (!*a0 && n0a) { a0++; n0a--; } c = quicksqri(a,na); if (n0a) { c0 = quicksqri(a0,n0a); c1 = shifti(quickmulii(a0,a, n0a,na),1); 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 (e & ~EXPOBITS) err(muler4); 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 (e & ~EXPOBITS) err(muler4); 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