/***********************************************************************/
/***********************************************************************/
/**								      **/
/**		       OPERATIONS DE BASE (NOYAU)		      **/
/**								      **/
/***********************************************************************/
/***********************************************************************/
/* $Id: mp.c,v 2.0.0.2 1997/12/14 20:11:49 karim Exp karim $ */
#include "genpari.h"

/* Define the kernel symbols if functions can not be inlined */
#ifndef __cplusplus
# if !defined(INLINE) || !defined(__OPTIMIZE__) || defined(__M68K__)
#  undef INLINE
#  define INLINE
#  include "kernelinline.h"
#  include "mpinline.h"
#  undef INLINE
# endif
#endif

#ifndef __M68K__

/* prototype of positive small ints */
static long pos_s[] = {
  evaltyp(t_INT) | evallg(3), evalsigne(1) | evallgefint(3), 0 };

/* prototype of negative small ints */
static long neg_s[] = {
  evaltyp(t_INT) | evallg(3), evalsigne(-1) | evallgefint(3), 0 };

void 
mpnegz(GEN x, GEN y)
{
  long av=avma; 
  x = (typ(x)==t_INT)? negi(x): negr(x);
  gaffect(x,y); avma=av;
}

void 
mpabsz(GEN x, GEN y)
{
  long av=avma; 
  x = (typ(x)==t_INT)? absi(x): absr(x);
  gaffect(x,y); avma=av;
}

void
affir(GEN x, GEN y)
{
  const long s=signe(x),ly=lg(y);
  long lx,s1,i,k;

  if (!s)
  {
    y[1]=HIGHEXPOBIT - bit_accuracy(ly);
    y[2]=0; return;
  }

  lx=lgefint(x); s1=bfffo(x[2]);
  y[1] = evalsigne(s) | evalexpo(bit_accuracy(lx)-s1-1);
  if (s1)
  {
    if (lx<=ly)
    {
      for (i=lx; i<ly; i++) y[i]=0;
      k=0; i=lx-1;
    }
    else
    {
      shiftl(x[ly],s1);
      k=hiremainder; i=ly-1;
    }
    for ( ; i>=2; i--,k=hiremainder)
      y[i]=shiftl(x[i],s1)+k;
    return;
  }

  if (lx<ly)
  {
    for (i=2; i<lx; i++) y[i]=x[i];
    for (   ; i<ly; i++) y[i]=0;
  }
  else 
    for (i=2; i<ly; i++) y[i]=x[i];
}

void
affrr(GEN x, GEN y)
{
  if (x==y) return;
  y[1]=x[1];
  if (!signe(x)) y[2]=0;
  else
  {
    const long lx=lg(x), ly=lg(y);
    long i;

    if (lx<ly)
    {
      for (i=2; i<lx; i++) y[i]=x[i];
      for (   ; i<ly; i++) y[i]=0;
    }
    else
      for (i=2; i<ly; i++) y[i]=x[i];
  }
}

GEN
shifti(GEN x, long n)
{
  const long s=signe(x);
  long lx,i,d,m,p1,p2,k;
  GEN y,z;

  if (!s) return gzero;
  if (!n) return icopy(x);
  lx=lgefint(x);
  if (n>0)
  {
    d = n>>TWOPOTBITS_IN_LONG; m = n & (BITS_IN_LONG-1);
    i=lx+d; 
    if (m)
    {
      p1=shiftl(x[2],m); k=0;
      if (hiremainder)
      {
	z=y=cgeti(i+1);
        y[2]=hiremainder; y++; /* shift left the y digits */
      }
      else
	z=y=cgeti(i);
      for (i--; i>=lx; i--) y[i]=0;
      for (   ; i>=3 ; i--)
        { y[i]=shiftl(x[i],m)+k; k=hiremainder; }
      y[2]=p1+k;
    }
    else
    {
      z=y=cgeti(i);
      for (i--; i>=lx; i--) y[i]=0;
      for (   ; i>=2 ; i--) y[i]=x[i];
    }
    z[1]=z[0]; setsigne(z,s); return z;
  }

  n = -n; d = n>>TWOPOTBITS_IN_LONG;
  if (lx<d+3) return gzero;

  lx -= d;
  m = n & (BITS_IN_LONG-1);
  if (!m)
  {
    z=y=cgeti(lx);
    for (i=lx-1; i>=2; i--) y[i]=x[i];
  }
  else
  {
    m=BITS_IN_LONG-m; lx--;
    p1=shiftl(x[2],m);
    if (hiremainder)
    {
      z=y=cgeti(lx+1);
      y[2]=hiremainder;
    }
    else
    {
      if (lx==2) return gzero;
      z=y=cgeti(lx); y--; /* shift right the y digits */
    }
    for (i=3; i<=lx; i++)
    {
      p2=shiftl(x[i],m); y[i]=p1+hiremainder; p1=p2;
    }
  }
  z[1]=z[0]; setsigne(z,s); return z;
}

GEN
mptrunc(GEN x)
{
  long d,e,i,s,m;
  GEN y;

  if (typ(x)==t_INT) return icopy(x);
  s=signe(x); if (!s) return gzero;
  e=expo(x); if (e<0) return gzero;
  d = (e>>TWOPOTBITS_IN_LONG)+3; m =e & (BITS_IN_LONG-1);
  if (d>lg(x)) err(truer2);

  y=cgeti(d); y[1] = evallgefint(d) | evalsigne(s);
  if (m==(BITS_IN_LONG-1))
    for (i=2; i<d; i++) y[i]=x[i];
  else
  {
    long p1, p2;

    m++; p1=0;
    for (i=2; i<d; i++)
    {
      p2=shiftl(x[i],m); y[i]=hiremainder+p1; p1=p2;
    }
  }
  return y;
}

/* integral part */
GEN
mpent(GEN x)
{
  long d,e,i,lx,m;
  GEN y;

  if (typ(x)==t_INT) return icopy(x);
  if (signe(x)>=0) return mptrunc(x);
  e=expo(x);
  if (e<0)
  { 
    y=cgeti(3); y[1] = evalsigne(-1) | evallgefint(3);
    y[2]=1; return y;
  }
  d = (e>>TWOPOTBITS_IN_LONG)+3; m = e & (BITS_IN_LONG-1); 
  lx=lg(x); if (d>lx) err(truer2);
  y=cgeti(d); y[1] = evalsigne(-1) | evallgefint(d);
  if (m==(BITS_IN_LONG-1))
  {
    for (i=2; i<d; i++) y[i]=x[i];
    while (i<lx && !x[i]) i++;
    if (i==lx) return y;
  }
  else
  {
    long p1=0, p2;

    m++;
    for (i=2; i<d; i++)
    {
      p2=shiftl(x[i],m); y[i]=hiremainder+p1; p1=p2;
    }
    if (!p1)
    {
      while (i<lx && !x[i]) i++;
      if (i==lx) return y;
    }
  }

  for (i=d-1; i>=2 && y[i]==(long)MAXULONG; i--) y[i]=0;
  if (i>=2) y[i]++;
  else
  {
    const GEN z=y;
    y=cgeti(1); y[0]=z[0]+1; y[1]=z[1]+1; y[2]=1;
  }
  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==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== -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 (sx<sy) return -1;
  if (sx>sy) return 1;
  if (!sx) return 0;

  lx=lgefint(x); ly=lgefint(y);
  if (lx>ly) return sx;
  if (lx<ly) return -sx;
  i=2; while (i<lx && x[i]==y[i]) i++;
  if (i==lx) return 0;
  return ((ulong)x[i] > (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 (sx<sy) return -1;
  if (sx>sy) return 1;
  if (!sx) return 0;

  ex=expo(x); ey=expo(y);
  if (ex>ey) return sx;
  if (ex<ey) return -sx;

  lx=lg(x); ly=lg(y); lz = (lx<ly)?lx:ly;
  i=2; while (i<lz && x[i]==y[i]) i++;
  if (i<lz) return ((ulong)x[i] > (ulong)y[i]) ? sx : -sx;
  if (lx>=ly)
  {
    while (i<lx && !x[i]) i++;
    return (i==lx) ? 0 : sx;
  }
  while (i<ly && !y[i]) i++;
  return (i==ly) ? 0 : -sx;
}

GEN
addss(long x, long y)
{
  if (!x) return stoi(y);
  if (x>0) { 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,i;
  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;
  ly=lgefint(y);
  if (sx==sy)
  {
    const long p=addll(x,y[ly-1]);

    if (overflow)
    {
      z=cgeti(ly+1); z[ly]=p; y--;
      for (i=ly-1; i>2 && y[i] == (long)MAXULONG; i--) z[i]=0;
      if (i>2)
      {
	z[i]=y[i]+1; for (i--; i>=3; i--) z[i]=y[i];
	z[2]=z[1]=z[0]-1; z++; avma+=BYTES_IN_LONG;
      }
      else { z[2]=1; z[1]=z[0]; }
    }
    else
    {
      z=cgeti(ly); z[ly-1]=p;
      for (i=1; i<ly-1; i++) z[i]=y[i];
    }
    setsigne(z,sx); return z;
  }

  if (ly==3)
  {
    if (y[2]==x) return gzero;
    z=cgeti(3); 
    if ((ulong)y[2] > (ulong)x)
    {
      z[1] = evalsigne(sy) | evallgefint(3);
      z[2]=y[2]-x;
    }
    else
    {
      z[1] = evalsigne(-sy) | evallgefint(3);
      z[2]=x-y[2]; 
    }
    return z;
  }

  z=cgeti(ly); ly--; z[ly]=subll(y[ly],x);
  if (overflow)
  {
    for (i=ly-1; y[i]==0; i--) z[i]=(long)MAXULONG;
    z[i]=y[i]-1;
    if (i>2 || z[i]) 
      for (i--; i>=1; i--) z[i]=y[i];
    else
    {
      z[2]=z[1]=z[0]-1; z++;
      avma+=BYTES_IN_LONG; setsigne(z,sy);
    }
  }
  else
    for (i=1; i<ly; i++) z[i]=y[i];
  return z;
}

GEN
addii(GEN x, GEN y)
{
  long sx=signe(x),sy,lx,ly,i,j;
  GEN z,z2;

  if (!sx) return icopy(y);
  sy=signe(y); if (!sy) return icopy(x);
  lx=lgefint(x); ly=lgefint(y);

  if (sx==sy)
  {
    if (lx<ly) { z=x; x=y; y=z; i=lx; lx=ly; ly=i; }
    z2=cgeti(lx+1); z=z2+1; overflow=0;
    for (i=ly-1,j=lx-1; i>=2; i--,j--) z[j]=addllx(x[j],y[i]);
    if (overflow)
    {
      for ( ; j>=2 && x[j]==(long)MAXULONG; j--) z[j]=0;
      if (j==1) { z[1]=1; z[0]=x[1]+1; return z2; }
      z[j]=x[j]+1; j--;
    }
    for (; j>=2; j--) z[j]=x[j];
    z[0]=z2[0]-1; z[1]=x[1]; avma += BYTES_IN_LONG;
    return z;
  }

  /* here sx != sy */
  if (lx==ly)
  {
    setsigne(y,1); setsigne(x,1);
    i=cmpii(x,y);
    setsigne(y,sy); setsigne(x,sx);
    if (!i) return gzero;
    if (i<0) { z=x; x=y; y=z; sx=sy; }
  }
  else if (lx<ly)
    { z=x; x=y; y=z; sx=sy; i=lx; lx=ly; ly=i; }
  z=cgeti(lx); overflow=0;
  for (i=ly-1,j=lx-1; i>=2; i--,j--) z[j]=subllx(x[j],y[i]);
  if (overflow)
  {
    for (; !x[j]; j--) z[j]=(long)MAXULONG;
    z[j]=x[j]-1; j--;
  }
  for (; j>=2; j--) z[j]=x[j];
  if (z[2]) { z[1]=x[1]; return z; }

  j=3; while (j<lx && !z[j]) j++;
  i=j-2; z[i+1] = z[i] = z[0]-i;
  z += i; avma += (i<<TWOPOTBYTES_IN_LONG);
  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 l,e,ly,av,i,l1;
  GEN z;

  if (!signe(x)) return rcopy(y);
  if (!signe(y))
  {
    l=lgefint(x)-(expo(y)>>TWOPOTBITS_IN_LONG); 
    if (l<3 || l>32767) 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<=2) return rcopy(y);
  }

  l = ly + ((-e)>>TWOPOTBITS_IN_LONG)+1;
  if (l>32767) err(adder3);
  av=avma; z=cgetr(l); affir(x,z); l1=av-avma;
  l=l1>>TWOPOTBYTES_IN_LONG; z=addrr(z,y);
  for (i=lg(z)-1; i>=0; i--) z[i+l]=z[i];
  z+=l; avma+=l1;
  return z;
}

GEN
addrr(GEN x, GEN y)
{
  long sx=signe(x),sy=signe(y),lx,ly,ex=expo(x),ey=expo(y),sz;
  long av0=avma,e,l,i,d,m,flag,lp1,lp2,av,k,j,f2;
  GEN z,p1,p2;

  if (!sy)
  {
    if (!sx)
    {
      e = (ex>=ey)? ex: ey; z=cgetr(3);
      z[2]=0; z[1]=e+HIGHEXPOBIT; return z;
    }
    e=ex-ey;
    if (e<0) { z=cgetr(3); z[2]=0; z[1]=ey+HIGHEXPOBIT; return z; }
    l=(e>>TWOPOTBITS_IN_LONG)+3;
    lx=lg(x); if (l>lx) l=lx;
    z=cgetr(l); for (i=1; i<l; i++) z[i]=x[i];
    return z;
  }

  e=ey-ex;
  if (!sx)
  {
    if (e<0) { z=cgetr(3); z[2]=0; z[1]=ex+HIGHEXPOBIT; return z; }
    l=(e>>TWOPOTBITS_IN_LONG)+3; 
    ly=lg(y); if (l>ly) l=ly;
    z=cgetr(l); for (i=1; i<l; i++) z[i]=y[i];
    return z;
  }

  if (e)
  {
    if (e<0) { z=x; x=y; y=z; ey=ex; e= -e; sz=sx; sx=sy; sy=sz; }
    lx=lg(x); ly=lg(y);
    d = e >> TWOPOTBITS_IN_LONG;
    if (d>=ly-2) return rcopy(y);
    m = e & (BITS_IN_LONG-1);

    l=d+lx;
    if (l>=ly)
    {
      flag=1; p1=cgetr(ly); lp1=ly; lp2=ly-d;
    }
    else
    {
      flag=0; p1=cgetr(l+1); lp1=l+1; lp2=lx+1;
    }
    av=avma;
    if (m)
    {
      p2=cgetr(lp2); m=BITS_IN_LONG-m;
      if (flag) { shiftl(x[lp2-1],m); k=hiremainder; }
      else k=0;
      for (i=lp2-1; i>=3; i--)
      {
	p2[i]=shiftl(x[i-1],m)+k; k=hiremainder;
      }
      p2[2]=k;
    }
    else p2=x;
  }
  else
  {
    lx=lg(x); ly=lg(y); l=(lx>ly)?ly:lx; p1=cgetr(l);
    av=avma; lp2=lp1=l; flag=2; p2=x; m=0;
  }

  overflow=0;
  if (sx==sy)
  {
    if (m || flag) { i=lp1-1; j=lp2-1; }
    else
    {
      p1[lp1-1]=y[lp1-1];
      i=lp1-2; j=lp2-2;
    }
    for (; j>=2; i--,j--) p1[i]=addllx(p2[j],y[i]);

    p1[1] = evalsigne(sx) | (ey + HIGHEXPOBIT);
    if (overflow)
    {
      for (; i>=2 && y[i] == (long)MAXULONG; i--) p1[i]=0;
      if (i==1)
      {
	if (ey == HIGHEXPOBIT-1) err(adder4);
        k=HIGHBIT; p1[1]++;
	for (i=2; i<lp1; i++, k=hiremainder)
	  p1[i] = shiftlr(p1[i],1) + k;
	avma=av; return p1;
      }
      p1[i]=y[i]+1; i--;
    }
    for (; i>=2; i--) p1[i]=y[i];
    avma=av; return p1;
  }

  if (!e)
  {
    i=2; while (i<l && p2[i]==y[i]) i++;
    if (i==l)
    {
      e = ex - bit_accuracy(l) + HIGHEXPOBIT;
      if (e<0) err(adder5); if (e>EXPOBITS) err(adder4);
      avma=av0; z=cgetr(3); z[2]=0; z[1]=e; return z;
    }
    f2 = ((ulong) y[i] > (ulong) p2[i]) ? 1 : 0;
  }
  else f2=1;

  if (f2)
  {
    if (m || flag) { i=lp1-1; j=lp2-1; }
    else
    {
      p1[lp1-1]=y[lp1-1];
      i=lp1-2; j=lp2-2;
    }
    for (; j>=2; i--,j--) p1[i] = subllx(y[i],p2[j]);
    if (overflow)
    {
      for (; i>=2 && !y[i]; i--) p1[i]=(long)MAXULONG;
      p1[i]=y[i]-1; i--;
    }
    for (; i>=2; i--) p1[i]=y[i];
  }
  else
  {
    if (m || flag) i=lp1-1;
    else
    {
      p1[lp1-1]=subllx(0,y[lp1-1]); i=lp1-2;
    }
    for (; i>=2; i--) p1[i]=subllx(p2[i],y[i]);
  }

  i=2; while (!p1[i]) i++;
  j=i-2; avma = av + (j<<TWOPOTBYTES_IN_LONG);
  p1[j]=p1[0]-j; p1+=j; m=bfffo(p1[2]);
  e = ey-(j<<TWOPOTBITS_IN_LONG)-m+HIGHEXPOBIT;
  if (e<0) err(adder5);
  p1[1] = f2 ? evalsigne(sy)+e : evalsigne(sx)+e;
  if (m)
    for (k=0, i=lp1-1-j; i>=2; i--, k=hiremainder)
      p1[i]=shiftl(p1[i],m)+k;
  return p1;
}

GEN
mulss(long x, long y)
{
  long s,p1;
  GEN z;

  if (!x || !y) return gzero;
  if (x<0) { s = -1; x = -x; } else s=1;
  if (y<0) { s = -s; y = -y; }
  p1=mulll(x,y);
  if (hiremainder)
  {
    z=cgeti(4); z[1] = evalsigne(s) | evallgefint(4);
    z[2]=hiremainder; z[3]=p1; return z;
  }
  z=cgeti(3); z[1] = evalsigne(s) | evallgefint(3);
  z[2]=p1; return z;
}

/* private version */
ulong
smulss(ulong x, ulong y, ulong *rem)
{
  x=mulll(x,y); *rem=hiremainder; return x;
}

GEN
mulsi(long x, GEN y)
{
  long s,ly,i;
  GEN z,z2;

  if (!x) return gzero; 
  s=signe(y); if (!s) return gzero; 
  if (x<0) { s = -s; x = -x; }
  ly=lgefint(y); z2=cgeti(ly+1);
  z = z2+1; hiremainder=0;
  for (i=ly-1; i>=2; i--) z[i]=addmul(x,y[i]);
  if (hiremainder)
  {
    z[1]=hiremainder; z[0] = evallgefint(ly+1) | evalsigne(s);
    return z2;
  }
  z[0]=z2[0]-1; z[1] = evallgefint(ly) | evalsigne(s);
  avma+=BYTES_IN_LONG; return z;
}

GEN
mulsr(long x, GEN y)
{
  long lx,i,k,s,p1,p2,e;
  GEN z,z2;

  if (!x) return gzero;
  s=signe(y);
  if (!s)
  { 
    if (x<0) x= -x; p1=bfffo(x);
    e=y[1]+(BITS_IN_LONG-1)-p1; 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); z=cgetr(lx); z2 = z + 1; p2=mulll(x,y[lx-1]);
  for (i=lx-2; i>=2; i--) z2[i]=addmul(x,y[i]);
  z[2]=hiremainder; p1=bfffo(hiremainder);
  if (p1)
  {
    shiftl(p2,p1); k=hiremainder;
    for (i=lx-1; i>=2; i--)
    {
      z[i]=shiftl(z[i],p1)+k; k=hiremainder;
    }
  }
  e=BITS_IN_LONG-p1+expo(y); if (e>=HIGHEXPOBIT) err(muler2);
  z[1] = evalsigne(s) | evalexpo(e); return z;
}

GEN
mulrr(GEN x, GEN y)
{
  long sx = signe(x), sy = signe(y), ex = expo(x), ey = expo(y);
  long ii,i,j,lx,ly,lz,lzz,e,flag,garde,p1,p2;
  GEN z;

  e = ex+ey+HIGHEXPOBIT; if (e>=EXPOBITS) err(muler4);
  if (e<0) err(muler5);
  if (!sx || !sy) { z=cgetr(3); z[2]=0; z[1]=e; return z; }
  if (sy<0) sx = -sx;
  lx=lg(x); ly=lg(y);
  if (lx>ly) { lz=ly; z=x; x=y; y=z; flag=1; } else { lz=lx; flag = (lx!=ly); }
  z=cgetr(lz); z[1] = evalsigne(sx) | e;
  if (flag) mulll(x[2],y[lz]); else hiremainder=0;
  if (lz==3)
  {
    garde=flag ? addmul(x[2],y[2]) : mulll(x[2],y[2]);
    if ((long)hiremainder<0) { z[2]=hiremainder; z[1]++; }
    else { z[2]=hiremainder<<1; if (garde<0) z[2]++; }
    return z;
  }

  lzz=lz-1; p1=x[lzz]; garde=hiremainder;
  if (p1)
  {
    mulll(p1,y[3]); p2=addmul(p1,y[2]);
    garde=addll(p2,garde); z[lzz] = overflow+hiremainder;
  }
  else z[lzz]=0;
  for (j=lz-2; j>=3; j--)
  {
    p1=x[j];
    if (p1)
    { 
      ii=lz-j; mulll(p1,y[ii+2]); p2 = addmul(p1,y[ii+1]);
      garde=addll(p2,garde); hiremainder += overflow;
      for (i=lzz; i>j; i--)
      {
	p2=addmul(p1,y[ii]); z[i]=addll(p2,z[i]); 
        hiremainder += overflow; ii--;
      }
      z[j]=hiremainder;
    }
    else z[j]=0;
  }
  p1=x[2]; p2=mulll(p1,y[lzz]); y--;
  garde=addll(p2,garde); hiremainder += overflow;
  for (i=lzz; i>2; i--)
  {
    p2=addmul(p1,y[i]); z[i]=addll(p2,z[i]);
    hiremainder += overflow;
  }
  z[2]=hiremainder;
  if ((long)hiremainder > 0)
  {
    overflow = (garde < 0)? 1 : 0;
    for (i=lzz; i>=2; i--) { p1=z[i]; z[i]=addllx(p1,p1); }
  }
  else z[1]++;
  return z;
}

GEN
mulir(GEN x, GEN y)
{
  long sx=signe(x),sy,av,lz,lzz,ey,e,garde,p1,p2,i,ii,j;
  GEN z,temp;

  if (!sx) return gzero;
  sy=signe(y); ey=expo(y);
  if (!sy)
  {
    z=cgetr(3); z[2]=0; e=expi(x)+ey+HIGHEXPOBIT;
    if (e>EXPOBITS) err(muler6);
    z[1]=e; return z;
  } 
  if (sy<0) sx = -sx;
  lz=lg(y); z=cgetr(lz);
  av=avma; temp=cgetr(lz+1);
  affir(x,temp); x=y; y=temp;
  e=expo(y)+ey+HIGHEXPOBIT; if (e>=EXPOBITS) err(muler4);
  if (e<0) err(muler5);

  z[1] = evalsigne(sx) | e; mulll(x[2],y[lz]);
  if (lz==3)
  {
    garde=addmul(x[2],y[2]);
    if ((long)hiremainder < 0) { z[2]=hiremainder; z[1]++; }
    else { z[2]=hiremainder<<1; if (garde<0) z[2]++; }
    avma=av; return z;
  }

  lzz=lz-1; p1=x[lzz]; garde=hiremainder;
  if (p1)
  {
    mulll(p1,y[3]); p2=addmul(p1,y[2]);
    garde=addll(p2,garde); z[lzz] = overflow+hiremainder;
  }
  else z[lzz]=0;
  for (j=lz-2; j>=3; j--)
  {
    p1=x[j];
    if (p1)
    { 
      ii=lz-j; mulll(p1,y[ii+2]); p2 = addmul(p1,y[ii+1]);
      garde=addll(p2,garde); hiremainder += overflow;
      for (i=lzz; i>j; i--)
      {
        p2=addmul(p1,y[ii]); z[i]=addll(p2,z[i]);
        hiremainder += overflow; ii--;
      }
      z[j]=hiremainder;
    }
    else z[j]=0;
  }
  p1=x[2]; p2=mulll(p1,y[lzz]); y--;
  garde=addll(p2,garde); hiremainder += overflow;
  for (i=lzz; i>=3; i--)
  {
    p2=addmul(p1,y[i]); z[i]=addll(p2,z[i]);
    hiremainder += overflow;
  }
  z[2]=hiremainder;
  if ((long)hiremainder > 0)
  {
    overflow = (garde < 0)? 1 : 0;
    for (i=lzz; i>=2; i--) { p1=z[i]; z[i]=addllx(p1,p1); }
  }
  else z[1]++;
  avma=av; return z;
}

#ifdef LONG_IS_64BIT
#  define DIVCONVI 7
#else
#  define DIVCONVI 14
#endif
 
/* Conversion entier --> base 10^9 */
GEN
convi(GEN x)
{
  long av=avma, lz,lim, sx = signe(x);
  GEN z,p1,p2;

  if (!sx)
  {
    z=cgeti(3); z[1] = -1; z[2]=0;
    avma=av; return z+3;
  }
  setsigne(x,1); p1 = x;
  lz = 3 + ((lgefint(p1)-2)*15)/DIVCONVI;
  z=cgeti(lz); z[1] = -1; p2 = z+2; 
  lim = (av+bot)>>1;
  for(;;)
  { 
    p1 = divis(p1,1000000000); *p2++ = hiremainder;
    if (!signe(p1)) { avma=av; setsigne(x,sx); return p2; }
    if (low_stack(lim, (av+bot)>>1)) p1 = gerepileupto((long)z,p1);
  }
}

/* Conversion partie fractionnaire --> base 10^9 */
GEN
confrac(GEN x)
{
  long lx=lg(x), ex = -expo(x)-1,ex1,av=avma,ly,ey;
  long lr,nbdec,k,i,j;
  GEN y,res;

  ey = ex + bit_accuracy(lx);
  ly = (ey + (2*BITS_IN_LONG-1)) >> TWOPOTBITS_IN_LONG;
  y=cgeti(ly);
  ex1 = ex >> TWOPOTBITS_IN_LONG; /* 95 dans mp.s faux? */
  for (i=0; i<ex1; i++) y[i]=0;
  ex &= (BITS_IN_LONG-1);
  if (!ex)
    for (j=2; j<lx; j++) y[i++]=x[j];
  else
  {
    for (k=0, j=2; j<lx; j++, k=hiremainder)
      y[i++] = shiftlr(x[j],ex) + k;
    y[ly-2]=k;
  }
  y[ly-1]=0;
  nbdec = (long) (ey*L2SL10)+1; lr=(nbdec+17)/9;
  res=cgeti(lr); *res=nbdec;
  for (j=1; j<lr; j++)
  {
    hiremainder=0;
    for (i=ly-1; i>=0; i--) y[i]=addmul(y[i],1000000000);
    res[j]=hiremainder;
  }
  avma=av; return res;
}

/* due to Bruno Haible */
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 | -z;
  z = (z<<4) + z;
  z = (z<<6) + z;
  z = z ^ (z<<16); /* or  z = z - (z<<16);  or  z = z &~ (z<<16);  */
#ifdef LONG_IS_64BIT
  return s + tab[(z&0xffffffff)>>26];
#endif  
  return tab[z>>26];
}

/*
GEN
modss(long x, long y)
{
  if (!y) err(moder1);
  if (y<0) y=-y;
  hiremainder=0; divll(labs(x),y);
  if (!hiremainder) return gzero;
  return (((long)hiremainder) < 0) ? stoi(y-hiremainder) : stoi(hiremainder);
}

GEN
resss(long x, long y)
{
  if (!y) err(reser1);
  hiremainder=0; divll(labs(x),labs(y));
  return (y<0) ? stoi(-((long)hiremainder)) : stoi(hiremainder);
}

GEN
divsi(long x, GEN y)
{
  long p1, s = signe(y);

  if (!s) err(diver2);
  if (!x || lgefint(y)>3 || y[2]<0) { hiremainder=x; return gzero; }
  hiremainder=0; p1=divll(labs(x),y[2]);
  if (s<0) { hiremainder = -((long)hiremainder); p1 = -p1; }
  if (x<0) p1 = -p1;
  return stoi(p1);
}

GEN
modsi(long x, GEN y)
{
  long s;
  GEN p1;

  divsi(x,y); if (!hiremainder) return gzero;
  if (x>0) return stoi(hiremainder);
  s=signe(y);
  if (s<0) 
    { setsigne(y,1); p1=addsi(hiremainder,y); setsigne(y,-1); }
  else
    p1=addsi(-hiremainder,y);
  return p1;
}
*/

GEN
modss(long x, long y)
{
  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)
{
  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);

  if (!s) err(diver2);
  if (!x || lgefint(y)>3 || ((long)y[2])<0) { hiremainder=x; return gzero; }
  hiremainder=0; p1=divll(labs(x),y[2]);
  if (x<0) { hiremainder = -((long)hiremainder); p1 = -p1; }
  if (s<0) p1 = -p1;
  return stoi(p1);
}

GEN
modsi(long x, GEN y)
{
  long s = signe(y);
  GEN p1;

  if (!s) err(diver2);
  if (!x || lgefint(y)>3 || ((long)y[2])<0) hiremainder=x;
  else
  {
    hiremainder=0; 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,z2;

  if (!x) err(diver4);
  if (!sy) { hiremainder=0; return gzero; }
  if (x<0) { s = -sy; x = -x; } else s=sy;

  ly=lgefint(y);
  if ((ulong)x > (ulong)y[2])
  {
    if (ly==3) { hiremainder=itos(y); return gzero; }
    z=cgeti(ly-1); z2 = z-1; z[1] = evallgefint(ly-1) | evalsigne(s);
    hiremainder=y[2]; for (i=3; i<ly; i++) z2[i]=divll(y[i],x);
  }
  else
  {
    z=cgeti(ly); z[1] = evallgefint(ly) | evalsigne(s);
    hiremainder=0; for (i=2; i<ly; i++) z[i]=divll(y[i],x);
  }
  if (sy<0) hiremainder = - ((long)hiremainder);
  return z;
}

GEN
divir(GEN x, GEN y)
{
  GEN xr,z;
  long av,ly;

  if (!signe(y)) err(diver5);
  if (!signe(x)) return gzero;
  ly=lg(y); z=cgetr(ly); av=avma; xr=cgetr(ly+1); affir(x,xr);
  affrr(divrr(xr,y),z); avma=av; return z;
}

GEN
divri(GEN x, GEN y)
{
  GEN yr,z;
  long av,lx,s=signe(y);

  if (!s) err(diver8);
  if (!signe(x))
  {
    const long ex = expo(x) - expi(y) + HIGHEXPOBIT;

    if (ex<0) err(diver12);
    z=cgetr(3); z[1]=ex; z[2]=0; return z;
  }

  if (lg(y)==3 && y[2]>0)
    return (s>0) ? divrs(x,y[2]) : divrs(x,-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)
{
  long av = avma,tetpil;
  GEN p1 = resii(x,y);

  if (signe(p1)>=0) return p1;
  tetpil=avma; p1 = (signe(y) > 0) ? addii(p1,y) : subii(p1,y);
  return gerepile(av,tetpil,p1);
}

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,k,lx,ex,garde,sh,s=signe(x);
  GEN z;

  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<lx; i++) z[i]=divll(x[i],y);

  /* we may have hiremainder != 0 ==> garde */
  garde=divll(0,y); sh=bfffo(z[2]); ex=expo(x)-sh;
  if ( (-ex) > HIGHEXPOBIT) err(diver7);
  z[1] = evalsigne(s) | evalexpo(ex);
  if (sh)
  {
    shiftl(garde,sh); k=hiremainder;
    for (i=lx-1; i>=2; i--) { z[i]=shiftl(z[i],sh)+k; k=hiremainder; }
  }
  return z;
}

/* 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.
 */
GEN
dvmdii(GEN x, GEN y, GEN *z)
{
  long sx=signe(x),sy=signe(y);
  long av,av1,lx,ly,lz,i,j,sh,k,k1,saux;
  ulong si,qp;
  GEN p1,p2,p3;
  GEN *gptr[2];

  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 (z == ONLY_REM) return icopy(x);
    if (z) *z=icopy(x);
    return gzero;
  }
  av=avma; if (sx<0) sy = -sy;
  if (ly==3)
  {
    si=y[2];
    if (si > (ulong)x[2])
    {
      p1=cgeti(lx-1); p2=p1-1; hiremainder=x[2];
      for (i=3; i<lx; i++) p2[i]=divll(x[i],si);
      ly=0;
    } 
    else
    {
      p1=cgeti(lx); hiremainder=0;
      for (i=2; i<lx; i++) p1[i]=divll(x[i],si);
    }
    if (z == ONLY_REM)
    {
      avma=av; if (!hiremainder) return gzero;
      p2=cgeti(3); p2[1] = evalsigne(sx) | evallgefint(3);
      p2[2]=hiremainder; return p2;
    }
    /* here lx > 2 */
    if (ly || lx != 3) { p1[1]=p1[0]; setsigne(p1,sy); }
    else { avma=av; p1=gzero; }

    if (!z) return p1;
    if (!hiremainder) { *z=gzero; return p1; }
    p2=cgeti(3); p2[1] = evalsigne(sx) | evallgefint(3);
    p2[2]=hiremainder; *z=p2; return p1;
  }

  p1=cgeti(lx); sh=bfffo(y[2]);
  if (sh)
  {
    p2=cgeti(ly); p3=p2-1; k=shiftl(y[2],sh);
    for (i=3; i<ly; i++)
    {
      k1=shiftl(y[i],sh); p3[i]=k+hiremainder; k=k1;
    }
    p3[ly]=k; k=0; p3=p1-1;
    for (i=2; i<lx; i++)
    {
      k1=shiftl(x[i],sh); p3[i]=k+hiremainder; k=k1;
    }
    p3[lx]=k;
  }
  else { p1[1]=0; for (j=2; j<lx; j++) p1[j]=x[j]; p2=y; }

  si=p2[2]; saux=p2[3]; p3 = p1+1;
  for (i=1; i<=lz+1; i++)
  {
    if (p1[i]==si)
    {
      qp=(long)MAXULONG; k=addll(si,p3[i]);
    }
    else
    {
      hiremainder=p1[i]; qp=divll(p3[i],si);
      overflow=0; k=hiremainder;
    }
    if (!overflow)
    {
      long k3 = subll(mulll(qp,saux), p1[i+2]);
      long k4 = subllx(hiremainder,k);

      while (!overflow && k4) { qp--; k3=subll(k3,saux); k4=subllx(k4,si); }
    }
    hiremainder=0;
    for (j=ly+i-2; j>i; j--)
    {
      p1[j] = subll(p1[j], addmul(qp,p2[j+1-i]));
      hiremainder+=overflow;
    }
    if ((ulong)p1[i] < hiremainder)
    {
      overflow=0; qp--;
      for (j=ly+i-2; j>i; j--) p1[j] = addllx(p1[j],p2[j+1-i]);
    }
    p1[i]=qp;
  }

  av1=avma;
  if (z != ONLY_REM)
  {
    long lp3;

    if (p1[1]) /* we know lz >=0 */
    {
      p3=cgeti(lp3=lz+3); p2=p1-1;
      for (i=2; i<lp3; i++) p3[i]=p2[i];
    }
    else
    {
      p3=cgeti(lp3=lz+2);
      if (!lz) sy=0; else for (i=2; i<lp3; i++) p3[i]=p1[i];
    }
    p3[1] = sy ? evallgefint(lp3) | evalsigne(sy) : evallgefint(2);
    if (!z) return gerepile(av,av1,p3);
  }

  j=lz+2; while (j<lx && !p1[j]) j++;
  if (j==lx) p2=gzero;
  else
  {
    p2=cgeti(lx-j+2); p2[1]=p2[0];
    if (!sh) for (i=2; j<lx; j++,i++) p2[i]=p1[j];
    else
    {
      hiremainder=0; k1=shiftlr(p1[j++],sh); k=hiremainder;
      if (k1) { p2[2]=k1; i=3; }
      else
      {
	p2[1]=p2[0]-1; p2++; avma+=BYTES_IN_LONG;
	p2[1]=p2[0]; i=2;
      }
      while (j<lx)
      {
	p2[i++]=shiftlr(p1[j++],sh)+k;
	k=hiremainder;
      }
    }
    setsigne(p2,sx);
  }
  if (z == ONLY_REM) return gerepile(av,av1,p2);

  *z=p2; gptr[0]=&p3; gptr[1]=z;
  gerepilemanysp(av,av1,gptr,2);
  return p3;
}

GEN
divrr(GEN x, GEN y)
{
  long sx=signe(x), sy=signe(y), lx,ly,lz,lzz,ex,ex1,i,z0;
  ulong remnder,si,saux,j;
  GEN z,p1;

  if (!sy) err(diver9);
  ex = expo(x) - expo(y) + HIGHEXPOBIT;
  if (ex<=0) err(diver10);
  if (ex>EXPOBITS) err(diver11);
  if (!sx)
  {
    z=cgetr(3); z[1]=ex; z[2]=0; return z;
  } 
  if (sy<0) sx = -sx;
  lx=lg(x); ly=lg(y); lz = (lx<=ly)? lx : ly;
  z=cgetr(lz); ex1 = evalsigne(sx)+ex;
  if (ly==3)
  {
    i=x[2]; si = (lx>3)? x[3] : 0;
    if ((ulong)i < (ulong)y[2])
    {
      hiremainder=i; z[2]=divll(si,y[2]);
      z[1]=ex1-1; return z;
    }
    hiremainder = ((ulong)i) >> 1;
    z[2] = (i&1) ? divll( (((ulong)si) >> 1) | HIGHBIT, y[2]):
                   divll( ((ulong)si) >> 1, y[2]);
    z[1]=ex1; return z;
  }

  z0=*z; *z=0; lzz = lz-1; p1 = x+1;
  for (i=1; i<lzz; i++) z[i]=p1[i];
  z[lzz] = (lx>lz) ? x[lz] : 0;

  si=y[2]; saux=y[3]; p1 = z+1;
  for (i=0; i<lzz; i++)
  {
    ulong k,k3,k4,qp;

    if (z[i] != si)
    {
      if ((ulong)z[i] > si) /* can't happen if i=0 */
      {
	overflow=0;
	for (j=lzz; j>=i; j--) z[j] = subllx(z[j],y[j-i+2]);
	do z[j--]++; while (j && !z[j]);
      }
      hiremainder=z[i]; qp=divll(p1[i],si);
      overflow=0; k=hiremainder;
    }
    else
    {
      qp=(long) MAXULONG; k=addll(si,p1[i]);
    }

    if (!overflow)
    {
      k3 = subll(mulll(qp,saux), z[i+2]);
      k4 = subllx(hiremainder,k);
      while (!overflow && k4) { qp--; k3=subll(k3,saux); k4=subllx(k4,si); }
    }
    if (lz+1-i<ly) mulll(qp,y[lz+1-i]);
    else           hiremainder = 0;
    for (j=min(lzz,ly+i-2); j>i; j--)
    {
      z[j] = subll(z[j], addmul(qp,y[j+1-i]));
      hiremainder += overflow;
    }
    if ((ulong)z[i] != hiremainder)
    {
      if ((ulong)z[i] < hiremainder)
      {
	overflow=0; qp--;
	for (j=lzz; j>i; j--) z[j]=addllx(z[j], y[j+1-i]);
      }
      else
      {
	z[i] -= hiremainder;
	while (z[i]) 
	{
	  overflow=0; qp++;
	  if (!qp) 
	  {
	    j=i-1; do z[j--]++; while (j && !z[j]);
	  }
	  for (j=lzz; j>i; j--) z[j]=subllx(z[j],y[j+1-i]);
	  z[i]-=overflow;
	}
      }
    }
    z[i]=qp;
  }

  for (j=lzz; j>=2; j--) z[j]=z[j-1];
  if (*z)
  {
    remnder=HIGHBIT;
    for (j=2; j<lz; j++) { z[j]=shiftlr(z[j],1)+remnder; remnder=hiremainder; }
  }
  else ex1--;
  z[1]=ex1; *z=z0; return z;
}
#endif /* !defined(__M68K__) */

/* The following ones are not in mp.s (mulii is, with a different algorithm) */

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 gerepileupto(av,res);
    if (z) *z = res; else cgiv(res);
    return qu;
  }

  tetpil=avma;
  if (z == ONLY_REM)
  {
    res = (signe(y) > 0) ? addii(res,y) : subii(res,y);
    return gerepile(av,tetpil,res);
  }
  qu = addsi(-signe(y),qu);
  if (!z) return gerepile(av,tetpil,qu);

  *z = (signe(y) > 0) ? addii(res,y) : subii(res,y);
  gptr[0]=&qu; gptr[1]=z; gerepilemanysp(av,tetpil,gptr,2);
  return qu;
}  

/* 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)<vy) err(talker,"impossible division in diviirev");
    y=shifti(y,-vy); x=shifti(x,-vy); a-=(vy>>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;
    
    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((i<lx)&&(!z[i])) i++;
  if (i==lx) {avma=av; return gzero;}
  y=cgeti(lx-i+2); y[1]=evalsigne(1)|evallgefint(lx-i+2); j=2;
  for ( ; i<lx; i++) y[j++]=z[i];
  return gerepile(av,tetpil,y);
}

GEN
diviiexactfullrev(GEN x, GEN y)
/* Find z such that x=y*z knowing that y divides x */
{
  long lx,lz,ly,vy,av=avma,tetpil,i,j,ii,sx=signe(x),sy=signe(y);
  ulong binv,q;
  GEN z;
  
  if (!sy) err(dvmer1);
  if (!sx) return gzero;
/* make y odd */
  vy=vali(y);
  if (vy)
  {
    if (vali(x)<vy) err(talker,"impossible division in diviirev");
    y=shifti(y,-vy); x=shifti(x,-vy);
  }
  else x=icopy(x); /* necessary because we destroy x */
/* now y is odd */
  ly=lgefint(y); lx=lgefint(x);
  if (ly>lx) err(talker,"impossible division in diviirev");
  binv=invrev(y[ly-1]);
  i=2; while (i<ly && y[i]==x[i]) i++;
  lz=(i==ly || y[i]<x[i]) ? lx-ly+3 : lx-ly+2;
  z=cgeti(lz); 
  for (ii=lx-1,i=lz-1; i>=2; i--,ii--)
  {
    long limj;
    
    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((i<lz)&&(!z[i])) i++;
  if (i==lz) err(talker,"bug in diviiexact");
  y=cgeti(lz-i+2); y[1]=evalsigne(sx*sy) | evallgefint(lz-i+2); j=2;
  for ( ; i<lz; i++) y[j++]=z[i];
  return gerepile(av,tetpil,y);
}

GEN
diviiexact2(GEN x, GEN y)
/* Find z such that x=y*z assuming y divides x (which is not checked) */
{
  long sx=signe(x),sy=signe(y),av=avma,tetpil,lyinv,lpr,a,lx,ly,lz,lzs,lp1;
  long i,j,vy;
  ulong aux;
  GEN yinv,p1,z,xinit,yinit;
  
  if (!sy) err(dvmer1);
  if (!sx) return gzero;
  xinit=x; yinit=y;
  setsigne(y,1);setsigne(x,1);
/* make y odd */
  vy=vali(y);
  if (vy)
  {
    if (vali(x)<vy) err(talker,"impossible division in diviirev");
    y=shifti(y,-vy); x=shifti(x,-vy);
  }
/* now y is odd */
  ly=lgefint(y); lx=lgefint(x);
  if (lx<ly) err(talker,"not an exact division in diviiexact");
  a=lx-ly+1; lz=a+2;
  aux=invrev(y[ly-1]);
  if (aux & HIGHBIT) {yinv=stoi(aux^HIGHBIT);yinv[2]|=HIGHBIT;}
  else yinv=stoi(aux); /* inverse of y mod 2^32 (or 2^64) */
  lpr=1; /* current accuracy */
  while(lpr<a)
  {
    long lycut;
    GEN ycut;
    
    lyinv=lgefint(yinv);
    lycut=min(2*lpr+2,ly);
    ycut=cgeti(lycut); ycut[1]=evalsigne(1) | evallgefint(lycut);
    for(i=2; i<lycut; i++) ycut[i]=y[ly+i-lycut];
    p1=mulii(yinv,ycut); lp1=lgefint(p1);
    if (lp1>lpr+2)
    {
      long lp1cut,lynew,lp2;
      GEN p1cut,p2,ynew;
      
      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; i<lzs; i++) z[i]=yinv[i+lyinv-lzs];
  p1=mulii(z,x); lp1=lgefint(p1); lzs=min(lz,lp1);
  z=cgeti(lzs);
  for (i=2; i<lzs; i++) z[i]=p1[i+lp1-lzs];
  i=2; while (i<lzs && !z[i]) i++;
  if (i==lzs) err(talker,"bug in diviiexact");
  tetpil=avma; p1=cgeti(lzs-i+2);
  p1[1]=evalsigne(sx*sy) | evallgefint(lzs-i+2);
  for (j=2; j<=lzs-i+1; j++) p1[j]=z[j+i-2];
  setsigne(xinit,sx);setsigne(yinit,sy);
  return gerepile(av,tetpil,p1);
}

long
smodsi(long x, GEN y)
{
  if (x<0) err(talker,"negative small integer in smodsi");
  divsi(x,y); return hiremainder;
}

/* x and y are integers. Return 1 if |x| == |y|, 0 otherwise */
int
absi_equal(GEN x, GEN y)
{
  long lx,i;

  if (!signe(x)) return !signe(y);
  if (!signe(y)) return 0;

  lx=lgefint(x); if (lx != lgefint(y)) return 0;
  i=2; while (i<lx && x[i]==y[i]) i++;
  return (i==lx);
}

/* x and y are integers. Return sign(|x| - |y|) */
int
absi_cmp(GEN x, GEN y)
{
  long lx,ly,i;

  if (!signe(x)) return signe(y)? -1: 0;
  if (!signe(y)) return 1;

  lx=lgefint(x); ly=lgefint(y);
  if (lx>ly) return 1;
  if (lx<ly) return -1;
  i=2; while (i<lx && x[i]==y[i]) i++;
  if (i==lx) return 0;
  return ((ulong)x[i] > (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<ey) return -1;

  lx=lg(x); ly=lg(y); lz = (lx<ly)?lx:ly;
  i=2; while (i<lz && x[i]==y[i]) i++;
  if (i<lz) return ((ulong)x[i] > (ulong)y[i])? 1: -1;
  if (lx>=ly)
  {
    while (i<lx && !x[i]) i++;
    return (i==lx)? 0: 1;
  }
  while (i<ly && !y[i]) i++;
  return (i==ly)? 0: -1;
}

/********************************************************************/
/**                                                                **/
/**               INTEGER MULTIPLICATION (KARATSUBA)               **/
/**   (adapted from an implementation of X. Gourdon for rootpol.c) **/
/**                                                                **/
/********************************************************************/

#define SQRI_LIMIT 30  /* probably not optimal */
#define MULII_LIMIT 30

/* 0 < nx <= ny (num. of digits). x and y are not GENs. See mulii. */
static GEN
muliispec(GEN x, GEN y, long nx, long ny)
{ 
  const long lz = nx+ny+2, nyy = ny-1, nxx = nx-1;
  GEN z = cgeti(lz), z2;
  long i,j,p1;

  z[1] = evallgefint(lz) | evalsigne(1);
  z+=2; /* strip codewords */

  hiremainder=0; p1=x[nxx]; z2 = z + nx;
  for (i=nyy; i>=0; i--) z2[i]=addmul(p1,y[i]);
  z[nxx]=hiremainder;

  for (j=nxx-1; j>=0; j--)
  {
    hiremainder=0; p1=x[j];
    for (i=ny+j; i>j; i--)
    {
      const long p2=addmul(p1,y[i-1-j]);

      z[i]=addll(p2,z[i]); hiremainder+=overflow;
    }
    z[j]=hiremainder;
  }
  z-=2; /* back to normalcy */

  if (z[2]) return z;

  z[2]=z[1]-1; z[1]=z[0]-1; avma+=BYTES_IN_LONG;
  return z+1;
}

/* need nx >= ny */
static GEN
addiispec(GEN x, GEN y, long nx, long ny)
{
  long i,j;
  GEN z, p1;

  z=cgeti(nx+3); overflow=0; p1=z+3;
  for (i=ny-1,j=nx-1; i>=0; i--,j--) p1[j]=addllx(x[j],y[i]);
  if (overflow)
  {
    for (; j>=0 && x[j]==(long)MAXULONG; j--) p1[j]=0;
    if (j==-1)
    { 
      z[2]=1; z[1]=evalsigne(1) | evallgefint(nx+3);
      return z;
    }
    p1[j]=x[j]+1; j--;
  }
  for (; j>=0; j--) p1[j]=x[j];
  z[1]=z[0]-1; z[2]=evalsigne(1) | evallgefint(nx+2);
  avma += BYTES_IN_LONG; return z+1;
}

/* fast product (Karatsuba) of integers a,b. These are not real GENs, a+2,
 * b+2 were sent instead. We assume na >= nb (number of digits). 
 * Only c, c0, c1, c2 are genuine GEN.
 */
static GEN
quickmulii(GEN a, GEN b, long na, long nb)
{
  GEN a0,c,c0,c1;
  long av,n0;

  if (na<MULII_LIMIT) return muliispec(a,b,na,nb);

  av=(na>>1); n0=na-av; na=av;

  av=avma; a0=a+na;
  if (nb>n0)
  {             
    /* nb <= na <= n0, nb <=na */
    GEN b0,c2;

    nb=nb-n0; b0=b+nb;
    c=quickmulii(a,b,na,nb);
    c0=quickmulii(a0,b0,n0,n0);

    c2=addiispec(a0,a,n0,na); na=lgefint(c2)-2;
    c1=addiispec(b0,b,n0,nb); nb=lgefint(c1)-2;

    if (na>=nb)
      c1=quickmulii(c2+2,c1+2,na,nb);
    else
      c1=quickmulii(c1+2,c2+2,nb,na);

    c1=subii(c1,addii(c0,c));
    c=addii(shifti(c,(n0<<(TWOPOTBITS_IN_LONG+1))),
	    shifti(c1,(n0<<TWOPOTBITS_IN_LONG)));
  }
  else
  {
    if (na>=nb)
      c=quickmulii(a,b,na,nb);
    else
      c=quickmulii(b,a,nb,na);
    c0=quickmulii(a0,b,n0,nb);
    c=shifti(c,(n0<<TWOPOTBITS_IN_LONG));
  }
  c = addii(c,c0);

  /* fast gerepile, we know av and c don't overlap */
  na = lg(c)*sizeof(long); avma = av - na;
  memcpy((char *)avma, (char *)c, na);
  return (GEN) avma;
}

/* the actual operations will take place on a+2 and b+2 : we strip the
 * codewords
 */
#ifndef __M68K__ /* the one in mp.s won't include Karatsuba */
GEN
mulii(GEN a,GEN b)
{
  long sa,sb,na,nb;
  GEN z;

  sa=signe(a); if (!sa) return gzero;
  sb=signe(b); if (!sb) return gzero;

  na=lgefint(a)-2; nb=lgefint(b)-2;
  sa = sb<0 ? -sa: sa;
  if (na<nb) { z=a; a=b; b=z; sb=na; na=nb; nb=sb; }
  a+=2; b+=2;
  if (na<MULII_LIMIT)
    z = muliispec(a,b,na,nb);
  else
    z = quickmulii(a,b,na,nb);
  setsigne(z,sa); return z;
}

GEN
mymulii(GEN a,GEN b)
{
  long sa,sb,na,nb;
  GEN z;

  sa=signe(a); if (!sa) return gzero;
  sb=signe(b); if (!sb) return gzero;

  na=lgefint(a)-2; nb=lgefint(b)-2;
  sa = sb<0 ? -sa: sa;
  if (na<nb) { z=a; a=b; b=z; sb=na; na=nb; nb=sb; }
  a+=2; b+=2;
  z = muliispec(a,b,na,nb);
  setsigne(z,sa); return z;
}

#endif /* !defined(__M68K__) */

static GEN
sqrispec(GEN x, long nx)
{ 
  const long lz = (nx+1)<<1, nxx = nx-1;
  GEN z = cgeti(lz), z2;
  long i,j,p1;

  z[1] = evallgefint(lz) | evalsigne(1);
  z+=2;

  hiremainder=0; p1=x[nxx]; z2 = z + nx;
  for (i=nxx; i>=0; i--) z2[i]=addmul(p1,x[i]);
  z[nxx]=hiremainder;

  for (j=nxx-1; j>=0; j--)
  {
    hiremainder=0; p1=x[j];
    for (i=nx+j; i>=j+1; i--)
    {
      const long p2=addmul(p1,x[i-1-j]);

      z[i]=addll(p2,z[i]); hiremainder+=overflow;
    }
    z[j]=hiremainder;
  }
  z-=2;

  if (z[2]) return z;

  z[2]=z[1]-1; z[1]=z[0]-1; avma+=BYTES_IN_LONG;
  return z+1;
}

static GEN
quicksqri(GEN a, long na)
{
  GEN a0,c,c0,c1;
  long av,n0;

  if (na<SQRI_LIMIT) return sqrispec(a,na);
  av=(na>>1); n0=na-av; na=av;

  av=avma; a0=a+na;

  c=quicksqri(a,na);
  c0=quicksqri(a0,n0);
  c1=addiispec(a0,a,n0,na);

  c1=quicksqri(c1+2,lgefint(c1)-2);
  c1=subii(c1,addii(c0,c));
  c=addii(shifti(c,(n0<<(TWOPOTBITS_IN_LONG+1))),
	  shifti(c1,(n0<<TWOPOTBITS_IN_LONG)));
  c = addii(c,c0);

  /* fast gerepile, we know av and c don't overlap */
  na = lg(c)*sizeof(long); avma = av - na;
  memcpy((char *)avma, (char *)c, na);
  return (GEN) avma;
}

/* see mulii */
GEN
sqri(GEN a)
{
  long sa=signe(a),na;

  if (!sa) return gzero;
  na=lgefint(a)-2; a+=2;
  if (na<SQRI_LIMIT)
    return sqrispec(a,na);
  return quicksqri(a,na);
}

#define MULRR_LIMIT 5

static GEN
karamulrr1(GEN x, GEN y)
{
  long sx,sy,ex,ey;
  long i,i1,i2,lx=lg(x),ly=lg(y),lz,e,flag,lzpf,garde;
  long lz2,lz3,lz4,av;
  GEN z,lo,lo1,lo2,hi,xs,ys;

  if (lx>ly) { lz=ly; z=x; x=y; y=z; flag=1; } else { lz=lx; flag = (lx!=ly); }
  if (lz<MULRR_LIMIT) return mulrr(x,y);
  lzpf=lz+flag;
  sx=signe(x); sy=signe(y); ex=expo(x); ey=expo(y);
  e = ex+ey+HIGHEXPOBIT; if (e>=EXPOBITS) err(muler4);
  if (e<0) err(muler5);
  if (!sx || !sy) { z=cgetr(3); z[2]=0; z[1]=e; return z; }
  if (sy<0) sx = -sx;
  z=cgetr(lz); av=avma;
  lz2=(lz>>1)+2; lz3=(lz+1)>>1; /* lz2+lz3==lz+2 */
  i1=lz2; while ((i1<lz) && (!x[i1])) i1++;
  i2=lz2; while ((i2<lzpf) && (!y[i2])) i2++;
  xs=x+2; ys=y+2;
  hi=quickmulii(xs,ys,lz2-2,lz2-2); 
  if (i1<lz) lo1=quickmulii(ys,x+i1,lz2-2,lz-i1); else lo1=gzero;
  if (i2<lz) lo2=quickmulii(xs,y+i2,lz2-2,lzpf-i2); else lo2=gzero;

  if (flag) { lo=addii(shifti(lo1,BITS_IN_LONG),lo2); lz3++; }
  else lo=addii(lo1,lo2);
  lz4=lgefint(lo)-lz3;
  if (lz4>0)
  {
    setlgefint(lo,lz4+2);
    hi=addii(hi,lo);
  }
  if (hi[2]&HIGHBIT)
  {
    e++; garde=hi[lz];
    for (i=2; i<lz ; i++) z[i]=hi[i];
  }
  else
  {
    garde=addll(hi[lz],hi[lz]);
    for (i=lz-1; i>=2; i--) z[i]=addllx(hi[i],hi[i]);
  }
  if (garde&HIGHBIT)
  {
/* round to nearest */
    i=lz-1;
    z[i]++; while (z[i]==0) z[--i]++;
  }
  z[1]=evalsigne(sx) | e;
  avma=av; return z;
}

static GEN
karamulrr2(GEN x, GEN y)
{
  long sx,sy,ex,ey;
  long i,lx=lg(x),ly=lg(y),lz,e,flag,lzpf,garde;
  long av;
  GEN z,hi;

  if (lx>ly) { lz=ly; z=x; x=y; y=z; flag=1; } else { lz=lx; flag = (lx!=ly); }
  if (lz<MULRR_LIMIT) return mulrr(x,y);
  lzpf=lz+flag;
  sx=signe(x); sy=signe(y); ex=expo(x); ey=expo(y);
  e = ex+ey+HIGHEXPOBIT; if (e>=EXPOBITS) err(muler4);
  if (e<0) err(muler5);
  if (!sx || !sy) { z=cgetr(3); z[2]=0; z[1]=e; return z; }
  if (sy<0) sx = -sx;
  z=cgetr(lz); av=avma;
  hi=quickmulii(y+2,x+2,lzpf-2,lz-2);
  if (hi[2]&HIGHBIT)
  {
    e++; garde=hi[lz];
    for (i=2; i<lz ; i++) z[i]=hi[i];
  }
  else
  {
    garde=addll(hi[lz],hi[lz]);
    for (i=lz-1; i>=2; i--) z[i]=addllx(hi[i],hi[i]);
  }
  if (garde&HIGHBIT)
  {
/* round to nearest */
    i=lz-1;
    z[i]++; while (z[i]==0) z[--i]++;
  }
  z[1]=evalsigne(sx) | e;
  avma=av; return z;
}
  
GEN
karamulrr(GEN x, GEN y, long flag)
{
  switch(flag)
  {
    case 1: return karamulrr1(x,y);
    case 2: return karamulrr2(x,y);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}    

GEN
karamulir(GEN x, GEN y, long flag)
{
  long sx=signe(x),av,lz,i;
  GEN z,temp,z1;

  if (!sx) return gzero;
  lz=lg(y); z=cgetr(lz);
  av=avma; temp=cgetr(lz+1);
  affir(x,temp);
  z1=karamulrr(temp,y,flag);
  for (i=1; i<lz; i++) z[i]=z1[i];
  avma=av;
  return z;
}

#ifdef LONG_IS_64BIT

#if   BYTE_ORDER == ALPHA_ENDIAN
#else
   error.... unknown machine
#endif

GEN
dbltor(double x)
{
  GEN z;
  long ex;
  union { double f; ulong i; } fi;
  const int df_mant_len = 52;  /* mantissa bits (excl. hidden bit) */
  const int df_exp_mid = 0x3ff; /* exponent bias */
  const int df_expo_len = 11; /* number of bits of exponent */
  
  if (x==0) { z=cgetr(3); z[2]=0; z[1]=HIGHEXPOBIT-308; return z; }
  fi.f = x; z=cgetr(3);
  ex = ((fi.i & HIGHBITM1) >> df_mant_len) - df_exp_mid;
  z[1] = (x<0) ? evalsigne(-1) | evalexpo(ex) : evalsigne(1) | evalexpo(ex);  
  z[2] = (fi.i << df_expo_len) | HIGHBIT;
  return z;
}

double
rtodbl(GEN x)
{
  long ex,s=signe(x);
  ulong a;
  union { double f; ulong i; } fi;
  const int df_mant_len = 52;  /* mantissa bits (excl. hidden bit) */
  const int df_exp_mid = 0x3ff; /* exponent bias */
  const int df_expo_len = 11; /* number of bits of exponent */
  
  if (typ(x)==t_INT && !s) return 0.0;
  if (typ(x)!=t_REAL) err(typeer,"rtodbl");
  if (!s || (ex=expo(x)) < - df_exp_mid) return 0.0;

  /* start by rounding to closest */
  a = ( x[2] & HIGHBITM1 ) + 0x400;
  if (a & HIGHBIT) { ex++; a=0; }  
  if (ex >= df_exp_mid) err(rtodber);
  fi.i = ((ex + df_exp_mid) << df_mant_len) | shiftlr(a, df_expo_len);
  if (s<0) fi.i |= HIGHBIT;
  return fi.f;
}

#else

#if   BYTE_ORDER == LITTLE_ENDIAN
#  define INDEX0 1
#  define INDEX1 0
#elif BYTE_ORDER == BIG_ENDIAN
#  define INDEX0 0
#  define INDEX1 1
#else
   error.... unknown machine
#endif

GEN
dbltor(double x)
{
  GEN z;
  long ex;
  union { double f; ulong i[2]; } fi;
  const int df_mant_len = 52;  /* mantissa bits (excl. hidden bit) */
  const int df_exp_mid = 0x3ff; /* exponent bias */
  const int df_shift = df_mant_len-32;
  const int df_expo_len = 11; /* number of bits of exponent */
  
  if (x==0) { z=cgetr(3); z[2]=0; z[1]=HIGHEXPOBIT-308; return z; }
  fi.f = x; z=cgetr(4);
  ex = ((fi.i[INDEX0] & HIGHBITM1) >> df_shift) - df_exp_mid;
  z[1] = (x<0) ? evalsigne(-1) | evalexpo(ex) : evalsigne(1) | evalexpo(ex);
  z[3] = shiftl(fi.i[INDEX1],df_expo_len);
  z[2] = hiremainder | HIGHBIT | (fi.i[INDEX0] << df_expo_len);
  return z;
}

double
rtodbl(GEN x)
{
  long ex,s=signe(x),lx=lg(x);
  ulong a,b;
  union { double f; ulong i[2]; } fi;
  const int df_mant_len = 52;  /* mantissa bits (excl. hidden bit) */
  const int df_exp_mid = 0x3ff; /* exponent bias */
  const int df_shift = df_mant_len-32;
  const int df_expo_len = 11; /* number of bits of exponent */
  
  if (typ(x)==t_INT && !s) return 0.0;
  if (typ(x)!=t_REAL) err(typeer,"rtodbl");
  if (!s || (ex=expo(x)) < - df_exp_mid) return 0.0;

  /* start by rounding to closest */
  a = x[2] & HIGHBITM1;
  if (lx > 3)
  {
    b=x[3]+0x400UL; if(b<0x400UL) a++;
    if (a & HIGHBIT) { ex++; a=0; }
  }
  else b = 0;
  if (ex >= df_exp_mid) err(rtodber);
  a = shiftlr(a, df_expo_len);
  ex += df_exp_mid; a |= (ex << df_shift);
  if (s<0) a |= HIGHBIT;
  fi.i[INDEX0] = a;
  fi.i[INDEX1] = hiremainder | (b >> df_expo_len);
  return fi.f;
}
#endif

/* Old cgiv without reference count (which was not used anyway)
 * Should be a macro.
 */
void
cgiv(GEN x)
{
  if (x == (GEN) avma)
    avma = (long) (x+lg(x));
}
