/*
 *   This file contains declarations/definitions of functions that
 *   _can_ be inlined.
 */
/* $Id: mpinline.h,v 2.0.0.2 1997/12/14 20:11:49 karim Exp karim $ */

#ifndef INLINE
GEN    absi(GEN x);
GEN    absr(GEN x);
void   addsii(long x, GEN y, GEN z);
void   addssz(long x, long y, GEN z);
void   affii(GEN x, GEN y);
void   affsi(long s, GEN x);
void   affsr(long s, GEN x);
GEN    cgetg(long x, long y);
GEN    cgeti(long x);
GEN    cgetr(long x);
int    cmpir(GEN x, GEN y);
int    cmpsr(long x, GEN y);
int    divise(GEN x, GEN y);
long   divisii(GEN x, long y, GEN z);
void   divisz(GEN x, long y, GEN z);
void   divrrz(GEN x, GEN y, GEN z);
void   divsiz(long x, GEN y, GEN z);
GEN    divss(long x, long y);
void   divssz(long x, long y, GEN z);
void   dvmdiiz(GEN x, GEN y, GEN z, GEN t);
GEN    dvmdis(GEN x, long y, GEN *z);
void   dvmdisz(GEN x, long y, GEN z, GEN t);
GEN    dvmdsi(long x, GEN y, GEN *z);
void   dvmdsiz(long x, GEN y, GEN z, GEN t);
GEN    dvmdss(long x, long y, GEN *z);
void   dvmdssz(long x, long y, GEN z, GEN t);
long   expi(GEN x);
GEN    icopy(GEN x);
long   itos(GEN x);
GEN    modis(GEN x, long y);
GEN    mpadd(GEN x, GEN y);
void   mpaff(GEN x, GEN y);
int    mpcmp(GEN x, GEN y);
GEN    mpdiv(GEN x, GEN y);
int    mpdivis(GEN x, GEN y, GEN z);
GEN    mpmul(GEN x, GEN y);
GEN    mpsub(GEN x, GEN y);
void   mulsii(long x, GEN y, GEN z);
void   mulssz(long x, long y, GEN z);
GEN    negi(GEN x);
GEN    negr(GEN x);
GEN    rcopy(GEN x);
void   resiiz(GEN x, GEN y, GEN z);
GEN    resis(GEN x, long y);
GEN    ressi(long x, GEN y);
GEN    shiftr(GEN x, long n);
GEN    stoi(long x);
GEN    subii(GEN x, GEN y);
GEN    subir(GEN x, GEN y);
GEN    subri(GEN x, GEN y);
GEN    subrr(GEN x, GEN y);
GEN    subsi(long x, GEN y);
GEN    subsr(long x, GEN y);
long   vali(GEN x);

double gtodouble(GEN x);
long   smodis(GEN x, long y);
long   addssmod(long a, long b, long p);
long   subssmod(long a, long b, long p);
long   mulssmod(ulong a, ulong b, ulong c);
long   divssmod(long a, long b, long p);

#endif  /* !defined(INLINE) */

/* THE FOLLOWING ONES ARE IN mp.s */
#if defined(INLINE) && !defined(__M68K__)

#ifdef MEMSTEP
   void checkmemory(long z); /* in init.c */
#else
#  define checkmemory(z) if (z<bot) err(errpile); avma=z;
#endif
#define new_chunk(x) (((GEN) avma) - x)

INLINE GEN
cgetg(long x, long y)
{
  const GEN z = new_chunk(x);

  checkmemory((ulong)z);
  z[0]=evaltyp(y) | evallg(x);
  return z;
}

INLINE GEN
cgeti(long x)
{
  const GEN z = new_chunk(x);

  checkmemory((ulong)z);
  z[0] = evaltyp(t_INT) | evallg(x);
  return z;
}

INLINE GEN
cgetr(long x)
{
  const GEN z = new_chunk(x);

  checkmemory((ulong)z);
  z[0] = evaltyp(t_REAL) | evallg(x);
  return z;
}

/* cannot do memcpy because sometimes x and y overlap */
INLINE GEN
icopy(GEN x)
{
  long lx = lgefint(x);
  const GEN y = cgeti(lx);

  while (--lx) y[lx]=x[lx];
  return y;
}

INLINE GEN
rcopy(GEN x)
{
  long lx = lg(x);
  const GEN y = cgetr(lx);

  while (--lx) y[lx]=x[lx];
  return y;
}

INLINE GEN
negi(GEN x)
{
  const long s=signe(x);
  GEN y;

  if (!s) return gzero;
  y=icopy(x); setsigne(y,-s);
  return y;
}

INLINE GEN
negr(GEN x)
{
  const GEN y=rcopy(x);
  setsigne(y,-signe(x)); return y;
}


INLINE GEN
absi(GEN x)
{
  GEN y;

  if (!signe(x)) return gzero;
  y=icopy(x); setsigne(y,1);
  return y;
}

INLINE GEN
absr(GEN x)
{
  const GEN y=rcopy(x);

  if (signe(x)<0) setsigne(y,1);
  return y;
}

INLINE long
expi(GEN x)
{
  const long lx=lgefint(x);
  return lx==2 ? -HIGHEXPOBIT : ((lx-2)<<TWOPOTBITS_IN_LONG)-bfffo(x[2])-1;
}

INLINE GEN
stoi(long x)
{
  static long pcode1 = evalsigne(1) | evallgefint(3);
  static long mcode1 = evalsigne(-1) | evallgefint(3);
  GEN y;

  if (!x) return gzero;
  y=cgeti(3);
  if (x>0) { y[1] = pcode1; y[2] = x; }
  else { y[1] = mcode1; y[2] = -x; }
  return y;
}

INLINE long
itos(GEN x)
{
  const long s=signe(x);
  ulong p1;

  if (!s) return 0;
  if (lgefint(x)>3) err(affer2);
  p1=x[2]; if (p1 >= (ulong)HIGHBIT) err(affer2);
  return (s>0) ? p1 : -(long)p1;
}

INLINE void
affii(GEN x, GEN y)
{
  long lx;

  if (x==y) return;
  lx=lgefint(x); if (lg(y)<lx) err(affer3);
  while (--lx) y[lx]=x[lx];
}

INLINE void
affsi(long s, GEN x)
{
  static long pcode1 = evalsigne(1) | evallgefint(3);
  static long mcode1 = evalsigne(-1) | evallgefint(3);

  if (!s) { x[1]=2; return; }
  if (lg(x)<3) err(affer1);
  if (s>0) { x[1]=pcode1; x[2] = s; }
  else { x[1]=mcode1; x[2] = -s; }
}

INLINE void
affsr(long s, GEN x)
{
  long l;

  if (!s)
  {
    l = -bit_accuracy(lg(x));
    x[1]=evalexpo(l); x[2]=0; return;
  }
  if (s<0) { x[1] = evalsigne(-1); s = -s; }
  else x[1] = evalsigne(1);
  l=bfffo(s); x[1] |= evalexpo((BITS_IN_LONG-1)-l);
  x[2] = s<<l; for (l=3; l<lg(x); l++) x[l]=0;
}

INLINE void
mpaff(GEN x, GEN y)
{
  if (typ(x)==t_INT)
    if (typ(y)==t_INT) affii(x,y); else affir(x,y);
  else
    if (typ(y)==t_INT) affri(x,y); else affrr(x,y);
}

INLINE GEN
shiftr(GEN x, long n)
{
  const long l = expo(x)+n;
  const GEN y = rcopy(x);

  if (l>=HIGHEXPOBIT || l<-HIGHEXPOBIT) err(shier2);
  setexpo(y,l); return y;
}

INLINE int
cmpir(GEN x, GEN y)
{
  long av;
  GEN z;

  if (!signe(x)) return -signe(y);
  av=avma; z=cgetr(lg(y)); affir(x,z); avma=av;
  return cmprr(z,y); /* cmprr does no memory adjustment */
}

INLINE int
cmpsr(long x, GEN y)
{
  long av;
  GEN z;

  if (!x) return -signe(y);
  av=avma; z=cgetr(3); affsr(x,z); avma=av;
  return cmprr(z,y);
}	

INLINE void
addssz(long x, long y, GEN z)
{
  if (typ(z)==t_INT) gops2ssz(addss,x,y,z);
  else
  {
    const long av=avma;
    const GEN p1=cgetr(lg(z));

    affsr(x,p1); affrr(addrs(p1,y),z); avma=av;
  }
}

INLINE GEN
subii(GEN x, GEN y)
{
  long s;
  GEN z;

  if (x==y) return gzero;
  s=signe(y); setsigne(y,-s); z=addii(x,y);
  setsigne(y,s); return z;
}

INLINE GEN
subrr(GEN x, GEN y)
{
  long s;
  GEN z;

  if (x==y)
  {
    z=cgetr(3); z[1]=HIGHEXPOBIT-(lg(x)<<TWOPOTBITS_IN_LONG);
    z[2]=0; return z;
  }
  s=signe(y); setsigne(y,-s); z=addrr(x,y);
  setsigne(y,s); return z;
}

INLINE GEN
subir(GEN x, GEN y)
{
  const long s=signe(y);
  GEN z;

  setsigne(y,-s); z=addir(x,y); setsigne(y,s); return z;
}

INLINE GEN
subri(GEN x, GEN y)
{
  const long s=signe(y);
  GEN z;

  setsigne(y,-s); z=addir(y,x); setsigne(y,s); return z;
}

INLINE GEN
subsi(long x, GEN y)
{
  const long s=signe(y);
  GEN z;

  setsigne(y,-s); z=addsi(x,y); setsigne(y,s); return z;
}

INLINE GEN
subsr(long x, GEN y)
{
  const long s=signe(y);
  GEN z;

  setsigne(y,-s); z=addsr(x,y); setsigne(y,s); return z;
}

INLINE void
mulssz(long x, long y, GEN z)
{
  if (typ(z)==t_INT) gops2ssz(mulss,x,y,z);
  else
  {
    const long av=avma;
    const GEN p1=cgetr(lg(z));

    affsr(x,p1); mpaff(mulsr(y,p1),z); avma=av;
  }
}

INLINE void
mulsii(long x, GEN y, GEN z)
{
  const long av=avma;
  affii(mulsi(x,y),z); avma=av;
}

INLINE void
addsii(long x, GEN y, GEN z)
{
  const long av=avma;
  affii(addsi(x,y),z); avma=av;
}

INLINE long
divisii(GEN x, long y, GEN z)
{
  const long av=avma;
  affii(divis(x,y),z); avma=av; return hiremainder;
}

INLINE long
vali(GEN x)
{
  long lx,i;

  if (!signe(x)) return -1;
  lx = lgefint(x)-1;
  i=lx; while (i>=2 && !x[i]) i--;
  return ((lx-i)<<TWOPOTBITS_IN_LONG) + vals(x[i]);
}

INLINE GEN
divss(long x, long y)
{
  long p1;

  if (!y) err(diver1);
  hiremainder=0; p1 = divll((ulong)labs(x),(ulong)labs(y));
  if (x<0) { hiremainder = -((long)hiremainder); p1 = -p1; }
  if (y<0) p1 = -p1;
  return stoi(p1);
}

INLINE GEN
dvmdss(long x, long y, GEN *z)
{
  const GEN p1=divss(x,y);
  *z = stoi(hiremainder); return p1;
}

INLINE GEN
dvmdsi(long x, GEN y, GEN *z)
{
  const GEN p1=divsi(x,y);
  *z = stoi(hiremainder); return p1;
}

INLINE GEN
dvmdis(GEN x, long y, GEN *z)
{
  const GEN p1=divis(x,y);
  *z=stoi(hiremainder); return p1;
}

INLINE void
dvmdssz(long x, long y, GEN z, GEN t)
{
  const long av=avma;
  const GEN p1=divss(x,y);

  affsi(hiremainder,t); mpaff(p1,z); avma=av;
}

INLINE void
dvmdsiz(long x, GEN y, GEN z, GEN t)
{
  const long av=avma;
  const GEN p1=divsi(x,y);

  affsi(hiremainder,t); mpaff(p1,z); avma=av;
}

INLINE void
dvmdisz(GEN x, long y, GEN z, GEN t)
{
  const long av=avma;
  const GEN p1=divis(x,y);

  affsi(hiremainder,t); mpaff(p1,z); avma=av;
}

INLINE void
dvmdiiz(GEN x, GEN y, GEN z, GEN t)
{
  const long av=avma;
  GEN p;

  mpaff(dvmdii(x,y,&p),z); mpaff(p,t); avma=av;
}

INLINE GEN
modis(GEN x, long y)
{
  const long av=avma;

  divis(x,y); avma=av;
  if (!hiremainder) return gzero;
  return (signe(x)>0) ? stoi(hiremainder) : stoi(labs(y)+hiremainder);
}

INLINE GEN
ressi(long x, GEN y)
{
  const long av=avma;
  divsi(x,y); avma=av; return stoi(hiremainder);
}

INLINE GEN
resis(GEN x, long y)
{
  const long av=avma;
  divis(x,y); avma=av; return stoi(hiremainder);
}

INLINE void
divisz(GEN x, long y, GEN z)
{
  if (typ(z)==t_INT) gops2gsz(divis,x,y,z);
  else
  {
    const long av=avma;
    const GEN p1=cgetr(lg(z));

    affir(x,p1); affrr(divrs(p1,y),z); avma=av;
  }
}

INLINE void
divsiz(long x, GEN y, GEN z)
{
  const long av=avma;

  if (typ(z)==t_INT) gaffect(divsi(x,y),z);
  else
  {
    const long lz=lg(z);
    const GEN p1=cgetr(lz), p2=cgetr(lz);
    
    affsr(x,p1); affir(y,p2);
    affrr(divrr(p1,p2),z);
  }
  avma=av;
}

INLINE void
divssz(long x, long y, GEN z)
{
  const long av=avma;

  if (typ(z)==t_INT) gaffect(divss(x,y),z);
  else
  {
    const GEN p1=cgetr(lg(z));

    affsr(x,p1); affrr(divrs(p1,y),z);
  }
  avma=av;
}

INLINE void
divrrz(GEN x, GEN y, GEN z)
{
  const long av=avma;
  mpaff(divrr(x,y),z); avma=av;
}

INLINE void
resiiz(GEN x, GEN y, GEN z)
{
  const long av=avma;
  affii(resii(x,y),z); avma=av;
}

INLINE int
divise(GEN x, GEN y)
{
  const long av=avma;
  const GEN p1=resii(x,y);

  avma=av; return signe(p1) ? 0 : 1;
}

INLINE int
mpcmp(GEN x, GEN y)
{
  if (typ(x)==t_INT)
    return (typ(y)==t_INT) ? cmpii(x,y) : cmpir(x,y);
  return (typ(y)==t_INT) ? -cmpir(y,x) : cmprr(x,y);
}

INLINE GEN
mpadd(GEN x, GEN y)
{
  if (typ(x)==t_INT)
    return (typ(y)==t_INT) ? addii(x,y) : addir(x,y);
  return (typ(y)==t_INT) ? addir(y,x) : addrr(x,y);
}

INLINE GEN
mpsub(GEN x, GEN y)
{
  if (typ(x)==t_INT)
    return (typ(y)==t_INT) ? subii(x,y) : subir(x,y);
  return (typ(y)==t_INT) ? subri(x,y) : subrr(x,y);
}

INLINE GEN
mpmul(GEN x, GEN y)
{
  if (typ(x)==t_INT)
    return (typ(y)==t_INT) ? mulii(x,y) : mulir(x,y);
  return (typ(y)==t_INT) ? mulir(y,x) : mulrr(x,y);
}

INLINE GEN
mpdiv(GEN x, GEN y)
{
  if (typ(x)==t_INT)
    return (typ(y)==t_INT) ? divii(x,y) : divir(x,y);
  return (typ(y)==t_INT) ? divri(x,y) : divrr(x,y);
}

INLINE int
mpdivis(GEN x, GEN y, GEN z)
{
  const long av=avma;
  GEN p2;
  const GEN p1=dvmdii(x,y,&p2);

  if (signe(p2)) { avma=av; return 0; }
  affii(p1,z); avma=av; return 1;
}

#endif /* defined(INLINE) && !defined(__M68K__) */
/* THE FOLLOWING ONES ARE NOT IN mp.s */
#if defined(INLINE)

INLINE double
gtodouble(GEN x)
{
  static long reel4[4]={ evaltyp(t_REAL) | evallg(4),0,0,0 };

  if (typ(x)==t_REAL) return rtodbl(x);
  gaffect(x,(GEN)reel4); return rtodbl((GEN)reel4);
}

INLINE long
smodis(GEN x, long y)
{
  const long av=avma;

  divis(x,y); avma=av;
  if (!hiremainder) return 0;
  return (signe(x)>0) ? hiremainder: labs(y)+hiremainder;
}

INLINE long
addssmod(long a, long b, long p)
{
  long res = a + b;
  return (res >= p) ? res - p : res;
}

INLINE long
subssmod(long a, long b, long p)
{
  long res = a - b;
  return (res >= 0) ? res : res + p;
}

INLINE long
mulssmod(ulong a, ulong b, ulong c)
{
  divll(mulll(a,b),c); return hiremainder;
}

INLINE long
divssmod(long a, long b, long p)
{
  long v1 = 0, v2 = 1, v3, r, oldp = p;

  while (b > 1)
  {
    v3 = v1 - (p / b) * v2; v1 = v2; v2 = v3;
    r = p % b; p = b; b = r;
  }

  if (v2 < 0) v2 += oldp;
  return mulssmod(a, v2, oldp);
}

#endif /* defined(INLINE) */

