/********************************************************************/
/********************************************************************/
/**                                                                **/
/**                      GENERIC OPERATIONS                        **/
/**                         (first part)                           **/
/**                                                                **/
/**                      copyright Babe Cool                       **/
/**                                                                **/
/********************************************************************/
/********************************************************************/
/* $Id: gen1.c,v 2.0.0.2 1997/12/14 20:11:49 karim Exp karim $ */
# include "genpari.h"

/* y is a polmod, f is gadd or gmul */
static GEN
op_polmod(GEN f(GEN,GEN), GEN x, GEN y, long tx)
{
  GEN mod,k,l, z=cgetg(3,t_POLMOD);
  long av,tetpil,vx,vy;
  
  l=(GEN)y[1];
  if (tx==t_POLMOD)
  {
    k=(GEN)x[1];
    if (k==l || gegal(k,l)) { mod=gcopyifstack(k); x=(GEN)x[2]; y=(GEN)y[2]; }
    else
    {
      vx=varn(k), vy=varn(l);
      if (vx==vy) { mod=srgcd(k,l); x=(GEN)x[2]; y=(GEN)y[2]; }
      else
        if (vx<vy) { mod=gcopyifstack(k); x=(GEN)x[2]; }
        else       { mod=gcopyifstack(l); y=(GEN)y[2]; }
    }
  }
  else
  {
    mod=gcopyifstack(l); y=(GEN)y[2];
    if (is_scalar_t(tx))
    { 
      z[2] = (long)f(x,y);
      z[1] = (long)mod; return z;
    }
  }
  av=avma; x = f(x,y); tetpil=avma;
  z[2] = lpile(av,tetpil,gmod(x,mod));
  z[1] = (long)mod; return z;
}

/********************************************************************/
/**                                                                **/
/**                          SUBSTRACTION                          **/
/**                                                                **/
/********************************************************************/

GEN
gsub(GEN x, GEN y)
{
  long tetpil, av = avma;

  y=gneg(y); tetpil=avma;
  return gerepile(av,tetpil,gadd(x,y));
}

/********************************************************************/
/**                                                                **/
/**                           ADDITION                             **/
/**                                                                **/
/********************************************************************/

static GEN
gaddpadic(GEN x, GEN y)
{
  long c,e,r,d,r1,r2,av,tetpil;
  GEN z,p1,p2, p = (GEN)x[2];

  z=cgetg(5,t_PADIC);
  z[2]=(long)copyifstack(p); av=avma; 
  if (!gegal(p,(GEN)y[2])) err(gadderi,"t_PADIC","t_PADIC");

  e=valp(x); r=valp(y); d = r-e;
  if (d<0) { p1=x; x=y; y=p1; e=r; d = -d; }
  r1=precp(x); r2=precp(y);
  if (d)
  {
    r = d+r2; 
    p1 = (d==1)? p: gclone(gpuigs(p,d));
    avma=av;
    if (r<r1) z[3]=lmulii(p1,(GEN)y[3]);
    else
    {
      r=r1; z[3]=licopy((GEN)x[3]);
    }
    av=avma; p2=mulii(p1,(GEN)y[4]);
    if (d!=1) killbloc(p1);
    p1=addii(p2,(GEN)x[4]); tetpil=avma;
    z[4]=lpile(av,tetpil, modii(p1,(GEN)z[3]));
    z[1]=evalprecp(r)+evalvalp(e); return z;
  }
  if (r2<r1) { r=r2; z=x; x=y; y=z; } else r=r1;
  p1 = addii((GEN)x[4],(GEN)y[4]);
  if (!signe(p1) || (c = pvaluation(p1,p,&p2)) >=r)
  { 
    avma=av; z[4]=zero; z[3]=un;
    z[1]=evalvalp(e+r); return z;
  }
  if (c)
  {
    p2=gclone(p2); avma=av;
    if (c==1)
      z[3] = ldivii((GEN)x[3], p);
    else
    {
      p1 = gpuigs(p,c); tetpil=avma;
      z[3] = lpile(av,tetpil, divii((GEN)x[3], p1));
    }
    z[4]=lmodii(p2,(GEN)z[3]); killbloc(p2);
    z[1]=evalprecp(r-c)+evalvalp(e+c); return z;
  }
  tetpil=avma;
  z[4]=lpile(av,tetpil,modii(p1,(GEN)x[3]));
  z[3]=licopy((GEN)x[3]);
  z[1]=evalprecp(r)+evalvalp(e); return z;
}  

/* return x + y, where x is t_INT or t_FRAC(N), y t_PADIC */
static GEN
gaddpex(GEN x, GEN y)
{
  long tx,e1,e2,e3,av,tetpil;
  GEN z,p,p1,p2;

  if (gcmp0(x)) return gcopy(y);

  av=avma; p=(GEN)y[2]; tx=typ(x);
  z=cgetg(5,t_PADIC); z[2]=(long)p;
  e3 = (tx == t_INT)? pvaluation(x,p,&p1)
                    : pvaluation((GEN)x[1],p,&p1) - 
                      pvaluation((GEN)x[2],p,&p2);
  e1 = valp(y)-e3; e2 = signe(y[4])? e1+precp(y): e1;
  if (e2<=0)
  { 
    z[1] = evalprecp(0)+evalvalp(e3);
    z[3] = un;
    z[4] = zero;
  }
  else
  {
    if (tx != t_INT && !gcmp1(p2)) p1 = gdiv(p1,p2);
    z[1] = evalprecp(e2)+evalvalp(e3);
    z[3] = e1? lmul((GEN)y[3], gpuigs(p,e1)): y[3];
    z[4] = lmod(p1,(GEN)z[3]);
  }
  tetpil=avma; return gerepile(av,tetpil,gaddpadic(z,y));
}

static long
kro_quad(GEN x, GEN y)
{
  GEN p1 = (GEN)x[1];
  long k, av=avma;

  p1 = subii(sqri((GEN)p1[3]), shifti((GEN)p1[2],2));
  k=kronecker(p1,y); avma=av; return k;
}

GEN
gadd(GEN x, GEN y)
{
  long vx,vy,lx,ly,tx,ty,i,j,k,l,av,tetpil;
  GEN z,p1,p2;

  tx=typ(x); ty=typ(y);
  if (is_const_t(tx) && is_const_t(ty))
  {
    if (tx>ty) { p1=x; x=y; y=p1; i=tx; tx=ty; ty=i; }
  }
  else
  {
    vx=gvar(x); vy=gvar(y);
    if (vx<vy || (vx==vy && tx>ty))
    {
      p1=x; x=y; y=p1;
      i=tx; tx=ty; ty=i;
      i=vx; vx=vy; vy=i;
    }
    if (ty==t_POLMOD) return op_polmod(gadd,x,y,tx);
  }

  /* here vx >= vy */
  if (is_scalar_t(ty))
  {
    switch(tx)
    {
      case t_INT:
        switch(ty)
	{
	  case t_INT: 
            return addii(x,y);
          case t_REAL:
	    return addir(x,y);
	  
	  case t_INTMOD: z=cgetg(3,ty);
	    z[1] = copyifstack(y[1]);
	    av=avma; p1 = addii(x,(GEN)y[2]); tetpil=avma;
	    z[2] = lpile(av,tetpil, modii(p1,(GEN)y[1]));
	    return z;

	  case t_FRAC: case t_FRACN: z=cgetg(3,ty);
            p2 = (GEN)y[2]; av=avma; p1 = mulii(p2,x); tetpil=avma;
	    z[1] = lpile(av,tetpil, addii(p1,(GEN)y[1]));
	    z[2] = licopy(p2); return z;

	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=ladd(x,(GEN)y[1]);
	    z[2]=lcopy((GEN)y[2]); return z;
	  
	  case t_PADIC:
	    return gaddpex(x,y);
	  
	  case t_QUAD: z=cgetg(4,ty);
	    z[1]=copyifstack(y[1]);
	    z[2]=ladd(x,(GEN)y[2]);
	    z[3]=lcopy((GEN)y[3]); return z;
	}
	
      case t_REAL:
        switch(ty)
	{
	  case t_REAL:
	    return addrr(x,y);
	  
	  case t_FRAC: case t_FRACN:
	    if (!signe(y[1])) return rcopy(x);
            if (!signe(x))
            {
              lx = expi((GEN)y[1]) - expi((GEN)y[2]) - expo(x);
              if (lx<=0) lx=0; else lx >>= TWOPOTBITS_IN_LONG;
              z=cgetr(lx+3); diviiz((GEN)y[1],(GEN)y[2],z);
              return z;
            }
            av=avma; z=addir((GEN)y[1],mulir((GEN)y[2],x)); tetpil=avma;
            return gerepile(av,tetpil,divri(z,(GEN)y[2]));
	  
	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=ladd(x,(GEN)y[1]);
	    z[2]=lcopy((GEN)y[2]);
	    return z;

	  case t_QUAD:
	    if (gcmp0(y)) return rcopy(x);

	    av=avma; i=gexpo(y)-expo(x);
	    if (i<=0) i=0; else i >>= TWOPOTBITS_IN_LONG;
	    p1=co8(y,lg(x)+i); tetpil=avma;
	    return gerepile(av,tetpil,gadd(p1,x));
	  
	  case t_INTMOD: case t_PADIC:
	    err(gadderf,"t_REAL","t_INTMOD");
	}
	
      case t_INTMOD:
        switch(ty)
	{
	  case t_INTMOD: z=cgetg(3,ty);
            k=x[1]; l=y[1];
	    if (k==l || gegal((GEN)k,(GEN)l))
	      z[1]=copyifstack(k);
	    else
	      z[1]=lmppgcd((GEN)k,(GEN)l);
	    av=avma; p1=addii((GEN)x[2],(GEN)y[2]); tetpil=avma;
	    z[2]=lpile(av,tetpil,modii(p1,(GEN)z[1])); return z;
	  
	  case t_FRAC: case t_FRACN: z=cgetg(3,tx);
            p2 = (GEN)x[1];
	    z[1]=copyifstack(p2);
	    z[2]=lgeti(lgefint(p2)); av=avma;
            p1 = mpinvmod((GEN)y[2],p2);
            p1 = mulii((GEN)y[1],p1);
            p1 = addii(p1,(GEN)x[2]);
            affii(modii(p1,p2), (GEN)z[2]); avma=av; return z;
	  
	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=ladd(x,(GEN)y[1]);
            z[2]=lcopy((GEN)y[2]); return z;
	  
	  case t_PADIC:
	    l=avma; p1=cgetg(3,t_INTMOD);
	    p1[1]=x[1]; p1[2]=lgeti(lgefint(x[1]));
	    gaffect(y,p1); tetpil=avma;
	    return gerepile(l,tetpil,gadd(p1,x));
	  
	  case t_QUAD: z=cgetg(4,ty);
            z[1]=copyifstack(y[1]);
	    z[2]=ladd(x,(GEN)y[2]);
            z[3]=lcopy((GEN)y[3]); return z;
	}
	
      case t_FRAC: case t_FRACN:
        switch (ty)
	{
	  case t_FRAC: case t_FRACN: z=cgetg(3,ty); l=avma;
	    p1=mulii((GEN)x[1],(GEN)y[2]);
	    p2=mulii((GEN)x[2],(GEN)y[1]);
	    tetpil=avma; z[1]=lpile(l,tetpil,addii(p1,p2));
	    z[2]=lmulii((GEN)x[2],(GEN)y[2]);
	    return (ty==t_FRACN)? z: gredsp(z);

	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=ladd((GEN)y[1],x);
	    z[2]=lcopy((GEN)y[2]); return z;

	  case t_PADIC:
	    return gaddpex(x,y);

	  case t_QUAD: z=cgetg(4,ty);
	    z[1]=lcopy((GEN)y[1]);
	    z[2]=ladd((GEN)y[2],x);
	    z[3]=lcopy((GEN)y[3]); return z;
	}
	
      case t_COMPLEX:
        switch(ty)
	{
	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=ladd((GEN)x[1],(GEN)y[1]);
	    z[2]=ladd((GEN)x[2],(GEN)y[2]); return z;

	  case t_PADIC:
	    if (krosg(-1,(GEN)y[2])== -1)
	    {
	      z=cgetg(3,t_COMPLEX);
              z[1]=ladd((GEN)x[1],y);
	      z[2]=lcopy((GEN)x[2]); return z;
	    }
	    av=avma; l = signe(y[4])? precp(y): 1;
	    p1=cvtop(x,(GEN)y[2], l + valp(y)); tetpil=avma;
            return gerepile(av,tetpil,gadd(p1,y));

	  case t_QUAD:
	    lx=precision(x); if (!lx) err(gadderi,"t_COMPLEX","t_QUAD");
	    if (gcmp0(y)) return gcopy(x);

	    av=avma; i=gexpo(y)-gexpo(x);
	    if (i<=0) i=0; else i >>= TWOPOTBITS_IN_LONG;
	    p1=co8(y,lx+i); tetpil=avma;
	    return gerepile(av,tetpil,gadd(p1,x));
	}
	
      case t_PADIC:
        switch(ty)
	{
	  case t_PADIC:
            return gaddpadic(x,y);

	  case t_QUAD:
	    if (kro_quad(y,(GEN)x[2]) == -1)
	    {
	      z=cgetg(4,t_QUAD);
	      z[1]=copyifstack(y[1]);
	      z[2]=ladd((GEN)y[2],x);
	      z[3]=lcopy((GEN)y[3]); return z;
	    }
	    av=avma; l = signe(x[4])? precp(x): 1;
	    p1=cvtop(y,(GEN)x[2],valp(x)+l); tetpil=avma;
	    return gerepile(av,tetpil,gadd(p1,x));
	}

      case t_QUAD: z=cgetg(4,ty); k=x[1]; l=y[1];
        if (k!=l && !gegal((GEN)k,(GEN)l)) err(gadderi,"t_QUAD","t_QUAD");
        z[1]=copyifstack(l);
        z[2]=ladd((GEN)x[2],(GEN)y[2]);
        z[3]=ladd((GEN)x[3],(GEN)y[3]); return z;
    }
    err(bugparier,"gadd");
  }

  /* here !isscalar(y) */
  if ( (vx>vy && (!is_matvec_t(tx) || !is_matvec_t(ty)))
    || (vx==vy && is_scalar_t(tx)) )
  {
    switch(ty)
    {
      case t_POL: ly=lgef(y);
	if (ly==2) return isexactzero(x)? zeropol(vy): scalarpol(x,vy);

	z=cgetg(ly,ty); x = gadd(x,(GEN)y[2]); z[2]=(long)x;
	if (ly==3 && gcmp0(x))
	{
	  z[1]=isexactzero(x)? evallgef(2) | evalvarn(vy)
	                     : evallgef(3) | evalvarn(vy);
	  return z;
	}
	z[1]=y[1]; for (i=3; i<ly; i++) z[i]=lcopy((GEN)y[i]);
	return normalizepol(z);
      
      case t_SER: l=valp(y); ly=lg(y);
        if (l<3-ly) return gcopy(y);
	if (l<0)
	{
	  z=cgetg(ly,ty); z[1]=y[1];
	  for (i=2; i<=1-l; i++) z[i]=lcopy((GEN)y[i]);
	  for (i=3-l; i<ly; i++) z[i]=lcopy((GEN)y[i]);
	  z[2-l]=ladd(x,(GEN)y[2-l]); return z;
	}
	if (l>0)
	{
	  if (gcmp0(x)) return gcopy(y);
	  if (gcmp0(y)) ly=2;
          
          ly += l; z=cgetg(ly,ty);
	  z[1]=evalsigne(1)+HIGHVALPBIT+evalvarn(vy);
	  for (i=3; i<=l+1; i++) z[i]=zero;
	  for (   ; i<ly; i++) z[i]=lcopy((GEN)y[i-l]);
	  z[2]=lcopy(x); return z;
	}
	av=avma; z=cgetg(ly,ty);
	p1=signe(y)? gadd(x,(GEN)y[2]): x;
	if (!isexactzero(p1))
        {
          z[1] = HIGHVALPBIT+evalvarn(vy);
          if (signe(y))
          {
            z[1] += evalsigne(1); z[2]=(long)p1;
            for (i=3; i<ly; i++) z[i]=lcopy((GEN)y[i]);
          }
          return z;
        }
        avma=av; /* first coeff is 0 */
        i=3; while (i<ly && gcmp0((GEN)y[i])) i++;
        if (i==ly) return zeroser(vy,i-2);

        z=cgetg(ly-i+2,ty); z[1]=evalvalp(i-2)+evalvarn(vy)+evalsigne(1);
        for (j=2; j<=ly-i+1; j++) z[j]=lcopy((GEN)y[j+i-2]);
        return z;
      
      case t_RFRAC: case t_RFRACN: av=avma; z=cgetg(3,ty);
        l=avma; p1=gmul(x,(GEN)y[2]); tetpil=avma;
        p1 = gadd(p1,(GEN)y[1]);
        if (ty==t_RFRACN)
        { 
          z[1]=lpile(l,tetpil,p1);
          z[2]=lcopy((GEN)y[2]); return z;
        }
        z[1]=(long)p1; z[2]=y[2]; 
        return gerepileupto(av,gred_rfrac(z));

      case t_VEC: case t_COL: case t_MAT:
	if (isexactzero(x)) return gcopy(y); 
	if (ty == t_MAT) return gaddmat(x,y);
        /* fall through */
      case t_QFR: case t_QFI:
	err(gadderf,"Scalar","vector/matrix");
    }
    err(typeer,"addition");
  }

  lx=lg(x); ly=lg(y);
  /* here !isscalar(x) && isscalar(y) && (vx=vy || ismatvec(x and y)) */
  if (tx>ty) { p1=x; x=y; y=p1; i=tx; tx=ty; ty=i; }
  switch(tx)
  {
    case t_POL:
      switch (ty)
      {
	case t_POL: lx=lgef(x); ly=lgef(y);
	  if (ly>lx) { p1=x; x=y; y=p1; k=lx; lx=ly; ly=k; }
	  z=cgetg(lx,ty);
	  for (i=2; i<ly; i++) z[i]=ladd((GEN)x[i],(GEN)y[i]);
	  for (   ; i<lx; i++) z[i]=lcopy((GEN)x[i]);
	  z[1]=x[1]; return normalizepol(z);

	case t_SER:
	  if (gcmp0(x)) return gcopy(y);
          if (!signe(y)) ly=3;
	  i = ly+valp(y)-gval(x,vx);
	  if (i<3) return gcopy(y);

	  p1=greffe(x,i,0); y=gadd(p1,y);
          free(p1); return y;
	      
	case t_RFRAC: case t_RFRACN: av=avma; z=cgetg(3,ty);
          l=avma; p1=gmul(x,(GEN)y[2]); tetpil=avma;
          p1 = gadd(p1,(GEN)y[1]);
          if (ty==t_RFRACN)
          {
            z[1]=lpile(l,tetpil,p1);
            z[2]=lcopy((GEN)y[2]); return z;
          }
          z[1]=(long)p1; z[2]=y[2];
          return gerepileupto(av,gred_rfrac(z));

	case t_QFR: case t_QFI:
	case t_VEC: case t_COL: case t_MAT:
	  err(gadderf,"t_POL","vector/matrix");
	default: err(typeer,"addition");
      }
    
    case t_SER:
      switch(ty)
      {
	case t_SER:
	  l=valp(y)-valp(x);
	  if (l<0) { l= -l; p1=x; x=y; y=p1; i=lx; lx=ly; ly=i; }
	  if (gcmp0(x)) return gcopy(x);
	  if (!signe(y)) ly=2;
	  ly += l; if (lx<ly) ly=lx;
	  if (l)
	  {
	    z=cgetg(ly,ty);
	    z[1]=evalvalp(valp(x))+evalsigne(1)+evalvarn(vx);
	    if (l>=ly-2)
	      for (i=2; i<ly; i++) z[i]=lcopy((GEN)x[i]);
            else
	    {
	      for (i=2; i<=l+1; i++) z[i]=lcopy((GEN)x[i]);
	      for (   ; i<ly; i++) z[i]=ladd((GEN)x[i],(GEN)y[i-l]);
	    }
	    return z;
	  }

	  i=2; l=avma;
	  while (i<ly)
	  {
	    p1=gadd((GEN)x[i],(GEN)y[i]); i++;
	    if (!isexactzero(p1))
	    {
	      z=cgetg(ly-i+3,ty);
	      z[1]=evalvalp(valp(x)+i-3)+evalsigne(1)+evalvarn(vx);
	      for (j=i; j<ly; j++)
		z[j-i+3]=ladd((GEN)x[j],(GEN)y[j]);
	      z[2]=(long)p1; return z;
	    }
            avma=l; 
	  }
          return zeroser(vx,ly-2+valp(y));
	      
	case t_RFRAC: case t_RFRACN:
	  if (gcmp0(y)) return gcopy(x);

	  l = valp(x)-gval(y,vy); l = gcmp0(x)? l+3: l+lx;
	  if (l<3) return gcopy(x);

	  av=avma; ty=typ(y[2]);
          p1 = is_scalar_t(ty)? (GEN)y[2]: greffe((GEN)y[2],l,1);
          p1 = gdiv((GEN)y[1], p1); tetpil=avma;
          return gerepile(av,tetpil,gadd(p1,x));

	case t_QFR: case t_QFI: case t_VEC: case t_COL: case t_MAT:
	  err(gadderf,"t_SER","qfb/vector/matrix");
	      
	default: err(typeer,"addition");
      }
    
    case t_RFRAC: case t_RFRACN: av=avma; z=cgetg(ly,ty);
      if (!is_rfrac_t(ty)) err(gadderi,"t_RFRAC","vector/matrix");
      l=avma;
      p1=gmul((GEN)x[1],(GEN)y[2]);
      p2=gmul((GEN)x[2],(GEN)y[1]); 
      tetpil=avma; p1 = gadd(p1,p2);
      if (ty==t_RFRACN)
      {
        z[1]=lpile(l,tetpil,p1);
        z[2]=lmul((GEN)x[2],(GEN)y[2]); return z;
      }
      z[1]=(long)p1; z[2]=lmul((GEN)x[2],(GEN)y[2]);
      return gerepileupto(av,gred_rfrac(z));
    
    case t_VEC: case t_COL: case t_MAT:
      if (lx!=ly || tx!=ty) err(gadderi,"vector/matrix","vector/matrix");
      z=cgetg(ly,ty);
      for (i=1; i<ly; i++)
	z[i]=ladd((GEN)x[i],(GEN)y[i]);
      return z;
    
    case t_QFR: case t_QFI:
      err(gadderf,"qfb","vector/matrix");
  }
  err(typeer,"addition");
  return NULL; /* not reached */
}

/********************************************************************/
/**                                                                **/
/**                        MULTIPLICATION                          **/
/**                                                                **/
/********************************************************************/

GEN
gmul(GEN x, GEN y)
{
  long tx,ty,lx,ly,vx,vy,i,j,k,l,av,tetpil;
  GEN z,p1,p2,p3,p4;

  tx=typ(x); ty=typ(y);
  if (is_const_t(tx) && is_const_t(ty))
  {
    if (tx>ty) { p1=x; x=y; y=p1; i=tx; tx=ty; ty=i; }
  }
  else
  {
    vx=gvar(x); vy=gvar(y);
    if (!is_matvec_t(ty))
      if (is_matvec_t(tx) || vx<vy || (vx==vy && tx>ty))
      {
	p1=x; x=y; y=p1; 
        i=tx; tx=ty; ty=i;
	i=vx; vx=vy; vy=i;
      }
    if (ty==t_POLMOD) return op_polmod(gmul,x,y,tx);
  }

  if (is_scalar_t(ty))
  {
    switch(tx)
    {
      case t_INT:
        switch(ty)
	{
	  case t_INT:
	    return mulii(x,y);

	  case t_REAL:
	    return mulir(x,y);

	  case t_INTMOD: z=cgetg(3,ty);
	    z[1]=copyifstack(y[1]);
	    l=avma; p1=mulii(x,(GEN)y[2]);
	    tetpil=avma; p2=modii(p1,(GEN)y[1]);
	    z[2]=lpile(l,tetpil,p2); return z;

	  case t_FRAC: case t_FRACN: z=cgetg(3,ty);
	    z[1]=lmulii(x,(GEN)y[1]);
	    z[2]=licopy((GEN)y[2]);
	    return (ty==t_FRACN)? z: gredsp(z);
	  
	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=lmul(x,(GEN)y[1]);
	    z[2]=lmul(x,(GEN)y[2]); return z;
	  
	  case t_PADIC:
	    if (!signe(x)) return gzero;
	    l=avma; p1=cgetp(y); gaffect(x,p1); tetpil=avma;
	    return gerepile(l,tetpil,gmul(p1,y));
	  
	  case t_QUAD: z=cgetg(4,ty);
	    z[1]=copyifstack(y[1]);
	    z[2]=lmul(x,(GEN)y[2]);
	    z[3]=lmul(x,(GEN)y[3]); return z;
	}
	
      case t_REAL: lx=lg(x);
        switch(ty)
	{
	  case t_REAL:
	    return mulrr(x,y);

	  case t_FRAC: case t_FRACN:
	    l=avma; p1=cgetr(lx); tetpil=avma; gaffect(y,p1);
	    p2=mulrr(p1,x); return gerepile(l,tetpil,p2);
	  
	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=lmul(x,(GEN)y[1]);
	    z[2]=lmul(x,(GEN)y[2]); return z;
	  
	  case t_QUAD:
	    l=avma; p1=co8(y,lx); tetpil=avma;
	    return gerepile(l,tetpil,gmul(p1,x));
	  
	  case t_INTMOD:
	    err(gmulerf,"t_REAL","t_INTMOD");
	}
	
      case t_INTMOD:
        switch(ty)
	{
	  case t_INTMOD: z=cgetg(3,ty);
            k=x[1]; l=y[1];
	    if (k==l || gegal((GEN)k,(GEN)l))
	      z[1]=copyifstack(k);
	    else
	      z[1]=lmppgcd((GEN)k,(GEN)l);
	    l=avma; p1=mulii((GEN)x[2],(GEN)y[2]); tetpil=avma;
	    z[2]=lpile(l,tetpil,modii(p1,(GEN)z[1])); return z;
	  
	  case t_FRAC: case t_FRACN: z=cgetg(3,tx);
            p2 = (GEN)x[1];
	    z[1]=copyifstack(p2);
	    z[2]=lgeti(lgefint(p2)); av=avma;
            p1 = mpinvmod((GEN)y[2],p2);
            p1 = mulii((GEN)y[1],p1);
            p1 = mulii(p1,(GEN)x[2]);
            modiiz(p1,p2, (GEN)z[2]); avma=av; return z;
	  
	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=lmul(x,(GEN)y[1]);
	    z[2]=lmul(x,(GEN)y[2]); return z;
	  
	  case t_PADIC:
	    l=avma; p1=cgetg(3,t_INTMOD);
	    p1[1]=x[1]; p1[2]=lgeti(lg(x[1]));
	    gaffect(y,p1); tetpil=avma;
	    return gerepile(l,tetpil,gmul(x,p1));

	  case t_QUAD: z=cgetg(4,ty);
            z[1]=copyifstack(y[1]);
	    z[2]=lmul(x,(GEN)y[2]);
            z[3]=lmul(x,(GEN)y[3]); return z;
	}
	
      case t_FRAC: case t_FRACN:
        switch(ty)
	{
	  case t_FRAC: case t_FRACN: z=cgetg(3,ty);
	    z[1]=lmulii((GEN)x[1],(GEN)y[1]);
	    z[2]=lmulii((GEN)x[2],(GEN)y[2]);
	    return (ty==t_FRACN)? z: gredsp(z);
	  
	  case t_COMPLEX: z=cgetg(3,ty);
	    z[1]=lmul((GEN)y[1],x);
	    z[2]=lmul((GEN)y[2],x); return z;
	  
	  case t_PADIC:
	    if (signe(x[1]) == 0) return gzero;

	    l=avma; p1=cgetp(y); gaffect(x,p1); tetpil=avma;
            return gerepile(l,tetpil,gmul(p1,y));
	  
	  case t_QUAD: z=cgetg(4,ty);
	    z[1]=copyifstack(y[1]);
	    z[2]=lmul((GEN)y[2],x);
	    z[3]=lmul((GEN)y[3],x); return z;
	}
	
      case t_COMPLEX:
        switch(ty)
	{
	  case t_COMPLEX: z=cgetg(3,ty); l=avma;
            p1=gmul((GEN)x[1],(GEN)y[1]);
            p2=gmul((GEN)x[2],(GEN)y[2]);
	    x=gadd((GEN)x[1],(GEN)x[2]); 
            y=gadd((GEN)y[1],(GEN)y[2]);
	    y=gmul(x,y); x=gadd(p1,p2);
	    tetpil=avma; z[1]=lsub(p1,p2); z[2]=lsub(y,x);
	    gerepilemanyvec(l,tetpil,z+1,2); return z;
	  
	  case t_PADIC:
	    if (krosg(-1,(GEN)y[2]))
	    {
	      z=cgetg(3,t_COMPLEX);
	      z[1]=lmul((GEN)x[1],y);
	      z[2]=lmul((GEN)x[2],y); return z;
	    }
	    av=avma;
            if (signe(y[4])) l=precp(y);
            else 
            { 
              l=valp(y)+1; if (l<=0) l=1;
            }
            p1=cvtop(x,(GEN)y[2],l); tetpil=avma;
            return gerepile(av,tetpil,gmul(p1,y));
	  
	  case t_QUAD:
	    lx=precision(x); if (!lx) err(gmuleri,"t_COMPLEX","t_QUAD");
	    l=avma; p1=co8(y,lx); tetpil=avma;
	    return gerepile(l,tetpil,gmul(p1,x));
	}
	
      case t_PADIC:
        switch(ty)
	{
	  case t_PADIC:
	    if (cmpii((GEN)x[2],(GEN)y[2])) err(gmuleri,"t_PADIC","t_PADIC");
            l = valp(x)+valp(y);
	    if (!signe(x[4]))
	      { z=gcopy(x); setvalp(z,l); return z; }
	    if (!signe(y[4]))
	      { z=gcopy(y); setvalp(z,l); return z; }

	    p1 = (precp(x) > precp(y))? y: x;
	    z=cgetp(p1); setvalp(z,l); av=avma; 
	    modiiz(mulii((GEN)x[4],(GEN)y[4]),(GEN)p1[3],(GEN)z[4]);
	    avma=av; return z;
	  
	  case t_QUAD:
	    if (kro_quad(y,(GEN)x[2])== -1)
	    {
	      z=cgetg(4,t_QUAD);
	      z[1]=copyifstack(y[1]);
	      z[2]=lmul((GEN)y[2],x);
	      z[3]=lmul((GEN)y[3],x); return z;
	    }
            l = signe(x[4])? precp(x): valp(x)+1;
	    av=avma; p1=cvtop(y,(GEN)x[2],l); tetpil=avma;
            return gerepile(av,tetpil,gmul(p1,x));
	}
	
      case t_QUAD: z=cgetg(4,ty); 
        p1=(GEN)x[1]; p2=(GEN)y[1];
        if (p1!=p2 && !gegal(p1,p2)) err(gmuleri,"t_QUAD","t_QUAD");

        z[1]=copyifstack(p2); l=avma;
        p2=gmul((GEN)x[2],(GEN)y[2]);
        p3=gmul((GEN)x[3],(GEN)y[3]);
        p4=gmul(gneg((GEN)p1[2]),p3);

        if (gcmp0((GEN)p1[3]))
        { 
          tetpil=avma;
          z[2]=lpile(l,tetpil,gadd(p4,p2)); l=avma;
          p2=gmul((GEN)x[2],(GEN)y[3]);
          p3=gmul((GEN)x[3],(GEN)y[2]); tetpil=avma;
          z[3]=lpile(l,tetpil,gadd(p2,p3)); return z;
        }

        p1 = gadd(gmul((GEN)x[2],(GEN)y[3]), gmul((GEN)x[3],(GEN)y[2]));
        tetpil=avma;
        z[2]=ladd(p2,p4); 
        z[3]=ladd(p1,p3);
        gerepilemanyvec(l,tetpil,z+2,2); return z;
    }
    err(bugparier,"multiplication");
  }

  /* here !isscalar(y) */
  if (is_matvec_t(ty))
  {
    ly=lg(y); 
    if (!is_matvec_t(tx))
    {
      z=cgetg(ly,ty);
      for (i=1; i<ly; i++) z[i]=lmul(x,(GEN)y[i]);
      return z;
    }
    lx=lg(x);

    switch(tx)
    {
      case t_VEC:
        switch(ty)
        {
          case t_COL:
            if (lx!=ly) err(gmuleri,"t_VEC","t_COL");

            z=gzero; l=avma;
            for (i=1; i<lx; i++)
            {
              p1=gmul((GEN)x[i],(GEN)y[i]);
              tetpil=avma; z=gadd(z,p1);
            }
            return gerepile(l,tetpil,z);
            
          case t_MAT:
            if (ly==1) return cgetg(1,t_VEC);
            l=lg(y[1]); if (lx!=l) err(gmuleri,"t_VEC","t_MAT");

            z=cgetg(ly,tx);
            for (i=1; i<ly; i++)
            {
              p1=gzero; av=avma;
              for (j=1; j<lx; j++)
              {
                p2=gmul((GEN)x[j],gcoeff(y,j,i));
                tetpil=avma; p1=gadd(p1,p2);
              }
              z[i]=lpile(av,tetpil,p1);
            }
            return z;

          case t_VEC:
            err(gmulerf,"t_VEC","t_VEC");
          default: err(typeer,"multiplication");
        }
          
      case t_COL:
        switch(ty)
        {
          case t_VEC:
            z=cgetg(ly,t_MAT);
            for (i=1; i<ly; i++) z[i]=lmul((GEN)y[i],x);
            return z;
            
          case t_MAT:
            if (ly!=1 && lg(y[1])!=2) err(gmuleri,"t_COL","t_MAT");

            z=cgetg(ly,t_MAT);
            for (i=1; i<ly; i++) z[i]=lmul(gcoeff(y,1,i),x);
            return z;
            
          case t_COL:
            err(gmulerf,"t_COL","t_COL");
          default: err(typeer,"multiplication");
        }
          
      case t_MAT:
        switch(ty)
        {
          case t_VEC:
            if (lx!=2) err(gmuleri,"t_MAT","t_VEC");
            z=cgetg(ly,t_MAT);
            for (i=1; i<ly; i++) z[i]=lmul((GEN)y[i],(GEN)x[1]);
            return z;
            
          case t_COL:
            if (lx!=ly) err(gmuleri,"t_MAT","t_COL");
            if (lx==1) return gcopy(y);

            lx=lg(x[1]); z=cgetg(lx,ty);
            for (i=1; i<lx; i++)
            {
              p1=gzero; l=avma;
              for (j=1; j<ly; j++)
              {
                p2=gmul(gcoeff(x,i,j),(GEN)y[j]);
                tetpil=avma; p1=gadd(p1,p2);
              }
              z[i]=lpile(l,tetpil,p1);
            }
            return z;
            
          case t_MAT:
            if (ly==1) return cgetg(ly,tx);
            if (lx != lg(y[1])) err(gmuleri,"t_MAT","t_MAT");
            z=cgetg(ly,tx);
            if (lx==1)
            {
              for (i=1; i<ly; i++) z[i]=lgetg(1,t_COL);
              return z;
            }
            l=lg(x[1]);
            for (i=1; i<ly; i++) z[i]=lgetg(l,t_COL);
            for (i=1; i<l; i++)
            {
              for (j=1; j<ly; j++)
              {
                p1=gzero; av=avma;
                for (k=1; k<lx; k++)
                {
                  p2=gmul(gcoeff(x,i,k),gcoeff(y,k,j));
                  tetpil=avma; p1=gadd(p1,p2);
                }
                coeff(z,i,j)=lpile(av,tetpil,p1);
              }
            }
            return z;
        }
    }
    err(bugparier,"multiplication");
  }
  /* now !ismatvec(x and y) */

  if (vx>vy || (vx==vy && is_scalar_t(tx)))
  {
    if (isexactzero(x)) return zeropol(vy);
    switch(ty)
    {
      case t_POL:
	if (isexactzero(y)) return zeropol(vy);
        ly=lgef(y); z=cgetg(ly,ty);
        for (i=2; i<ly; i++) z[i]=lmul(x,(GEN)y[i]);
        z[1]=y[1]; return normalizepol(z);
	
      case t_SER:
	if (!signe(y)) return gcopy(y);

	ly=lg(y); z=cgetg(ly,ty);
	for (i=2; i<ly; i++) z[i]=lmul(x,(GEN)y[i]);
	z[1]=y[1]; return normalize(z);
	
      case t_RFRAC: case t_RFRACN: av=avma; z=cgetg(3,ty);
        z[1]=lmul(x,(GEN)y[1]);
        if (ty==t_RFRACN) { z[2]=lcopy((GEN)y[2]); return z; }
	z[2]=y[2]; return gerepileupto(av,gred_rfrac(z));
    }
    err(typeer,"multiplication");
  }

  if (tx>ty) { p1=x; x=y; y=p1; i=tx; tx=ty; ty=i; }
  lx=lg(x); ly=lg(y);
  switch(tx)
  {
    case t_POL:
      switch (ty)
      {
	case t_POL:
	  if (isexactzero(x) || isexactzero(y)) return zeropol(vx);
	  lx=lgef(x); ly=lgef(y);
	  if (lx<ly)
	  {
	    p1=x; x=y; y=p1; k=lx; lx=ly; ly=k;
	  }
	  k=lx+ly-3; z=cgetg(k,ty);
	  for (i=2; i<ly; i++)
	  {
	    p1=gzero; l=avma;
	    for (j=2; j<=i; j++)
	    {
	      p2=gmul((GEN)y[j],(GEN)x[i-j+2]);
	      tetpil=avma; p1=gadd(p1,p2);
	    }
	    z[i]=lpile(l,tetpil,p1);
	  }
	  for ( ; i<lx; i++)
	  {
	    p1=gzero; l=avma;
	    for (j=2; j<ly; j++)
	    {
	      p2=gmul((GEN)y[j],(GEN)x[i-j+2]);
	      tetpil=avma; p1=gadd(p1,p2);
	    }
	    z[i]=lpile(l,tetpil,p1);
	  }
	  for ( ; i<=lx+ly-4; i++)
	  {
	    p1=gzero; l=avma;
	    for (j=i-lx+3; j<ly; j++)
	    {
	      p2=gmul((GEN)y[j],(GEN)x[i-j+2]);
	      tetpil=avma; p1=gadd(p1,p2);
	    }
	    z[i]=lpile(l,tetpil,p1);
	  }
	  z[1]=evalsigne(1)+evallgef(k)+evalvarn(vx);
	  return normalizepol(z);

	case t_SER:
	  if (gcmp0(x)) return zeropol(vx);
	  if (gcmp0(y))
	  {
	    z=cgetg(3,t_SER);
	    z[1]=evalvalp(valp(y)+gval(x,vx))+evalvarn(vx);
	    return z;
	  }
	  p1=greffe(x,ly,0); p2=gmul(p1,y);
          free(p1); return p2;
	  
	case t_RFRAC: case t_RFRACN: av=avma; z=cgetg(ly,ty);
          z[1]=lmul(x,(GEN)y[1]);
          if (ty==t_RFRACN) { z[2]=lcopy((GEN)y[2]); return z; }
          z[2]=y[2]; return gerepileupto(av,gred_rfrac(z));
	  
	default: err(typeer,"multiplication");
      }
	
    case t_SER:
      switch (ty)
      {
	case t_SER:
        {
          long limit;

	  if (lx>ly) { k=ly; ly=lx; lx=k; p1=y; y=x; x=p1; }
	  if (gcmp0(x)||gcmp0(y))
	  {
	    z=cgetg(3,t_SER); z[1]=evalvalp(valp(x)+valp(y))+evalvarn(vx);
	    return z;
	  }
	  l=avma; limit = (l + 3*bot)>>2;
          p1=cgeti(lx); z=cgetg(lx,ty);
	  z[1]=evalvalp(valp(x)+valp(y))+evalvarn(vx)+evalsigne(1);
	  for (i=2; i<lx; i++)
	  {
	    p1[i]=!isexactzero((GEN)y[i]);
	    z[i]=p1[i]?lmul((GEN)x[2],(GEN)y[i]):zero;
	  }
	  for (i=3; i<lx; i++)
	    if (!isexactzero((GEN)x[i]))
            {
	      for (j=2; j<=lx+1-i; j++)
		if (p1[j])
		  z[i+j-2]=ladd((GEN)z[i+j-2],gmul((GEN)x[i],(GEN)y[j]));
              if (low_stack(limit, (l+3*bot)>>2))
              {
                tetpil=avma; z=gerepile(l,tetpil,gcopy(z));
              }
            }
	  tetpil=avma; z=gerepile(l,tetpil,gcopy(z));
	  return normalize(z);
        }

	case t_RFRAC: case t_RFRACN:
	  if (gcmp0(y)) return zeropol(vx);
	  if (gcmp0(x))
	  {
	    z=cgetg(3,t_SER); z[1]=evalvalp(valp(x)+gval(y,vx))+evalvarn(vx);
	    return z;
	  }
	  l=avma; p1=gmul((GEN)y[1],x); tetpil=avma;
          return gerepile(l,tetpil,gdiv(p1,(GEN)y[2]));
	  
	default: err(typeer,"multiplication");
      }
	
    /* (tx,ty) == t_RFRAC <==> ty == t_RFRAC */
    case t_RFRAC: case t_RFRACN:
      if (!is_rfrac_t(ty)) err(typeer,"multiplication");
      av=avma; z=cgetg(ly,ty);
      z[1]=lmul((GEN)x[1],(GEN)y[1]);
      z[2]=lmul((GEN)x[2],(GEN)y[2]);
      return (ty==t_RFRACN)? z: gredsp(z);
  }
  if (tx==ty)
    switch(tx)
    {
      case t_QFI: return compimag(x,y); 
      case t_QFR: return compreal(x,y);
    }
  err(typeer,"multiplication");
  return NULL; /* not reached */
}

/********************************************************************/
/**                                                                **/
/**                           DIVISION                             **/
/**                                                                **/
/********************************************************************/

GEN
gdiv(GEN x, GEN y)
{
  long lx,ly,tx,ty,vx,vy,i,j,k,l,av,tetpil;
  GEN z,p1,p2,p3;

  if (gcmp0(y)) err(gdiver2);

  lx=lg(x); ly=lg(y); tx=typ(x); ty=typ(y);
  if (is_const_t(tx) && is_const_t(ty))
  {
    switch(tx)
    {
      case t_INT:
	switch(ty)
	{
	  case t_INT:
	    i=signe(x); if (!i) return gzero;
	    av=avma; z=dvmdii(x,y,&p1);
	    if (p1==gzero) return z;

	    p1 = mppgcd(y,p1); p1 = gcmp1(p1)? gun: gclone(p1);
            avma=av; z=cgetg(3,t_FRAC);
	    if (p1==gun) { 
              z[1]=licopy(x);
              z[2]=licopy(y);
            }
            else {
	      z[1]=ldivii(x,p1);
	      z[2]=ldivii(y,p1); killbloc(p1); 
	    } 
	    if (signe(y)<0) { setsigne(z[1],-i); setsigne(z[2],1); }
            return z;
		
	  case t_REAL:
	    return divir(x,y);
		
	  case t_INTMOD: z=cgetg(ly,ty);
            z[1]=copyifstack(y[1]); l=avma;
	    p1=mpinvmod((GEN)y[2],(GEN)y[1]);
	    p2=mulii(x,p1); tetpil=avma;
	    z[2]=lpile(l,tetpil,modii(p2,(GEN)y[1])); return z;
		
	  case t_FRAC: case t_FRACN: z=cgetg(ly,ty);
	    z[1]=lmulii(x,(GEN)y[2]);
	    z[2]=licopy((GEN)y[1]);
	    if (signe(z[2])<0)
	    {
	      setsigne(z[1],-signe(z[1]));
	      setsigne(z[2],1);
	    }
	    return (ty==t_FRACN)? z: gredsp(z);
		
	  case t_PADIC:
	    if (!signe(x)) return gzero;
            l=avma; p1=cgetp(y); gaffect(x,p1); tetpil=avma;
            return gerepile(l,tetpil,gdiv(p1,y));
		
	  case t_COMPLEX: case t_QUAD:
	    l=avma; p1=gnorm(y); p2=gmul(x,gconj(y)); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(p2,p1));
	}
      
      case t_REAL:
	switch(ty)
	{
	  case t_INT:
	    return divri(x,y);

	  case t_REAL:
	    return divrr(x,y);

	  case t_FRAC: case t_FRACN:
	    l=avma; p1=cgetg(lx,tx); gaffect(y,p1);
	    return gerepile(l,(long)p1,divrr(x,p1));

	  case t_COMPLEX: z=cgetg(ly,ty);
            l=avma; p1=gnorm(y);
	    p2=gmul(x,(GEN)y[1]);
            p3=gmul(x,(GEN)y[2]);
	    if (!gcmp0(p3)) p3 = gneg(p3);
            tetpil=avma;
	    z[1]=ldiv(p2,p1);
            z[2]=ldiv(p3,p1);
	    gerepilemanyvec(l,tetpil,z+1,2); return z;

	  case t_QUAD:
	    l=avma; p1=co8(y,lx); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(x,p1));

	  case t_INTMOD: case t_PADIC:
	    err(gdiverf,"t_REAL","t_INTMOD");
	}

      case t_INTMOD:
	switch(ty)
	{
	  case t_INT: z=cgetg(lx,tx);
            z[1]=copyifstack(x[1]);
	    z[2]=lmpinvmod(y,(GEN)x[1]); l=avma;
	    p1=mulii((GEN)x[2],(GEN)z[2]);
	    modiiz(p1,(GEN)x[1],(GEN)z[2]); avma=l;
	    return z;

	  case t_INTMOD: z=cgetg(ly,ty);
            k=x[1]; l=y[1];
	    if (k==l || gegal((GEN)k,(GEN)l))
              z[1]=copyifstack(k);
	    else
              z[1]=lmppgcd((GEN)k,(GEN)l);
	    l=avma; p1=mpinvmod((GEN)y[2],(GEN)z[1]);
	    p2=mulii((GEN)x[2],p1); tetpil=avma;
	    z[2]=lpile(l,tetpil,modii(p2,(GEN)z[1])); return z;

	  case t_FRAC: z=cgetg(lx,tx);
            z[1]=copyifstack(x[1]); 
	    z[2]=lmpinvmod((GEN)y[1],(GEN)x[1]);
	    l=avma;
	    p1 = mulii((GEN)x[2],(GEN)y[2]);
            p1 = modii(p1,(GEN)x[1]);
	    p2 = mulii(p1,(GEN)z[2]);
            modiiz(p2,(GEN)x[1],(GEN)z[2]);
            avma=l; return z;

	  case t_FRACN:
	    l=avma; p1=gred(y); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(x,p1));

	  case t_COMPLEX: case t_QUAD:
	    l=avma; p1=gnorm(y); p2=gmul(x,gconj(y)); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(p2,p1));

	  case t_PADIC:
	    l=avma; p1=cgetg(3,t_INTMOD); p1[1]=x[1]; p1[2]=lgeti(lg(x[1]));
	    gaffect(y,p1); tetpil=avma; return gerepile(l,tetpil,gdiv(x,p1));

	  case t_REAL:
	    err(gdiverf,"t_INTMOD","t_REAL");
	}

      case t_FRAC: case t_FRACN:
	switch(ty)
	{
	  case t_INT: z=cgetg(lx,tx);
	    z[1]=licopy((GEN)x[1]);
	    z[2]=lmulii((GEN)x[2],y);
	    if (signe(z[2])<0)
	    {
	      setsigne(z[1],-signe(z[1]));
	      setsigne(z[2],1);
	    }
	    return (tx==t_FRACN)? z: gredsp(z);

	  case t_REAL:
	    l=avma; p1=cgetg(ly,ty); gaffect(x,p1);
	    p2=divrr(p1,y); return gerepile(l,(long)p1,p2);

	  case t_INTMOD: z=cgetg(ly,ty);
            z[1]=copyifstack(y[1]); l=avma;
	    p1=mulii((GEN)y[2],(GEN)x[2]);
	    p1=mpinvmod(p1,(GEN)y[1]);
	    p1=mulii(p1,(GEN)x[1]); tetpil=avma;
	    z[2]=lpile(l,tetpil,modii(p1,(GEN)y[1])); return z;

	  case t_FRAC: case t_FRACN:
	    if (tx == t_FRACN) ty=t_FRACN;
	    z=cgetg(ly,ty);
	    z[1]=lmulii((GEN)x[1],(GEN)y[2]);
	    z[2]=lmulii((GEN)x[2],(GEN)y[1]);
	    if (signe(z[2])<0)
	    {
	      setsigne(z[1],-signe(z[1]));
	      setsigne(z[2],1);
	    }
	    return (ty==t_FRACN)? z: gredsp(z);

	  case t_COMPLEX: z=cgetg(ly,ty);
            l=avma; p1=gnorm(y);
	    p2=gmul(x,(GEN)y[1]);
	    p3=gmul(x,(GEN)y[2]); if(!gcmp0(p3)) p3 = gneg(p3);
	    tetpil=avma;
	    z[1]=ldiv(p2,p1); z[2]=ldiv(p3,p1);
	    gerepilemanyvec(l,tetpil,z+1,2); return z;

	  case t_PADIC:
	    if (signe(x[1]) == 0) return gzero;

	    l=avma; p1=cgetp(y); gaffect(x,p1);
	    tetpil=avma; return gerepile(l,tetpil,gdiv(p1,y));

	  case t_QUAD:
	    l=avma; p1=gnorm(y); p2=gmul(x,gconj(y)); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(p2,p1));
	}

      case t_COMPLEX:
	switch(ty)
	{
	  case t_INT: case t_REAL: case t_INTMOD: case t_FRAC: case t_FRACN:
	    z=cgetg(lx,tx);
	    z[1]=ldiv((GEN)x[1],y);
	    z[2]=ldiv((GEN)x[2],y); return z;

	  case t_COMPLEX:
	    l=avma; p1=gnorm(y); p2=gconj(y); p2=gmul(x,p2); tetpil=avma;
	    return gerepile(l,tetpil, gdiv(p2,p1));

	  case t_PADIC:
	    if (krosg(-1,(GEN)y[2])== -1)
	    {
	      z=cgetg(3,t_COMPLEX);
	      z[1]=ldiv((GEN)x[1],y);
	      z[2]=ldiv((GEN)x[2],y); return z;
	    }
	    av=avma; p1=cvtop(x,(GEN)y[2],precp(y)); tetpil=avma;
	    return gerepile(av,tetpil,gdiv(p1,y));

	  case t_QUAD:
	    lx=precision(x); if (!lx) err(gdiveri,"t_COMPLEX","t_QUAD");
	    l=avma; p1=co8(y,lx); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(x,p1));
	}

      case t_PADIC:
	switch(ty)
	{
	  case t_INT: case t_FRAC: case t_FRACN:
	    l=avma;
	    if (signe(x[4])) { p1=cgetp(x); gaffect(y,p1); }
	    else p1=cvtop(y,(GEN)x[2],(valp(x)>0)?valp(x):1);
	    tetpil=avma; return gerepile(l,tetpil,gdiv(x,p1));

	  case t_INTMOD:
	    l=avma; p1=cgetg(3,t_INTMOD);
	    p1[1]=y[1]; p1[2]=lgeti(lg(y[1]));
	    gaffect(x,p1); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(p1,y));

	  case t_PADIC:
	    if (cmpii((GEN)x[2],(GEN)y[2])) err(gdiveri,"t_PADIC","t_PADIC");
	    if (!signe(x[4]))
	    { 
	      z=gcopy(x); setvalp(z,valp(x)-valp(y));
	      return z;
	    }

	    p1=(precp(x)>precp(y)) ? y : x;
	    z=cgetp(p1); l=avma;
	    setvalp(z,valp(x)-valp(y));
	    p2=mpinvmod((GEN)y[4],(GEN)p1[3]);
	    modiiz(mulii((GEN)x[4],p2),(GEN)p1[3],(GEN)z[4]);
	    avma=l; return z;

	  case t_COMPLEX: case t_QUAD:
	    l=avma; p1=gmul(x,gconj(y)); p2=gnorm(y); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(p1,p2));

	  case t_REAL:
	    err(talker,"forbidden division p-adic/R");
	}

      case t_QUAD:
	switch (ty)
	{
	  case t_INT: case t_INTMOD: case t_FRAC: case t_FRACN:
	    z=cgetg(lx,tx);
	    z[1]=copyifstack(x[1]);
	    for (i=2; i<4; i++) z[i]=ldiv((GEN)x[i],y);
	    return z;

	  case t_REAL:
	    l=avma; p1=co8(x,ly); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(p1,y));

	  case t_PADIC:
	    l=avma; p1=cvtop(x,(GEN)y[2],precp(y));
	    tetpil=avma; return gerepile(l,tetpil,gdiv(p1,y));

	  case t_COMPLEX:
	    ly=precision(y); if (!ly) err(gdiveri,"t_QUAD","t_COMPLEX");
	    l=avma; p1=co8(x,ly); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(p1,y));

	  case t_QUAD:
	    k=x[1]; l=y[1];
	    if (k!=l && !gegal((GEN)k,(GEN)l)) err(gdiveri,"t_QUAD","t_QUAD");
	    l=avma; p1=gnorm(y); p2=gmul(x,gconj(y)); tetpil=avma;
	    return gerepile(l,tetpil,gdiv(p2,p1));
	}
    }
    err(bugparier,"division");
  }

  vx=gvar(x); vy=gvar(y);
  if (ty==t_POLMOD && (tx==t_POLMOD || vy<vx))
  {
    z=cgetg(3,ty);
    if (tx==t_POLMOD)
    {
      k=x[1]; l=y[1];
      if (k==l || gegal((GEN)k,(GEN)l))
      {
        z[1]=copyifstack(k); av=avma;
        p1=ginvmod((GEN)y[2],(GEN)z[1]);
        p2=gmul((GEN)x[2],p1);
      }
      else
      {
        vx=varn(x[1]); vy=varn(y[1]);
        if (vx==vy)
        {
          z[1]=lgcd((GEN)k,(GEN)l); av=avma;
          p1=ginvmod((GEN)y[2],(GEN)z[1]);
          p2=gmul((GEN)x[2],p1);
        }
        else
        {
          if (vx<vy)
          { z[1]=copyifstack(k); av=avma; p2=gdiv((GEN)x[2],y); }
          else
          { z[1]=copyifstack(l); av=avma; p2=gdiv((GEN)y[2],x); }
        }
      }
      tetpil=avma; p1 = gmod(p2,(GEN)z[1]);
    }
    else
    {
      z[1]=copyifstack(y[1]); av=avma;
      p1=ginvmod((GEN)y[2],(GEN)y[1]);
      tetpil=avma; p1 = gmul(x,p1);
    }
    z[2]=lpile(av,tetpil,p1); return z;
  }
  if (tx == t_POLMOD && vx<vy)
  {
    z=cgetg(3,tx);
    z[1]=copyifstack(x[1]);
    z[2]=ldiv((GEN)x[2],y); return z;
  }
  /* now x and y are not both is_scalar_t */

  if ((vx<vy && (!is_matvec_t(tx) || !is_matvec_t(ty)))
     || (vx==vy && is_scalar_t(ty)) || (is_matvec_t(tx) && !is_matvec_t(ty)))
  {
    av=avma; z=cgetg(lx,tx);
    switch(tx)
    {
      case t_POL:
	lx=lgef(x);
	for (i=2; i<lx; i++) z[i]=ldiv((GEN)x[i],y);
	z[1]=x[1]; return z;

      case t_SER:
	if (gcmp0(x)) return gcopy(x);

	for (i=2; i<lx; i++) z[i]=ldiv((GEN)x[i],y);
        z[1]=x[1]; return normalize(z);

      case t_RFRAC: case t_RFRACN:
        z[2]=lmul((GEN)x[2],y);
        if (ty==t_RFRACN) { z[1]=lcopy((GEN)x[1]); return z; }
        z[1]=x[1]; return gerepileupto(av, gred_rfrac(z));

      case t_VEC: case t_COL: case t_MAT:
	for (i=1; i<lx; i++) z[i]=ldiv((GEN)x[i],y);
	return z;
    }
    err(typeer,"division");
  }

  if (vy<vx || (vy==vx && is_scalar_t(tx)))
  {
    switch(ty)
    {
      case t_POL:
	if (lgef(y)==3) return gdiv(x,(GEN)y[2]);
        if (isexactzero(x)) return zeropol(vy);
        av=avma; z=cgetg(3,t_RFRAC); z[1]=(long)x; z[2]=(long)y;
        return gerepileupto(av,gred_rfrac(z));

      case t_SER:
	l=avma;
	if (gcmp0(x))
	{
	  p1=ginv(y); tetpil=avma; /* a ameliorer !!!! */
	  return gerepile(l,tetpil,gmul(x,p1));
	}
	p1=cgetg(ly,ty); p1[2]=lcopy(x);
	p1[1]=evalsigne(1)+HIGHVALPBIT+evalvarn(vy);
	for (i=3; i<ly; i++) p1[i]=zero;
	tetpil=avma; return gerepile(l,tetpil,gdiv(p1,y));

      case t_RFRAC: case t_RFRACN: av=avma; z=cgetg(ly,ty);
        z[1]=lmul(x,(GEN)y[2]);
        if (ty==t_RFRACN) { z[2]=lcopy((GEN)y[1]); return z; }
        z[2]=y[1]; return gerepileupto(av,gred_rfrac(z));

      case t_MAT:
	if (ly==1 || lg(y[1])!=ly) err(gdiverf,"Scalar","non-square matrix");
	l=avma; p1=invmat(y); tetpil=avma;
	return gerepile(l,tetpil,gmul(x,p1));

      case t_VEC: case t_COL:
	err(gdiverf,"Scalar","vector");
    }
    err(typeer,"division");
  }

  /* ici vx=vy et tx>=10 et ty>=10*/
  switch(tx)
  {
    case t_POL:
      switch(ty)
      {
	case t_POL: av=avma; z=cgetg(3,t_RFRAC);
          z[1]=(long)x; z[2]=(long)y;
          return gerepileupto(av,gred_rfrac(z));

	case t_SER:
	  if (gcmp0(x)) return zeropol(vx);
	  p1=greffe(x,ly,0); p2=gdiv(p1,y);
          free(p1); return p2;

	case t_RFRAC: case t_RFRACN: av=avma; z=cgetg(ly,ty);
	  z[1]=lmul(x,(GEN)y[2]);
	  if (ty==t_RFRACN) { z[2]=lcopy((GEN)y[1]); return z; }
	  z[2]=y[1]; return gerepileupto(av,gred_rfrac(z));

	case t_VEC: case t_COL: case t_MAT:
	  err(gdiverf,"t_POL","vector or matrix");
	default: err(typeer,"division");
      }

    case t_SER:
      switch(ty)
      {
	case t_POL:
	  p1=greffe(y,lx,0); p2=gdiv(x,p1);
          free(p1); return p2;

	case t_SER:
	  if (gcmp0(x)) return zeroser(vx, valp(x)-valp(y));
	  if (ly<lx) lx=ly;
	  z=cgetg(lx,ty); p2=cgeti(lx);
	  for (i=3; i<lx; i++) p2[i]=!isexactzero((GEN)y[i]);
	  z[1]=evalvalp(valp(x)-valp(y))+evalvarn(vx);
	  z[2]=ldiv((GEN)x[2],(GEN)y[2]);
	  for (i=3; i<lx; i++)
	  {
	    av=avma; p1=(GEN)x[i];
	    for (j=2; j<i; j++)
            {
              l = i-j+2;
              if (p2[l])
              {
                p3 = gneg((GEN)y[l]);
                p1 = gadd(p1, gmul((GEN)z[j],p3));
              }
            }
	    tetpil=avma; z[i]=lpile(av,tetpil, gdiv(p1,(GEN)y[2]));
	  }
	  return normalize(z);

	case t_RFRAC: case t_RFRACN:
	  l=avma; p2=gmul(x,(GEN)y[2]); tetpil=avma;
	  return gerepile(l,tetpil,gdiv(p2,(GEN)y[1]));

	case t_VEC: case t_COL: case t_MAT:
	  err(gdiverf,"t_SER","vector or matrix");
	default: err(typeer,"division");
      }

    case t_RFRAC: case t_RFRACN:
      switch(ty)
      {
	case t_POL: av=avma; z=cgetg(lx,tx);
          z[2]=lmul((GEN)x[2],y);
	  if (tx==t_RFRACN) { z[1]=lcopy((GEN)x[1]); return z; }
          z[1]=x[1]; return gerepileupto(av,gred_rfrac(z));

	case t_SER:
	  l=avma; p2=gmul((GEN)x[2],y); tetpil=avma;
	  return gerepile(l,tetpil, gdiv((GEN)x[1],p2));

	case t_RFRAC: case t_RFRACN:
	  if (tx == t_RFRACN) ty=t_RFRACN;
	  z=cgetg(ly,ty);
	  z[1]=lmul((GEN)x[1],(GEN)y[2]);
          z[2]=lmul((GEN)x[2],(GEN)y[1]);
	  return (ty==t_RFRACN)? z: gredsp(z);

	case t_VEC: case t_COL: case t_MAT:
	  err(gdiverf,"t_RFRAC","vector or matrix");
	default: err(typeer,"division");
      }

    case t_VEC: case t_COL: case t_MAT:
      if (!is_matvec_t(ty))
      {
	z=cgetg(lx,tx);
	for (i=1; i<lx; i++) z[i]=ldiv((GEN)x[i],y);
	return z;
      }
      if (ty==t_MAT && ly!=1 && lg(y[1])==ly)
      {
	l=avma; p1=invmat(y); tetpil=avma;
	return gerepile(l,tetpil,gmul(x,p1));
      }
      err(gdiverf,"vector or matrix","vector or non-square matrix");
  }
  if (tx==ty)
  {
    l=signe(y[2]); setsigne(y[2],-l); 
    switch(tx)
    {
      case t_QFI: z = compimag(x,y); 
        setsigne(y[2],l); return z;
      case t_QFR:
        k=signe(y[4]); setsigne(y[4],-k); z=compreal(x,y);
        setsigne(y[2],l); setsigne(y[4],k); return z;
    }
  }
  err(typeer,"division");
  return NULL; /* not reached */
}
