/********************************************************************/
/********************************************************************/
/**                                                                **/
/**                   FONCTIONS TRANSCENDANTES                     **/
/**                      (troisieme partie)                        **/
/**                                                                **/
/**                      copyright Babe Cool                       **/
/**                                                                **/
/********************************************************************/
/********************************************************************/
/* $Id: trans3.c,v 2.0.0.2 1997/12/14 20:11:49 karim Exp karim $ */
#include "genpari.h"

/***********************************************************************/
/**                                                                   **/
/**                    FONCTION K DE BESSEL                           **/
/**                                                                   **/
/***********************************************************************/

GEN
kbessel0(GEN nu, GEN gx, long flag, long prec)
{
  switch(flag)
  {
    case 0: return kbessel(nu,gx,prec);
    case 1: return kbessel2(nu,gx,prec);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}

GEN
kbessel(GEN nu, GEN gx, long prec)
{
  GEN x,y,p1,p2,zf,zz,s,t,q,r,u,v,e,f,c,d,ak,pitemp,nu2,w;
  long l,lbin,av,av1,k,k2,l1,n2,n;

  if (typ(nu)==t_COMPLEX) return kbessel2(nu,gx,prec);
  if (typ(gx)!=t_REAL)
    { l=prec; k=1; }
  else
    { l=lg(gx); k=0; x=gx; }
  y=cgetr(l); l1=l+1;
  av=avma; if (k) gaffect(gx,x=cgetr(l));
  u=cgetr(l1); v=cgetr(l1); c=cgetr(l1); d=cgetr(l1);
  e=cgetr(l1); f=cgetr(l1);
  nu2=gmulgs(gsqr(nu),-4);
  n = (long) (bit_accuracy(l)*LOG2 + PI*sqrt(gtodouble(gnorm(nu)))) / 2;
  n2=(n<<1); pitemp=mppi(l1);
  lbin = 5 - bit_accuracy(l); av1=avma;
  if (gcmpgs(x,n)<0)
  {
    zf=gsqrt(gdivgs(pitemp,n2),prec);
    zz=cgetr(l1); gaffect(ginv(stoi(n2<<2)), zz);
    s=gun; t=gzero;
    for (k=n2,k2=2*n2-1; k > 0; k--,k2-=2)
    {
      if (k2>(MAXHALFULONG>>1))
        p1 = gadd(mulss(k2,k2),nu2);
      else
        p1 = gaddsg(k2*k2,nu2);
      ak=gdivgs(gmul(p1,zz),-k);
      s=gadd(gun,gmul(ak,s));
      t=gaddsg(k2,gmul(ak,t));
    }
    gmulz(s,zf,u); t=gmul2n(t,-1);
    gdivgsz(gadd(gmul(t,zf),gmul(u,nu)),-n2,v); avma=av1;
    affsr(n2,q=cgetr(l1));
    r=gmul2n(x,1); av1=avma;
    for(;;)
    {
      p1=divsr(5,q); if (expo(p1) >= -1) p1=ghalf;
      p2=subsr(1,divrr(r,q));
      if (gcmp(p1,p2)>0) p1=p2;
      gnegz(p1,c); gaffsg(1,d); affrr(u,e); affrr(v,f);
      for (k=1; ; k++)
      {
	w=gadd(gmul(gsubsg(k,ghalf),u), gmul(subrs(q,k),v));
	w=gadd(w, gmul(nu,gsub(u,gmul2n(v,1))));
	gdivgsz(gmul(q,v),k,u);
	gdivgsz(w,k,v);
	gmulz(d,c,d);
	gaddz(e,gmul(d,u),e); p1=gmul(d,v);
	gaddz(f,p1,f);
	if (gexpo(p1)-gexpo(f) <= lbin) break;
	avma=av1;
      }
      p1=u; u=e; e=p1;
      p1=v; v=f; f=p1;
      gmulz(q,gaddsg(1,c),q);
      if (expo(subrr(q,r)) <= lbin) break;
    }
    gmulz(u,gpui(gdivgs(x,n),nu,prec),y);
  }
  else
  {
    p2=gmul2n(x,1);
    zf=gsqrt(gdiv(pitemp,p2),prec);
    zz=ginv(gmul2n(p2,2)); s=gun;
    for (k=n2,k2=2*n2-1; k > 0; k--,k2-=2)
    {
      if (k2>(MAXHALFULONG>>1)) 
        p1=gadd(mulss(k2,k2),nu2);
      else
        p1=gaddsg(k2*k2,nu2);
      ak=gdivgs(gmul(p1,zz),k);
      s=gsub(gun,gmul(ak,s));
    }
    gmulz(s,zf,y);
  }
  gdivz(y,mpexp(x),y); avma=av; return y;
}

/***********************************************************************/
/*                                                                    **/
/**                    FONCTION U(a,b,z) GENERALE                     **/
/**                         ET CAS PARTICULIERS                       **/
/**                                                                   **/
/***********************************************************************/

/* On suppose gx>0 et a,b reels */
GEN
hyperu(GEN a, GEN b, GEN gx, long prec)
{
  GEN x,y,p1,p2,p3,zf,zz,s,t,q,r,u,v,e,f,c,d,w,a1,gn;
  long l,lbin,av,av1,av2,k,l1,n,ex;

  if (typ(gx)!=t_REAL) 
    { l=prec; k=1; }
  else 
    { l=lg(gx); k=0; x=gx; }
  ex = (iscomplex(a) || iscomplex(b));
  if (ex) { y=cgetg(3,t_COMPLEX); y[1]=lgetr(l); y[2]=lgetr(l); }
  else y=cgetr(l);
  l1=l+1; av=avma; if (k) gaffect(gx,x=cgetr(l));
  a1=gaddsg(1,gsub(a,b));
  if (ex)
  {
    u=cgetg(3,t_COMPLEX); u[1]=lgetr(l1); u[2]=lgetr(l1);
    v=cgetg(3,t_COMPLEX); v[1]=lgetr(l1); v[2]=lgetr(l1);
    c=cgetg(3,t_COMPLEX); c[1]=lgetr(l1); c[2]=lgetr(l1);
    d=cgetg(3,t_COMPLEX); d[1]=lgetr(l1); d[2]=lgetr(l1);
    e=cgetg(3,t_COMPLEX); e[1]=lgetr(l1); e[2]=lgetr(l1);
    f=cgetg(3,t_COMPLEX); f[1]=lgetr(l1); f[2]=lgetr(l1);
  }
  else
  {
    u=cgetr(l1); v=cgetr(l1); c=cgetr(l1);
    d=cgetr(l1); e=cgetr(l1); f=cgetr(l1);
  }
  n=(long)(bit_accuracy(l)*LOG2 + PI*sqrt(gtodouble(gabs(gmul(a,a1),l1))));
  lbin = 5-bit_accuracy(l); av1=avma;
  if (gcmpgs(x,n)<0)
  {
    gn=stoi(n); zf=gpui(gn,gneg(a),l1);
    zz=gdivsg(-1,gn); s=gun; t=gzero;
    for (k=n-1; k>=0; k--)
    {
      p1=gdivgs(gmul(gmul(gaddgs(a,k),gaddgs(a1,k)),zz),k+1);
      s=gaddsg(1,gmul(p1,s));
      t=gadd(gaddsg(k,a),gmul(p1,t));
    }
    gmulz(s,zf,u); t=gmul(t,zz); gmulz(t,zf,v); avma=av1;
    q=cgetr(l1); affsr(n,q); r=x; av1=avma;
    do
    {
      p1=divsr(5,q); if (expo(p1)>= -1) p1=ghalf;
      p2=subsr(1,divrr(r,q)); if (gcmp(p1,p2)>0) p1=p2;
      gnegz(p1,c); avma=av1;
      k=0; gaffsg(1,d);
      gaffect(u,e); gaffect(v,f);
      p3=gsub(q,b); av2=avma;
      for(;;)
      {
	w=gadd(gmul(gaddsg(k,a),u),gmul(gaddsg(-k,p3),v));
	k++; gdivgsz(gmul(q,v),k,u);
	gdivgsz(w,k,v);
	gmulz(d,c,d);
	gaddz(e,gmul(d,u),e); p1=gmul(d,v);
	gaddz(f,p1,f);
	if (gexpo(p1)-gexpo(f) <= lbin) break;
	avma=av2;
      }
      p1=u; u=e; e=p1;
      p1=v; v=f; f=p1;
      gmulz(q,gadd(gun,c),q);
      p1=subrr(q,r); ex=expo(p1); avma=av1;
    }
    while (ex>lbin);
  }
  else
  {
    zf=gpui(x,gneg(a),l1);
    zz=gdivsg(-1,x); s=gun;
    for (k=n-1; k>=0; k--)
    {
      p1=gdivgs(gmul(gmul(gaddgs(a,k),gaddgs(a1,k)),zz),k+1);
      s=gadd(gun,gmul(p1,s));
    }
    u = gmul(s,zf);
  }
  gaffect(u,y); avma=av; return y;
}

GEN
kbessel2(GEN nu, GEN x, long prec)
{
  long av = avma,tetpil;
  GEN p1,p2,x2,a,pitemp;

  if (typ(x)==t_REAL) prec = lg(x);
  x2=gshift(x,1); pitemp=mppi(prec);
  if (gcmp0(gimag(nu))) a=cgetr(prec);
  else
  { a=cgetg(3,t_COMPLEX); a[1]=lgetr(prec); a[2]=lgetr(prec); }
  gaddz(gun,gshift(nu,1),a);
  p1=hyperu(gshift(a,-1),a,x2,prec);
  p1=gmul(gmul(p1,gpui(x2,nu,prec)),mpsqrt(pitemp)); 
  p2=gexp(x,prec); tetpil=avma;
  return gerepile(av,tetpil,gdiv(p1,p2));
}

GEN
eint1(GEN x, long prec)
{
  long av = avma,tetpil,l,n,i;
  GEN p1,p2,p3,p4;

  if (typ(x)!=t_REAL) { gaffect(x,p1=cgetr(prec)); x=p1; }
  if (expo(x)>=4)
  {
    tetpil=avma; return gerepile(av,tetpil,incgam2(gzero,x,prec));
  }

  l=lg(x); n = -bit_accuracy(l)-1;
  p1=cgetr(l); affsr(1,p1); p2=p1; p3=p1; p4=p1; i=1;
  while (expo(p2)>=n)
  {
    i++; p1=gadd(p1,gdivgs(gun,i)); p4=gdivgs(gmul(x,p4),i);
    p2=gmul(p4,p1); p3=gadd(p2,p3);
  }
  p3=gmul(x,gmul(mpexp(negr(x)),p3)); consteuler(l);
  p1=gadd(mplog(x),geuler); tetpil=avma;
  return gerepile(av,tetpil,gsub(p3,p1));
}

GEN
veceint1(GEN nmax, GEN C, long prec)
{
  long av,av1,k,n,nstop,i,cd,nmin,G;
  GEN y,e1,e2,F0,F,M2,f,den,minvn,mcn,p1,vdiff,a,ap,unr,zeror,deninit;
  
  if (signe(nmax)<=0) return cgetg(1,t_VEC);
  if (typ(C) != t_REAL || lg(C) > prec)
    { a = cgetr(prec); gaffect(C,a); C = a; }
  if (signe(C) <= 0) err(talker,"negative or zero constant in veceint1");

  G = -bit_accuracy(prec);
  n=itos(nmax); y=cgetg(n+1,t_VEC);
  for(i=1; i<=n; i++) y[i]=lgetr(prec);
  av=avma;

  nstop = itos(gceil(divsr(4,C)));
  if (nstop<1) nstop=1;
  if (nstop>n) nstop=n;
  nmin=n-10; if (nmin<nstop) nmin=nstop;
  if(DEBUGLEVEL>=2) fprintferr("nstop = %ld ",nstop);

  e1=mpexp(negr(mulsr(n,C)));
  e2=mpexp(mulsr(10,C));
  unr = cgetr(prec); affsr(1,unr);
  zeror=realzero(prec); deninit=negr(unr);
  f=cgetg(3,t_COL); M2=cgetg(3,t_VEC); av1=avma;

  F0=(GEN)y[n];
  affrr(eint1(mulsr(n,C),prec), F0);
  do
  {
    minvn=divrs(unr,-n); mcn=mulrr(C,minvn);
    M2[1] = (long)zeror; M2[2] = lsubrr(minvn,C);
    f[1]=(long)zeror; f[2]=ldivrs(e1,-n); 
    affrr(mulrr(e1,e2), e1);
    vdiff=cgetg(2,t_VEC); vdiff[1]=f[2];
    a=unr; cd=1;
    for (n--; n>=nmin; n--)
    {
      F = F0;
      ap = a; den = deninit;
      for (k=1;;)
      {
	if (k>cd)
        {
          cd++; p1 = (GEN)f[2];
          f[2] = lmul(M2,f);
          f[1] = (long)p1;
          M2[1] = laddrr((GEN)M2[1],mcn);
          M2[2] = laddrr((GEN)M2[2],minvn);
          vdiff = concatsp(vdiff,(GEN)f[2]);
        }
	p1 = mulrr(mulrr(den,ap),(GEN)vdiff[k]);
        if (expo(p1) < G) break;
	F = addrr(F,p1); ap = mulrr(ap,a);
	k++; den = divrs(den,-k);
      }
      affrr(F,(GEN)y[n]);
      a = addrr(a,unr);
    }
    avma=av1; n++; F0=(GEN)y[n]; nmin -= 10;
    if (nmin < nstop) nmin=nstop;
  }
  while(n>nstop);
  for(i=1; i<=nstop; i++)
    affrr(eint1(mulsr(i,C),prec), (GEN)y[i]);
  avma=av; return y;
}  

GEN
gerfc(GEN x, long prec)
{
  long av=avma;
  GEN p1,p2,pitemp;

  if (typ(x)!=t_REAL) { p1=cgetr(prec); gaffect(x,p1); x=p1; }
  av=avma; p1=incgam(ghalf,gsqr(x),prec);
  pitemp=mppi(lg(x)); p2=mpsqrt(pitemp); p1=divrr(p1,p2);
  if (signe(x) < 0) p1 = subsr(2,p1);
  return gerepileupto(av,p1);
}

GEN
incgam(GEN a, GEN x, long prec)
{
  long av=avma,tetpil;
  GEN p1,p2;

  if (typ(x)!=t_REAL) { gaffect(x,p1=cgetr(prec)); x=p1; }
  if (gcmp(subrs(x,1),a) > 0 || gsigne(greal(a)) <= 0)
  {
    tetpil=avma; return gerepile(av,tetpil,incgam2(a,x,prec));
  }

  p2=ggamma(a,prec); p1=incgam3(a,x,prec); tetpil=avma;
  return gerepile(av,tetpil,gsub(p2,p1));
}

GEN
incgam1(GEN a, GEN x, long prec)
{
  long av=avma,tetpil,l,n,i;
  GEN p1,p2,p3,y;
  double m,mx;

  if (typ(x)!=t_REAL) { gaffect(x,p1=cgetr(prec)); x=p1; }
  l=lg(x); mx=rtodbl(x);
  m=(long) bit_accuracy(l)*LOG2; n=(long)(m/(log(m)-(1+log(mx))));
  gaffect(gadd(gun,gsub(x,a)),p2=cgetr(l)); p3=subrs(p2,n+1);
  for (i=n; i>=1; i--)
    p3=addrr(subrs(p2,i),divrr(mulsr(i,x),p3));
  y=gmul(mpexp(negr(x)),gpui(x,a,prec)); tetpil=avma;
  return gerepile(av,tetpil,divrr(y,p3));
}

GEN
incgam2(GEN a, GEN x, long prec)
{
  long av=avma,tetpil,l,n,i;
  GEN p1,p2,p3,y;
  double m,mx;

  if (typ(x)!=t_REAL) { gaffect(x,p1=cgetr(prec)); x=p1; }
  l=lg(x); mx=rtodbl(x);
  m = (bit_accuracy(l)*LOG2 + mx)/4; n=(long)(1+m*m/mx);
  gaffect(gsub(x,a),p2=cgetr(l));
  p3=gdiv(gsubgs(a,n),addrs(p2,(n<<1)));
  for (i=n-1; i>=1; i--)
    p3=gdiv(gsubgs(a,i),addrr(addrs(p2,(i<<1)),gmulsg(i,p3)));
  p3=gadd(gun,p3); y=gmul(mpexp(negr(x)),gpui(x,gsubgs(a,1),prec));
  tetpil=avma; return gerepile(av,tetpil,gmul(y,p3));
}

GEN
incgam3(GEN a, GEN x, long prec)
{
  long av=avma,tetpil,l,n,i;
  GEN p1,p2,p3,y;

  if (typ(x)!=t_REAL) { gaffect(x,p1=cgetr(prec)); x=p1; }
  l=lg(x); n = -bit_accuracy(l)-1;
  p3=cgetr(l); affsr(1,p3); p2=gcopy(p3); i=0;
  while (expo(p2)>=n)
  {
    i++; p2=gdiv(gmul(x,p2),gaddgs(a,i));
    p3=gadd(p2,p3);
  }
  y=gdiv(gmul(mpexp(negr(x)),gpui(x,a,prec)),a);
  tetpil=avma; return gerepile(av,tetpil,gmul(y,p3));
}

/* One assumes that z=gamma(a,prec). Unchecked! */
GEN
incgam4(GEN a, GEN x, GEN z, long prec)
{
  long av,tetpil;
  GEN p1,p2;

  av=avma;
  if (typ(x)!=t_REAL) { gaffect(x,p1=cgetr(prec)); x=p1; }
  if (gcmp(subrs(x,1),a) > 0 || gsigne(greal(a)) <= 0)
  {
    tetpil=avma; return gerepile(av,tetpil,incgam2(a,x,prec));
  }
  p2=incgam3(a,x,prec); tetpil=avma;
  return gerepile(av,tetpil,gsub(z,p2));
}

GEN
incgam0(GEN a, GEN x, GEN z,long prec)
{
  return gcmp0(z)? incgam(a,x,prec): incgam4(a,x,z,prec);
}

/***********************************************************************/
/**								      **/
/**		        FONCTION ZETA DE RIEMANN                      **/
/**								      **/
/***********************************************************************/

static GEN
czeta(GEN s, long prec)
{
  long av,n,p,n1,l,flag1,flag2,flag3,i,i2;
  double st,sp,sn,ssig,ns,alpha,beta,maxbeta,xinf;
  GEN y,z,res,sig,ms,p1,p2,p3,p31,pitemp;

  l=precision(s); 
  if (typ(s)==t_COMPLEX)
  {
    if (!l) l=prec;
    res=cgetg(3,t_COMPLEX); res[1]=lgetr(l); res[2]=lgetr(l);
    av=avma;
    p1=cgetg(3,t_COMPLEX); p1[1]=lgetr(l+1); p1[2]=lgetr(l+1);
    gaffect(s,p1); s=p1; sig=(GEN)s[1];
  }
  else
  {
    res = cgetr(l); av=avma;
    p1=cgetr(l+1); affrr(s,p1); sig=s=p1;
  }

  if (signe(sig)>0 && expo(sig)>-2) flag1 = 0;
  else
  {
    if (gcmp0(gimag(s)) && gcmp0(gfrac(gmul2n(sig,-1))))
    {
      if (gcmp0(sig)) gaffect(gneg(ghalf),res); else gaffsg(0,res);
      avma=av; return res;
    }
    flag1=1; s=gsub(gun,s); sig=greal(s);
  }
  ssig=rtodbl(sig); st=fabs(rtodbl(gimag(s))); maxbeta = pow(3.0,-2.5);
  if (st)
  {
    ns = ssig*ssig + st*st;
    alpha=pariC2*(prec-2)-0.39-0.5*(ssig-1.0)*log(ns)-log(ssig)+ssig*2*pariC1;
    beta=(alpha+ssig)/st-atan(ssig/st);
    if (beta<=0)
    {
      if (ssig>=1.0)
      {
	p=0; sn=sqrt(ns);
	n=(long)(ceil(exp(pariC2*(prec-2)/ssig)*pow(sn/(2*ssig),1.0/ssig)));
      }
      else
      {
	p=1; sn=ssig+1; n=(long)ceil(sqrt(sn*sn+st*st)/(2*PI));
      }
    }
    else
    {
      if (beta<maxbeta) xinf=beta+pow(3*beta,1.0/3.0);
      else
      {
	double eps=0.0087, x00 = beta+PI/2.0, y00,x11;
        for(;;)
	{
	  y00=x00*x00; x11=(beta+atan(x00))*(1+y00)/y00-1/x00;
	  if (x00-x11 < eps) break;
	  x00 = x11;
	}
	xinf=x11;
      }
      sp=1.0-ssig+st*xinf;
      if (sp>0)
      {
	p=(long)(ceil(sp/2.0)); sn=ssig+2*p-1;
	n=(long)(ceil(sqrt(sn*sn+st*st)/(2*PI)));
      }
      else
      {
	p=0; sn=sqrt(ns);
	n=(long)(ceil(exp(pariC2*(prec-2)/ssig)*pow(sn/(2*ssig),1.0/ssig)));
      }
    }
  }
  else
  {
    beta=pariC2*(prec-2)+0.61+ssig*2*pariC1-ssig*log(ssig);
    if (beta>0)
    {
      p=(long)ceil(beta/2.0); sn=ssig+2*p-1;
      n=(long)ceil(sqrt(sn*sn+st*st)/(2*PI));
    }
    else
    {
      p=0; sn=sqrt(ssig*ssig+st*st);
      n=(long)ceil(exp(pariC2*(prec-2)/ssig)*pow(sn/(2*ssig),1.0/ssig));
    }
  }
  if (n < 46340) { flag2=1; n1=n*n; } else flag2=0;
  y=gun; ms=gneg(s); p1=cgetr(prec+1);
  for (i=2; i<=n; i++)
  {
    affsr(i,p1); p2 = gexp(gmul(ms,mplog(p1)), prec+1);
    y = gadd(y,p2);
  }
  flag3 = (2*p < 46340);
  mpbern(p,prec+1); p31=cgetr(prec+1); z=gzero;
  for (i=p; i>=1; i--)
  {
    i2=i<<1;
    p1=gmul(gaddsg(i2-1,s),gaddsg(i2,s));
    p1=flag3? gdivgs(p1,i2*(i2+1)): gdivgs(gdivgs(p1,i2),i2+1);
    p1=flag2? gdivgs(p1,n1): gdivgs(gdivgs(p1,n),n);
    p3 = bern(i);
    if (bernzone[2]>prec+1) { affrr(p3,p31); p3=p31; }
    z=gadd(divrs(p3,i),gmul(p1,z));
  }
  p1=gsub(gdivsg(n,gsubgs(s,1)),ghalf);
  z=gmul(gadd(p1,gmul(s,gdivgs(z,n<<1))),p2);
  y = gadd(y,z);
  if (flag1)
  {
    pitemp=mppi(prec+1); setexpo(pitemp,2);
    y=gmul(gmul(y,ggamma(s,prec+1)),gpui(pitemp,ms,prec+1));
    setexpo(pitemp,0);
    y=gmul2n(gmul(y,gcos(gmul(pitemp,s),prec+1)),1);
  }
  gaffect(y,res); avma=av; return res;
}

/* y = binomial(n,k-2). Return binomial(n,k) */
static GEN
next_bin(GEN y, long n, long k)
{
  y = divrs(mulrs(y, n-k+2), k-1); 
  return divrs(mulrs(y, n-k+1), k);
}

static GEN
izeta(long k, long prec)
{
  long av=avma,tetpil,kk,n,li;
  GEN y,p1,pitemp,qn,z,q,binom;

  if (!k) return gneg(ghalf);
  if (k<0)
  {
    if ((k&1)==0) return gzero;
    y=bernreal(1-k,prec); tetpil=avma;
    return gerepile(av,tetpil,divrs(y,k-1));
  }
  if (k > bit_accuracy(prec)+1)
  { 
    y=cgetr(prec); affsr(1,y); return y;
  }

  pitemp=mppi(prec); setexpo(pitemp,2);
  binom = cgetr(prec+1); affsr(1,binom);
  li = -(1+bit_accuracy(prec)); 
  if (k&1)
  {
    kk = k+1;
    if ((k&3)==3)
    {
      for (n=0; n <= kk>>1; n+=2)
      {
        p1 = mulrr(bernreal(kk-n,prec),bernreal(n,prec));
        if (n) { binom = next_bin(binom,kk,n); setlg(binom,prec+1); }
	p1 = mulrr(binom,p1);
	if (n == kk>>1) setexpo(p1, expo(p1)-1);
        if ((n>>1)&1) setsigne(p1,-signe(p1));
        y = n? addrr(y,p1): p1;
      }
      y=mulrr(divrr(gpuigs(pitemp,k),mpfactr(kk,prec)),y);
      q=mpexp(pitemp); z=divsr(1,addrs(q,-1)); qn=q;
      for (n=2; ; n++)
      {
	qn=mulrr(qn,q); p1=divsr(1,mulir(gpuigs(stoi(n),k),addrs(qn,-1)));
	z=addrr(z,p1); if (expo(p1)< li) break;
      }
      setexpo(z,expo(z)+1); tetpil = avma;
      y = addrr(y,z); setsigne(y,-signe(y));
      return gerepile(av,tetpil,y);
    }

    for (n=0; n <= (k-1)>>1; n+=2)
    {
      p1 = mulrr(bernreal(kk-n,prec),bernreal(n,prec));
      if (n) binom = next_bin(binom,kk,n);
      p1 = mulrr(binom,p1);
      p1 = mulsr(kk-(n<<1),p1);
      if ((n>>1)&1) setsigne(p1,-signe(p1));
      y = n? addrr(y,p1): p1;
    }
    y = mulrr(divrr(gpuigs(pitemp,k),mpfactr(kk,prec)),y);
    y = divrs(y,k-1); q = mpexp(pitemp);
    z=gzero; affsr(1,qn=cgetr(prec));
    for (n=1; ; n++)
    {
      qn=mulrr(qn,q); p1=mulir(gpuigs(stoi(n),k),gsqr(addrs(qn,-1)));
      p1=divrr(addrs(mulrr(qn,addsr(1,divrs(mulsr(n<<1,pitemp),k-1))),-1),p1);
      z=addrr(z,p1); if (expo(p1) < li) break;
    }
    setexpo(z,expo(z)+1); tetpil=avma;
    return gerepile(av,tetpil,subrr(y,z));
  }
  p1 = mulrr(gpuigs(pitemp,k),absr(bernreal(k,prec)));
  y = mpfactr(k,prec); tetpil=avma;
  y=divrr(p1,y); setexpo(y,expo(y)-1);
  return gerepile(av,tetpil,y);
}

GEN
gzeta(GEN x, long prec)
{
  if (gcmp1(x)) err(talker,"argument equal to one in zeta");
  switch(typ(x))
  {
    case t_INT:
      return izeta(itos(x),prec);

    case t_REAL: case t_COMPLEX:
      return czeta(x,prec);

    case t_INTMOD: case t_PADIC:
      err(typeer,"gzeta");
    case t_SER:
      err(impl,"zeta of power series");
  }
  return transc(gzeta,x,prec);
}

void
gzetaz(GEN x, GEN y)
{
  long av=avma, prec = precision(y);

  if (!prec) err(infprecer,"gzetaz");
  gaffect(gzeta(x,prec),y); avma=av;
}

/***********************************************************************/
/**                                                                   **/
/**                    FONCTIONS POLYLOGARITHME                       **/
/**                                                                   **/
/***********************************************************************/

/* validity domain contains .005 < |x| < 230 */
static GEN
cxpolylog(long m, GEN x, long prec)
{
  long av=avma,li,i,n,bern_upto;
  GEN p1,z,h,q,s;

  if (gcmp1(x)) return izeta(m,prec);
  z=glog(x,prec); h=gneg(glog(gneg(z),prec));
  for (i=1; i<m; i++) h = gadd(h,ginv(stoi(i)));

  bern_upto=m+50; mpbern(bern_upto,prec);
  q=gun; s=izeta(m,prec);
  for (n=1; n<=m+1; n++)
  { 
    q=gdivgs(gmul(q,z),n);
    s=gadd(s,gmul((n==(m-1))? h: izeta(m-n,prec),q));
  }

  n = m+3; z=gsqr(z); li = -(bit_accuracy(prec)+1);

  for(;;)
  {
    q = gdivgs(gmul(q,z),(n-1)*n);
    p1 = gmul(izeta(m-n,prec),q);
    s = gadd(s,p1);
    if (gexpo(p1) < li) break;
    n+=2;
    if (n>=bern_upto) { bern_upto += 50; mpbern(bern_upto,prec); }
  }
  return gerepileupto(av,s);
}

GEN
polylog(long m, GEN x, long prec)
{
  long av,av1,limpile,tetpil,l,e,sx,i;
  GEN p1,p2,n,y,logx,logx2;
  GEN *gptr[4];

  if (m<0) err(talker,"negative index in polylog");
  if (!m) return gneg(ghalf);
  if (gcmp0(x)) return gcopy(x);
  av=avma;
  if (m==1)
  {
    p1=glog(gsub(gun,x),prec); tetpil=avma;
    return gerepile(av,tetpil,gneg(p1));
  }
  l=precision(x);
  if (!l) { l=prec; p1=cgetr(l); affsr(1,p1); x=gmul(p1,x); }
  e=gexpo(gnorm(x)); if (!e || e== -1) return cxpolylog(m,x,prec);
  if (e>0)
  {
    logx=glog(x,l); sx=gsigne(gimag(x));
    if (!sx)
    { 
      if (m&1)
        sx = gsigne(greal(gsub(gun,x)));
      else
        sx = -gsigne(greal(x));
    }
    x=ginv(x);
  }
  av1=avma; limpile=(av1+bot)>>1;
  y=x; n=gun; p1=x;
  do
  {
    n=addsi(1,n); p1=gmul(x,p1); p2=gdiv(p1,gpuigs(n,m));
    y=gadd(y,p2);
    if (low_stack(limpile, (av1+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"polylog");
      gptr[0]=&y; gptr[1]=&n; gptr[2]=&p1; gptr[3]=&p2;
      gerepilemany(av1,gptr,4);
    }
  }
  while (gexpo(p2) > -bit_accuracy(l));
  tetpil=avma;
  if (e<=0) return gerepile(av,tetpil,gcopy(y));
  logx2=gsqr(logx); p1=gneg(ghalf);
  for (i=m-2; i>=0; i-=2)
  {
    p1 = gadd(izeta(m-i,l), gmul(p1,gdivgs(logx2,(i+1)*(i+2))));
  }
  if (m&1) p1 = gmul(logx,p1);
  p2=cgetg(3,t_COMPLEX); p2[1]=zero;
  p2[2]=ldiv(gmulsg(sx,mppi(l)),mpfact(m-1));
  p1=gadd(gmul2n(p1,1), gmul(p2,gpuigs(logx,m-1)));
  if ((m&1) == 0) y = gneg(y);
  tetpil=avma; return gerepile(av,tetpil,gadd(p1,y));
}

GEN
dilog(GEN x, long prec)
{
  GEN p1,p2,p3,y;
  long av=avma,tetpil;
  
  if (gcmpgs(gnorm(x),1)<1)
  {
    tetpil=avma; return gerepile(av,tetpil,polylog(2,x,prec));
  }
  y=gneg(polylog(2,ginv(x),prec)); p3=mppi(prec); p2=gdivgs(gsqr(p3),6);
  p1=glog(gneg(x),prec); p1=gadd(p2,gmul2n(gsqr(p1),-1));
  tetpil=avma; return gerepile(av,tetpil,gsub(y,p1));
}

GEN
polylogd0(long m, GEN x, long flag, long prec)
{
  long k,l,av,tetpil,fl,m2;
  GEN p1,p2,p3,y;

  m2=m&1; av=avma;
  if (gcmp0(x)) return gcopy(x);
  if (gcmp1(x) && m>=2) return m2?izeta(m,prec):gzero;
  l=precision(x);
  if (!l) { l=prec; p1=cgetr(l); affsr(1,p1); x=gmul(p1,x); }
  p1=gabs(x,prec); fl=0;
  if (gcmpgs(p1,1)>0) { x=ginv(x); p1=gabs(x,prec); fl=!m2; }

  p1=gneg(glog(p1,prec)); p2=gun;
  y=polylog(m,x,prec); y=m2?greal(y):gimag(y);
  for (k=1; k<m; k++)
  {
    p2=gdivgs(gmul(p2,p1),k);
    p3=m2?greal(polylog(m-k,x,prec)):gimag(polylog(m-k,x,prec));
    tetpil=avma; y=gadd(y,gmul(p2,p3));
  }
  if (m2)
  {
    if (flag)
      p2 = gdivgs(gmul(p2,p1),-2*m);
    else
      p2 = gdivgs(gmul(glog(gnorm(gsub(gun,x)),prec),p2),2*m);
    tetpil=avma; y=gadd(y,p2);
  }
  if (fl) { tetpil=avma; return gerepile(av,tetpil,gneg(y)); }
  return gerepile(av,tetpil,y);
}

GEN
polylogd(long m, GEN x, long prec)
{
  return polylogd0(m,x,0,prec);
}

GEN
polylogdold(long m, GEN x, long prec)
{
  return polylogd0(m,x,1,prec);
}

GEN
polylogp(long m, GEN x, long prec)
{
  long k,l,av,tetpil,fl,m2;
  GEN p1,y;

  m2=m&1; av=avma;
  if (gcmp0(x)) return gcopy(x);
  if (gcmp1(x) && m>=2) return m2?izeta(m,prec):gzero;
  l=precision(x);
  if (!l) { l=prec; p1=cgetr(l); affsr(1,p1); x=gmul(p1,x); }
  p1=gabs(x,prec); fl=0;
  if (gcmpgs(p1,1)>0) { x=ginv(x); p1=gabs(x,prec); fl=!m2; }

  p1=gmul2n(glog(p1,prec),1); mpbern(m>>1,prec);
  y=polylog(m,x,prec); y=m2?greal(y):gimag(y);
  
  if (m==1)
  {
    p1=gmul2n(p1,-2); tetpil=avma; y=gadd(y,p1);
  }
  else
  {
    GEN p2=gun, p3, p4, p5, p51=cgetr(prec);

    for (k=1; k<m; k++)
    {
      p2=gdivgs(gmul(p2,p1),k);
      if (!(k&1) || k==1)
      {
	if (k!=1)
	{
	  p5=(GEN)bern(k>>1);
	  if (bernzone[2]>prec) { affrr(p5,p51); p5=p51; }
	  p4=gmul(p2,p5);
	}
	else p4=gneg(gmul2n(p2,-1));
	p3=polylog(m-k,x,prec); p3=m2?greal(p3):gimag(p3);
	tetpil=avma; y=gadd(y,gmul(p4,p3));
      }
    }
  }
  if (fl) { tetpil=avma; return gerepile(av,tetpil,gneg(y)); }
  return gerepile(av,tetpil,y);
}

GEN
gpolylog(long m, GEN x, long prec)
{
  long i,lx,av=avma,tetpil,v,n;
  GEN y,p1,p2;

  if (m<=0)
  {
    p1=polx[0]; p2=gsub(gun,p1);
    for (i=1; i<=(-m); i++)
      p1=gmul(polx[0],gadd(gmul(p2,deriv(p1,0)),gmulsg(i,p1)));
    p1=gdiv(p1,gpuigs(p2,1-m)); tetpil=avma;
    return gerepile(av,tetpil,poleval(p1,x));
  }

  switch(typ(x))
  {
    case t_INT: case t_REAL: case t_FRAC: case t_FRACN:
    case t_COMPLEX: case t_QUAD:
      return polylog(m,x,prec);

    case t_INTMOD: case t_PADIC: case t_POLMOD:
      p1=roots((GEN)x[1],prec); lx=lg(p1); p2=cgetg(lx,t_COL);
      for (i=1; i<lx; i++) p2[i]=lpoleval((GEN)x[2],(GEN)p1[i]);
      tetpil=avma; y=cgetg(lx,t_COL);
      for (i=1; i<lx; i++) y[i]=(long)polylog(m,(GEN)p2[i],prec);
      return gerepile(av,tetpil,y);

    case t_POL: case t_RFRAC: case t_RFRACN:
      p1=tayl(x,gvar(x),precdl); tetpil=avma;
      return gerepile(av,tetpil,gpolylog(m,p1,prec));

    case t_SER:
      if (!m) return gneg(ghalf);
      if (m==1)
      {
	p1=glog(gsub(gun,x),prec); tetpil=avma;
	return gerepile(av,tetpil,gneg(p1));
      }
      if (valp(x)<=0) err(impl,"polylog around a!=0");
      v=varn(x); n=(lg(x)-2)/valp(x); y=ggrando(polx[v],lg(x)-2);
      for (i=n; i>=1; i--)
      {
	p1=gadd(gpuigs(stoi(i),-m),y); tetpil=avma;
	y=gmul(x,p1);
      }
      return gerepile(av,tetpil,y);

    case t_VEC: case t_COL: case t_MAT:
      lx=lg(x); y=cgetg(lx,typ(x));
      for (i=1; i<lx; i++)
	y[i]=(long)gpolylog(m,(GEN)x[i],prec);
      return y;
  }
  err(typeer,"gpolylog");
  return NULL; /* not reached */
}

void
gpolylogz(long m, GEN x, GEN y)
{
  long av=avma, prec = precision(y);

  if (!prec) err(infprecer,"gpolylogz");
  gaffect(gpolylog(m,x,prec),y); avma=av;
}

GEN
polylog0(long m, GEN x, long flag, long prec)
{
  switch(flag)
  {
    case 0: return gpolylog(m,x,prec);
    case 1: return polylogd(m,x,prec);
    case 2: return polylogdold(m,x,prec);
    case 3: return polylogp(m,x,prec);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}

static GEN
qq(GEN x, long prec)
{
  long tx=typ(x);

  if (tx==t_PADIC) return x;
  if (is_scalar_t(tx))
  {
    long l=precision(x);
    GEN p1,p2,q;
    
    if (tx != t_COMPLEX || gcmp((GEN)x[2],gzero)<=0)
      err(talker,"argument must belong to upper half-plane");

    if (!l) l=prec; p1=mppi(l); setexpo(p1,2);
    p2=cgetg(3,t_COMPLEX); p2[1]=zero; p2[2]=(long)p1; /* 2*I*Pi */
    q=gmul(x,p2); return gexp(q,prec);
  }
  if (tx != t_POL && tx != t_SER)
    err(talker,"bad argument for modular function");

  return tayl(x,gvar(x),precdl);
}

static GEN
inteta(GEN q)
{
  long tx=typ(q);
  GEN p1,ps,qn,y;

  y=gun; qn=gun; ps=gun;
  if (tx==t_PADIC)
  {
    for(;;)
    {
      p1=gneg(gmul(ps,gmul(q,gsqr(qn))));
      y=gadd(y,p1); qn=gmul(qn,q); ps=gmul(p1,qn);
      p1=y; y=gadd(y,ps); if (gegal(p1,y)) return y;
    }
  }
  else
  {
    long l,v, av = avma, lim = (av+7*bot)>>3;

    if (is_scalar_t(tx)) l = -bit_accuracy(precision(q));
    else 
      { v=gvar(q); tx = 0; }
    for(;;)
    {
      p1=gneg(gmul(ps,gmul(q,gsqr(qn))));
      y=gadd(y,p1); qn=gmul(qn,q); ps=gmul(p1,qn);
      y=gadd(y,ps);
      if (tx)
        { if (gexpo(ps)-gexpo(y) < l) return y; }
      else
        { if (gcmp0(ps) || gval(ps,v)>=precdl) return y; }
      if (low_stack(lim, (av+7*bot)>>3))
      {
        GEN *gptr[3];
        if(DEBUGMEM>1) err(warnmem,"inteta");
        gptr[0]=&y; gptr[1]=&qn; gptr[2]=&ps;
        gerepilemany(av,gptr,3);
      }
    }
  }
}

GEN
eta(GEN x, long prec)
{
  long av = avma;
  GEN q = qq(x,prec);
  return gerepileupto(av,inteta(q));
}

/* returns the true value of eta(x) for Im(x) > 0, using reduction */
GEN
trueeta(GEN x, long prec)
{
  long tx=typ(x), av=avma, tetpil,l;
  GEN p1,p2,q,q24,no,n,z,m,unapprox;

  if (!is_scalar_t(tx)) err(typeer,"trueeta");
  if (tx != t_COMPLEX || gcmp((GEN)x[2],gzero)<=0)
    err(talker,"argument must belong to upper half-plane");
  l=precision(x); if (l) prec=l;
  p1=mppi(prec); setexpo(p1,2);
  p2=cgetg(3,t_COMPLEX); p2[1]=zero; p2[2]=(long)p1; /* 2*I*Pi */
  z=gexp(gdivgs(p2,24),prec); /* exp(2*I*Pi/24) */
  unapprox=gsub(gun,gpuigs(stoi(10),-8));
  m=gun;
  for(;;)
  {
    n=ground(greal(x));
    if(signe(n)) {x=gsub(x,n); m=gmul(m,gpui(z,n,0));}
    no=gnorm(x); if (gcmp(no,unapprox)>=0) break;
    m=gmul(m,gsqrt(gdiv(gi,x),prec)); x=gdivsg(-1,x);
  }
  q=gmul(p2,x); 
  q24=gexp(gdivgs(q,24),prec); q=gpuigs(q24,24);
  p1=gmul(m,q24); q = inteta(q); tetpil=avma;
  return gerepile(av,tetpil,gmul(p1,q));
}

GEN
eta0(GEN x, long flag,long prec)
{
  return flag? trueeta(x,prec): eta(x,prec);
}

GEN
jell(GEN x, long prec)
{
  long av=avma,tetpil;
  GEN p1,p2;
  
  p1=gdiv(trueeta(gmul2n(x,1),prec),trueeta(x,prec));
  p1=gsqr(gsqr(gsqr(p1)));
  p2=gmul2n(gsqr(p1),8); p1=gadd(p2,ginv(p1));
  tetpil=avma;
  return gerepile(av,tetpil,gpuigs(p1,3));
}

GEN
wf2(GEN x, long prec)
{
  long av=avma,tetpil;
  GEN p1,p2;

  p1=gsqrt(gdeux,prec);
  p2=gdiv(trueeta(gmul2n(x,1),prec),trueeta(x,prec));
  tetpil=avma;
  return gerepile(av,tetpil,gmul(p1,p2));
}

GEN
wf1(GEN x, long prec)
{
  long av=avma,tetpil;
  GEN p1,p2;

  p1=trueeta(gmul2n(x,-1),prec); p2=trueeta(x,prec);
  tetpil=avma;
  return gerepile(av,tetpil,gdiv(p1,p2));
}

GEN
wf(GEN x, long prec)
{
  long av=avma,tetpil;
  GEN p1,p2;

  p1=gdiv(trueeta(gmul2n(gaddgs(x,1),-1),prec),trueeta(x,prec));  
  p2=cgetg(3,t_COMPLEX); p2[1]=zero; p2[2]=ldivrs(mppi(prec),-24);
  p2=gexp(p2,prec); tetpil=avma;
  return gerepile(av,tetpil,gmul(p1,p2));
}

GEN
weber0(GEN x, long flag,long prec)
{
  switch(flag)
  {
    case 0: return wf(x,prec);
    case 1: return wf1(x,prec);
    case 2: return wf2(x,prec);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}

static GEN
sagm(GEN x, long prec)
{
  GEN p1,a,b,a1,b1,y;
  long av,tetpil,l,ep;

  if (gcmp0(x)) return gcopy(x);
  switch(typ(x))
  {
    case t_REAL: 
      l = precision(x); y = cgetr(l); av=avma;
      a1 = x; b1 = cgetr(l); affsr(1,b1);
      l = 5-bit_accuracy(prec);
      do
      {
	a=a1; b=b1; a1 = addrr(a,b);
        setexpo(a1,expo(a1)-1);
	b1=mpsqrt(mulrr(a,b));
      }
      while (expo(subrr(b1,a1))-expo(b1) >= l);
      affrr(a1,y); avma=av; return y;
    
    case t_COMPLEX:
      if (gcmp0((GEN)x[2]))
        return transc(sagm,(GEN)x[1],prec);
      av=avma; l=precision(x); if (l) prec=l;
      a1=x; b1=gun; l = 5-bit_accuracy(prec);
      do
      {
	a=a1; b=b1;
	a1=gmul2n(gadd(a,b),-1);
	b1=gsqrt(gmul(a,b),prec);
      }
      while (gexpo(gsub(b1,a1))-gexpo(b1) >= l);
      tetpil=avma; return gerepile(av,tetpil,gcopy(a1));

    case t_PADIC:
      av=avma; a1=x; b1=gun; l=precp(x);
      do
      {
	a=a1; b=b1;
	a1=gmul2n(gadd(a,b),-1); b1=gsqrt(gmul(a,b),0);
	p1=gsub(b1,a1); ep=valp(p1)-valp(b1);
	if (ep<=0) { b1=gneg(b1); p1=gsub(b1,a1); ep=valp(p1)-valp(b1); }
      }
      while (ep<l && !gcmp0(p1));
      tetpil=avma; return gerepile(av,tetpil,gcopy(a1));

    case t_SER:
      av=avma; a1=x; b1=gun; l=lg(x)-2;
      do
      {
	a=a1; b=b1;
	a1=gmul2n(gadd(a,b),-1); b1=gsqrt(gmul(a,b),0);
	p1=gsub(b1,a1); ep=valp(p1)-valp(b1);
      }
      while (ep<l && !gcmp0(p1));
      tetpil=avma; return gerepile(av,tetpil,gcopy(a1));

    case t_INTMOD:
      err(impl,"agm of mod");
  }
  return transc(sagm,x,prec);
}

GEN
agm(GEN x, GEN y, long prec)
{
  long av,tetpil, ty=typ(y);
  GEN z;

  if (is_matvec_t(ty))
  {
    ty=typ(x);
    if (is_matvec_t(ty)) err(talker,"agm of two vector/matrices");
    z=x; x=y; y=z;
  }
  if (gcmp0(y)) return gcopy(y);
  av=avma; z=sagm(gdiv(x,y),prec); tetpil=avma;
  return gerepile(av,tetpil,gmul(y,z));
}

GEN
logagm(GEN q)
{
  long av=avma,prec=lg(q),tetpil,s,n,lim;
  GEN y,q4,q1;

  if (typ(q)!=t_REAL) err(typeer,"logagm");
  if (signe(q)<=0) err(talker,"non positive argument in logagm");
  if (expo(q)<0) s=1; else { q=ginv(q); s=0; }
  lim = - (bit_accuracy(prec) >> 1);
  for (n=0; expo(q)>=lim ; n++) { q1=q; q=mulrr(q,q); }
  q4=gmul2n(q,2); constpi(prec+1);
  if (!n) q1=gsqrt(q,prec);
  y=divrr(gpi,agm(addsr(1,q4),gmul2n(q1,2),prec));
  tetpil=avma; y=gmul2n(y,-n); if (s) setsigne(y,-1);
  return gerepile(av,tetpil,y);
}

GEN
glogagm(GEN x, long prec)
{
  long av,tetpil,v;
  GEN y,p1,p2;

  switch(typ(x))
  {
    case t_REAL:
      if (signe(x)>=0) return logagm(x);

      y=cgetg(3,t_COMPLEX); y[2]=lmppi(lg(x));
      setsigne(x,1); y[1]=(long)logagm(x);
      setsigne(x,-1); return y;

    case t_COMPLEX:
      y=cgetg(3,t_COMPLEX); y[2]=larg(x,prec);
      av=avma; p1=glogagm(gnorm(x),prec); tetpil=avma;
      y[1]=lpile(av,tetpil,gmul2n(p1,-1));
      return y;

    case t_PADIC:
      return palog(x);

    case t_SER:
      av=avma; if (valp(x)) err(negexper,"glogagm");
      v=varn(x); p1=gdiv(deriv(x,v),x);
      tetpil=avma; p1=integ(p1,v);
      if (gcmp1((GEN)x[2])) return gerepile(av,tetpil,p1);

      p2=glogagm((GEN)x[2],prec); tetpil=avma;
      return gerepile(av,tetpil,gadd(p1,p2));

    case t_INTMOD:
      err(typeer,"glogagm");
  }
  return transc(glogagm,x,prec);
}

GEN
theta(GEN q, GEN z, long prec)
{
  long av=avma,tetpil,l,n;
  GEN ps,qn,qnold,y,zy,lq,ps2,p1,k,zold;

  if (gexpo(q)>=0) err(thetaer1);
  l=precision(q); if (!l) prec=l;
  p1=cgetr(prec); affsr(1,p1); z=gmul(p1,z);
  if (!l) q=gmul(p1,q);
  if (gcmp0(zy=gimag(z))) k=gzero;
  else
  {
    lq=glog(q,prec); k=ground(gdiv(zy,greal(lq)));
    if (!gcmp0(k)) { zold=z; z=gadd(z,gdiv(gmul(lq,k),gi)); }
  }
  y=gsin(z,prec); n=0; qn=gun; ps=gneg(ps2=gsqr(q));
  do
  {
    n++; p1=gsin(gmulsg(n+n+1,z),prec);
    qnold=qn; qn=gmul(qn,ps);
    ps=gmul(ps,ps2); p1=gmul(p1,qn); y=gadd(y,p1);
  }
  while (gexpo(qnold)>= -bit_accuracy(prec));
  if (signe(k))
  {
    y=gmul(y,gmul(gpui(q,gmul(k,k),prec),
                  gexp(gmul2n(gmul(gmul(gi,zold),k),1),prec)));
    if (mod2(k)) y=gneg(y);
  }
  p1=gmul2n(gsqrt(gsqrt(q,prec),prec),1); tetpil=avma;
  return gerepile(av,tetpil,gmul(p1,y));
}

GEN
thetanullk(GEN q, long k, long prec)
{
  long av=avma,tetpil,l,n;
  GEN p1,ps,qn,y,ps2;

  if (gexpo(q)>=0) err(thetaer1);
  if (!(k&1)) return gzero;
  n=0; qn=gun; ps=gneg(ps2=gsqr(q));
  y=gun; l=precision(q);
  if (!l)
  {
    l=prec; p1=cgetr(prec); affsr(1,p1); q=gmul(p1,q);
  }

  do
  {
    n++; p1=gpuigs(stoi(n+n+1),k); qn=gmul(qn,ps);
    ps=gmul(ps,ps2); p1=gmul(p1,qn); y=gadd(y,p1);
  }
  while (gexpo(p1) >= -bit_accuracy(l));
  p1=gmul2n(gsqrt(gsqrt(q,prec),prec),1); tetpil=avma;
  if (k&2) { p1=gneg(p1); tetpil=avma; }
  return gerepile(av,tetpil,gmul(p1,y));
}

GEN
jbesselh(GEN n, GEN z, long prec)
{
  long av,tetpil,k,l,i,lz;
  GEN y,p1,p2,zinv,p0,s,c;

  if (typ(n)!=t_INT) err(talker,"not an integer index in jbesselh");
  k=itos(n); if (k<0) err(impl,"ybesselh");

  switch(typ(z))
  {
    case t_REAL: case t_COMPLEX:
      if (gcmp0(z)) return gzero;
      av=avma; zinv=ginv(z);
      l=precision(z); if (l>prec) prec=l;
      gsincos(z,&s,&c,prec);
      p1=gmul(zinv,s);
      if (k)
      { 
        p0=p1; p1=gmul(zinv,gsub(p0,c));
	for (i=2; i<=k; i++)
	{
	  p2=gsub(gmul(gmulsg(2*i-1,zinv),p1),p0);
          p0=p1; p1=p2;
	}
      }
      p2=gsqrt(gdiv(gmul2n(z,1),mppi(prec)),prec);
      tetpil=avma; return gerepile(av,tetpil,gmul(p2,p1));

    case t_VEC: case t_COL: case t_MAT:
      lz=lg(z); y=cgetg(lz,typ(z));
      for (i=1; i<lz; i++)
	y[i]=(long)jbesselh(n,(GEN)z[i],prec);
      return y;

    case t_INT: case t_FRAC: case t_FRACN:
      av=avma; p1=cgetr(prec); gaffect(z,p1); tetpil=avma;
      return gerepile(av,tetpil,jbesselh(n,p1,prec));

    case t_QUAD:
      av=avma; p1=cgetr(prec); affsr(1,p1);
      p1=gmul(z,p1); tetpil=avma;
      return gerepile(av,tetpil,jbesselh(n,p1,prec));

    case t_POL: case t_RFRAC: case t_RFRACN:
      av=avma; p1=tayl(z,gvar(z),precdl); tetpil=avma;
      return gerepile(av,tetpil,jbesselh(n,p1,prec));

    case t_POLMOD:
      av=avma; p1=roots((GEN)z[1],prec); lz=lg(p1); p2=cgetg(lz,t_COL);
      for (i=1; i<lz; i++) p2[i]=lpoleval((GEN)z[2],(GEN)p1[i]);
      tetpil=avma; y=cgetg(lz,t_COL);
      for (i=1; i<lz; i++) y[i]=(long)jbesselh(n,(GEN)p2[i],prec);
      return gerepile(av,tetpil,y);

    case t_PADIC:
      err(impl,"p-adic jbessel function");
    case t_SER:
      err(impl,"jbessel of power series");
  }
  err(typeer,"jbesselh");
  return NULL; /* not reached */
}
