view vbang.c @ 0:e0bbaa717f41 draft default tip

lol J
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Mon, 25 Nov 2013 11:56:30 -0500
parents
children
line wrap: on
line source

/* Copyright 1990-2011, Jsoftware Inc.  All rights reserved. */
/* License in license.txt.                                   */
/*                                                                         */
/* Verbs: !                                                                */

#include "j.h"


static Z z1={1, 0};

static D coeff[]={
 0.0, 1.0,            0.5772156649015329, -0.6558780715202538, 
 -0.0420026350340952, 0.1665386113822915, -0.0421977345555443,
 -0.009621971527877,  0.007218943246663,  -0.0011651675918591, 
 -0.0002152416741149, 0.0001280502823882, -0.0000201348547807,
 -0.0000012504934821, 0.000001133027232,  -0.0000002056338417,
 6.116095e-9,         5.0020075e-9,       -1.1812746e-9,
 1.043427e-10,        7.7823e-12,         -3.6968e-12,
 5.1e-13,             -2.06e-14,          -5.4e-15,
 1.4e-15,             1.0e-16
};

static I terms=sizeof(coeff)/sizeof(D);

static Z jtzhorner(J jt,I n,D*c,Z v){Z s;D*d=n+c;
 s=zeroZ;
 DO(n, s=zplus(zrj0(*--d),ztymes(v,s));); 
 R s;
}

static D dgps(D v){D*d=terms+coeff,s=0.0; DO(terms, s=*--d+v*s;); R 1/s;}
     /* Abramowitz & Stegun, 6.1.34 */

static Z jtzgps(J jt,Z z){R zdiv(z1,zhorner(terms,coeff,z));}

static D jtdgamma(J jt,D x){B b;D t;
 t=1.0; b=x==jfloor(x);
 if(b&&0>=x){ASSERT(x>x-1,EVLIMIT); R x==2*jfloor(x/2)?inf:infm;}
 if(0<=x) while(1<x){t*=--x; if(t==inf)R inf;}
 else    {while(0>x){t*=x++; if(t==inf)R 0.0;} t=1.0/t;}
 R b?t:t*dgps(x);
}    /* gamma(x) using recurrence formula */

static Z jtzgrecur(J jt,Z z){Z t;
 t=z1;
 if(0<=z.re) while( 0.5<z.re){--z.re; t=ztymes(t,z); if(t.re==inf)R t;    }
 else       {while(-0.5>z.re){t=ztymes(t,z); ++z.re; if(t.re==inf)R zeroZ;} t=zdiv(z1,t);}
 R ztymes(t,zgps(z));
}    /* gamma(z) using recurrence formula */

static Z jtzgauss(J jt,D n,Z z){D d=1/n;Z p,t;
 if(1>=n)R zgrecur(z);
 p=ztymes(zpow(zrj0(2*PI),zrj0((1-n)/2)),zpow(zrj0(n),zminus(z,zrj0(0.5))));
 t=zdiv(z,zrj0(n));
 DO((I)n, p=ztymes(p,zgrecur(t)); t.re+=d;);
 R p;
}    /* Abramowitz & Stegun, 6.1.20 */

static Z jtzstirling(J jt,Z z){Z p,q;
 static D c[]={1.0, 1.0/12, 1.0/288, -139.0/51840, -571.0/2488320},
  e=2.718281828459045235360287;
 p=ztymes(zsqrt(zdiv(zrj0(2*PI),z)),zpow(zdiv(z,zrj0(e)),z));
 q=zhorner(5L,c,zdiv(z1,z));
 R ztymes(p,q);
}    /* Abramowitz & Stegun, 6.1.37 */

static Z jtzgamma(J jt,Z z){D y=ABS(z.im);
 R !y?zrj0(dgamma(z.re)):20<y?zstirling(z):zgauss(ceil(y/0.8660254),z);
}

AMON(factI,  D,I, *z=dgamma(1.0+(D)*x);)
AMON(factD,  D,D, *z=_isnan(*x)?*x:dgamma(1.0+*x);)
AMON(factZ,  Z,Z, *z=zgamma(zplus(z1,*x));)


#define PQLOOP(expr) while(n&&h&&h!=inf&&h!=infm){h*=expr; --n;}

static D pq(D h,D m,D*c,D*d){D x=*c,y=*d;I n=(I)MIN(m,IMAX);
 if(0>=m)R h;
 switch(2*(0>x)+(0>y)){
  case 0: if(x!= y)PQLOOP(x--/y--); break;
  case 1: if(x!=-y)PQLOOP(x--/y++)else if(m>2*jfloor(0.5*m))h=-h; break;
  case 2: if(x!=-y)PQLOOP(x++/y--)else if(m>2*jfloor(0.5*m))h=-h; break;
  case 3: if(x!= y)PQLOOP(x++/y++); break;
 }
 if(0>=*c)*c+=m; else *c-=m;
 if(0>=*d)*d+=m; else *d-=m;
 R h;
}

static I signf(D x){R 0<=x||1<=x-2*jfloor(0.5*x)?1:-1;}
     /* sign of !x */

static D jtdbin(J jt,D x,D y){D c,d,e,h=1.0,p,q,r;I k=0;
 c=y;   if(0<=c)p=jfloor(c); else{k+=4; ++c; p=jfloor(-c);}
 d=y-x; if(0<=d)q=jfloor(d); else{k+=2; ++d; q=jfloor(-d);}
 e=x;   if(0<=e)r=jfloor(e); else{k+=1; ++e; r=jfloor(-e);}
 switch(k){
  case 0: h=pq(h,q,&c,&d); h=pq(h,r,&c,&e);                break;
  case 1: h=pq(h,p,&c,&d); h=pq(h,r,&e,&d);           --e; break;
  case 2: h=pq(h,p,&c,&e); h=pq(h,q,&d,&e);      --d;      break;
  case 5: h=pq(h,p,&e,&c); h=pq(h,q,&e,&d); --c;      --e; break;
  case 6: h=pq(h,p,&d,&c); h=pq(h,r,&d,&e); --c; --d;      break;
  case 7: h=pq(h,q,&d,&c); h=pq(h,r,&e,&c); --c; --d; --e; break;
 }
 if(!h)R 0; 
 if(h==inf||h==infm)R inf*signf(x)*signf(y)*signf(y-x);
 R h*dgamma(1+c)/(dgamma(1+d)*dgamma(1+e));
}    /* x and y-x are not negative integers */

static D ibin(D x,D y){D d=MIN(x,y-x),p=1;
 DO((I)d, p*=y--/d--; if(p==inf)R p;); 
 R jfloor(0.5+p);
}    /* x and y are non-negative integers; x<=y */

static Z jtzbin(J jt,Z x,Z y){Z a,b,c;
 a=zgamma(zplus(z1,y));
 b=zgamma(zplus(z1,x));
 c=zgamma(zplus(z1,zminus(y,x)));
 R zdiv(a,ztymes(b,c));
}

#define MOD2(x) ((x)-2*jfloor(0.5*(x)))

static D jtbindd(J jt,D x,D y){B id,ix,iy;D d;
 if(_isnan(x))R x; else if(_isnan(y))R y;
 d=y-x; 
 id=d==jfloor(d);
 ix=x==jfloor(x); 
 iy=y==jfloor(y);
 switch(4*(ix&&0>x)+2*(iy&&0>y)+(id&&0>d)){
  default: ASSERTSYS(0,"bindd");
  case 5: /* 1 0 1 */  /* Impossible */
  case 0: /* 0 0 0 */
  case 2: /* 0 1 0 */  R ix&&iy?ibin(x,y):dbin(x,y);
  case 3: /* 0 1 1 */  R (MOD2(x)?-1:1)*ibin(x,x-y-1);
  case 6: /* 1 1 0 */  R (MOD2(d)?-1:1)*ibin(-1-y,-1-x);
  case 1: /* 0 0 1 */ 
  case 4: /* 1 0 0 */ 
  case 7: /* 1 1 1 */  R 0;
}}   /* P.C. Berry, Sharp APL Reference Manual, 1979, p. 132 */

static Z jtbinzz(J jt,Z x,Z y){B id,ix,iy;D rd,rx,ry;Z d;
 if(!x.im&&!y.im)R zrj0(bindd(x.re,y.re));
 d=zminus(y,x);
 rd=d.re; id=rd==jfloor(rd)&&0==d.im;
 rx=x.re; ix=rx==jfloor(rx)&&0==x.im; 
 ry=y.re; iy=ry==jfloor(ry)&&0==y.im;
 switch(4*(ix&&0>rx)+2*(iy&&0>ry)+(id&&0>rd)){
  default: ZASSERT(0,EVSYSTEM);
  case 5: /* 1 0 1 */  /* Impossible */
  case 0: /* 0 0 0 */
  case 2: /* 0 1 0 */  R zbin(x,y);
  case 3: /* 0 1 1 */  R zrj0((MOD2(rx)?-1:1)*ibin(rx,rx-ry-1));
  case 6: /* 1 1 0 */  R zrj0((MOD2(rd)?-1:1)*ibin(-1-ry,-1-rx));
  case 1: /* 0 0 1 */ 
  case 4: /* 1 0 0 */ 
  case 7: /* 1 1 1 */  R zeroZ;
}}


ANAN(binDD, D,D,D, bindd)
ANAN(binZZ, Z,Z,Z, binzz)