📄 tools.c
字号:
p1 = (p<0.5 ? p : 1-p);
if (p1<1e-20) z=999;
else {
y = sqrt (log(1/(p1*p1)));
z = y + ((((y*a4+a3)*y+a2)*y+a1)*y+a0) / ((((y*b4+b3)*y+b2)*y+b1)*y+b0);
}
return (p<0.5 ? -z : z);
}
double CDFNormal (double x)
{
/* Hill ID (1973) The normal integral. Applied Statistics, 22:424-427.
Algorithm AS 66. (error < ?)
adapted by Z. Yang, March 1994. Hill's routine does not look good, and I
haven't consulted
Adams AG (1969) Algorithm 39. Areas under the normal curve.
Computer J. 12: 197-198.
*/
int invers=0;
double p, limit=10, t=1.28, y=x*x/2;
if (x<0) { invers=1; x=-x; }
if (x>limit) return (invers?0:1);
if (x<t)
p = .5 - x * ( .398942280444 - .399903438504 * y
/(y + 5.75885480458 - 29.8213557808
/(y + 2.62433121679 + 48.6959930692
/(y + 5.92885724438))));
else
p = 0.398942280385 * exp(-y) /
(x - 3.8052e-8 + 1.00000615302 /
(x + 3.98064794e-4 + 1.98615381364 /
(x - 0.151679116635 + 5.29330324926 /
(x + 4.8385912808 - 15.1508972451 /
(x + 0.742380924027 + 30.789933034 /
(x + 3.99019417011))))));
return (invers ? p : 1-p);
}
double LnGamma (double x)
{
/* returns ln(gamma(x)) for x>0, accurate to 10 decimal places.
Stirling's formula is used for the central polynomial part of the procedure.
Pike MC & Hill ID (1966) Algorithm 291: Logarithm of the gamma function.
Communications of the Association for Computing Machinery, 9:684
*/
double f=0, fneg=0, z;
if(x<=0) {
error2("lnGamma not implemented for x<0");
if((int)x-x==0) { puts("lnGamma undefined"); return(-1); }
for (fneg=1; x<0; x++) fneg/=x;
if(fneg<0) error2("strange!! check lngamma");
fneg=log(fneg);
}
if (x<7) {
f=1; z=x-1;
while (++z<7) f*=z;
x=z; f=-log(f);
}
z = 1/(x*x);
return fneg+ f + (x-0.5)*log(x) - x + .918938533204673
+ (((-.000595238095238*z+.000793650793651)*z-.002777777777778)*z
+.083333333333333)/x;
}
double DFGamma(double x, double alpha, double beta)
{
/* mean=alpha/beta; var=alpha/beta^2
*/
if (alpha<=0 || beta<=0) error2("err in DFGamma()");
if (alpha>100) error2("large alpha in DFGamma()");
return pow(beta*x,alpha)/x * exp(-beta*x - LnGamma(alpha));
}
double IncompleteGamma (double x, double alpha, double ln_gamma_alpha)
{
/* returns the incomplete gamma ratio I(x,alpha) where x is the upper
limit of the integration and alpha is the shape parameter.
returns (-1) if in error
ln_gamma_alpha = ln(Gamma(alpha)), is almost redundant.
(1) series expansion if (alpha>x || x<=1)
(2) continued fraction otherwise
RATNEST FORTRAN by
Bhattacharjee GP (1970) The incomplete gamma integral. Applied Statistics,
19: 285-287 (AS32)
*/
int i;
double p=alpha, g=ln_gamma_alpha;
/* double accurate=1e-8, overflow=1e30; */
double accurate=1e-10, overflow=1e60;
double factor, gin=0, rn=0, a=0,b=0,an=0,dif=0, term=0, pn[6];
if (x==0) return (0);
if (x<0 || p<=0) return (-1);
factor=exp(p*log(x)-x-g);
if (x>1 && x>=p) goto l30;
/* (1) series expansion */
gin=1; term=1; rn=p;
l20:
rn++;
term*=x/rn; gin+=term;
if (term > accurate) goto l20;
gin*=factor/p;
goto l50;
l30:
/* (2) continued fraction */
a=1-p; b=a+x+1; term=0;
pn[0]=1; pn[1]=x; pn[2]=x+1; pn[3]=x*b;
gin=pn[2]/pn[3];
l32:
a++; b+=2; term++; an=a*term;
for (i=0; i<2; i++) pn[i+4]=b*pn[i+2]-an*pn[i];
if (pn[5] == 0) goto l35;
rn=pn[4]/pn[5]; dif=fabs(gin-rn);
if (dif>accurate) goto l34;
if (dif<=accurate*rn) goto l42;
l34:
gin=rn;
l35:
for (i=0; i<4; i++) pn[i]=pn[i+2];
if (fabs(pn[4]) < overflow) goto l32;
for (i=0; i<4; i++) pn[i]/=overflow;
goto l32;
l42:
gin=1-factor*gin;
l50:
return (gin);
}
double PointChi2 (double prob, double v)
{
/* returns z so that Prob{x<z}=prob where x is Chi2 distributed with df=v
returns -1 if in error. 0.000002<prob<0.999998
RATNEST FORTRAN by
Best DJ & Roberts DE (1975) The percentage points of the
Chi2 distribution. Applied Statistics 24: 385-388. (AS91)
Converted into C by Ziheng Yang, Oct. 1993.
*/
double e=.5e-6, aa=.6931471805, p=prob, g, small=1e-6;
double xx, c, ch, a=0,q=0,p1=0,p2=0,t=0,x=0,b=0,s1,s2,s3,s4,s5,s6;
if (p<small) return(0);
if (p>1-small) return(9999);
if (v<=0) return (-1);
g = LnGamma (v/2);
xx=v/2; c=xx-1;
if (v >= -1.24*log(p)) goto l1;
ch=pow((p*xx*exp(g+xx*aa)), 1/xx);
if (ch-e<0) return (ch);
goto l4;
l1:
if (v>.32) goto l3;
ch=0.4; a=log(1-p);
l2:
q=ch; p1=1+ch*(4.67+ch); p2=ch*(6.73+ch*(6.66+ch));
t=-0.5+(4.67+2*ch)/p1 - (6.73+ch*(13.32+3*ch))/p2;
ch-=(1-exp(a+g+.5*ch+c*aa)*p2/p1)/t;
if (fabs(q/ch-1)-.01 <= 0) goto l4;
else goto l2;
l3:
x=PointNormal (p);
p1=0.222222/v; ch=v*pow((x*sqrt(p1)+1-p1), 3.0);
if (ch>2.2*v+6) ch=-2*(log(1-p)-c*log(.5*ch)+g);
l4:
q=ch; p1=.5*ch;
if ((t=IncompleteGamma (p1, xx, g))<0)
error2 ("\nIncompleteGamma");
p2=p-t;
t=p2*exp(xx*aa+g+p1-c*log(ch));
b=t/ch; a=0.5*t-b*c;
s1=(210+a*(140+a*(105+a*(84+a*(70+60*a))))) / 420;
s2=(420+a*(735+a*(966+a*(1141+1278*a))))/2520;
s3=(210+a*(462+a*(707+932*a)))/2520;
s4=(252+a*(672+1182*a)+c*(294+a*(889+1740*a)))/5040;
s5=(84+264*a+c*(175+606*a))/2520;
s6=(120+c*(346+127*c))/5040;
ch+=t*(1+0.5*t*s1-b*c*(s1-b*(s2-b*(s3-b*(s4-b*(s5-b*s6))))));
if (fabs(q/ch-1) > e) goto l4;
return (ch);
}
int DiscreteGamma (double freqK[], double rK[],
double alpha, double beta, int K, int median)
{
/* discretization of gamma distribution with equal proportions in each
category
*/
int i;
double t, factor=alpha/beta*K, lnga1;
if (median) {
FOR(i,K) rK[i]=PointGamma((i*2.+1)/(2.*K), alpha, beta);
for(i=0,t=0; i<K; i++) t+=rK[i];
FOR(i,K) rK[i]*=factor/t;
}
else {
lnga1=LnGamma(alpha+1);
for (i=0; i<K-1; i++)
freqK[i]=PointGamma((i+1.0)/K, alpha, beta);
for (i=0; i<K-1; i++)
freqK[i]=IncompleteGamma(freqK[i]*beta, alpha+1, lnga1);
rK[0] = freqK[0]*factor;
rK[K-1] = (1-freqK[K-2])*factor;
for (i=1; i<K-1; i++) rK[i] = (freqK[i]-freqK[i-1])*factor;
}
for (i=0; i<K; i++) freqK[i]=1.0/K;
return (0);
}
int AutodGamma (double M[], double freqK[], double rK[], double *rho1,
double alpha, double rho, int K)
{
/* Auto-discrete-gamma distribution of rates over sites, K equal-probable
categories, with the mean for each category used.
This routine calculates M[], freqK[] and rK[], using alpha, rho and K.
*/
int i,j, i1, i2;
double *point=freqK;
double x, y, large=20, v1;
/*
if (fabs(rho)>1-1e-4) error2("rho out of range");
*/
FOR (i,K-1) point[i]=PointNormal((i+1.0)/K);
for (i=0; i<K; i++) {
for (j=0; j<K; j++) {
x = (i<K-1?point[i]:large);
y = (j<K-1?point[j]:large);
M[i*K+j] = CDFBinormal(x,y,rho);
}
}
for (i1=0; i1<2*K-1; i1++) {
for (i2=0; i2<K*K; i2++) {
i=i2/K; j=i2%K;
if (i+j != 2*(K-1)-i1) continue;
y=0;
if (i>0) y-= M[(i-1)*K+j];
if (j>0) y-= M[i*K+(j-1)];
if (i>0 && j>0) y += M[(i-1)*K+(j-1)];
M[i*K+j] = (M[i*K+j]+y)*K;
if (M[i*K+j]<0) printf("M(%d,%d) =%12.8f<0\n", i+1, j+1, M[i*K+j]);
}
}
DiscreteGamma (freqK, rK, alpha, alpha, K, 0);
for (i=0,v1=*rho1=0; i<K; i++) {
v1+=rK[i]*rK[i]*freqK[i];
for (j=0; j<K; j++)
*rho1 += freqK[i]*M[i*K+j]*rK[i]*rK[j];
}
v1-=1;
*rho1=(*rho1-1)/v1;
return (0);
}
double CDFBinormal (double h1, double h2, double r)
{
/* F(h1,h2,r) = prob(x<h1, y<h2), where x and y are standard binormal,
*/
return (LBinormal(h1,h2,r)+CDFNormal(h1)+CDFNormal(h2)-1);
}
double LBinormal (double h1, double h2, double r)
{
/* L(h1,h2,r) = prob(x>h1, y>h2), where x and y are standard binormal,
with r=corr(x,y), error < 2e-7.
Drezner Z., and G.O. Wesolowsky (1990) On the computation of the
bivariate normal integral. J. Statist. Comput. Simul. 35:101-107.
*/
int i;
double x[]={0.04691008, 0.23076534, 0.5, 0.76923466, 0.95308992};
double w[]={0.018854042, 0.038088059, 0.0452707394,0.038088059,0.018854042};
double Lh=0, r1, r2, r3, rr, aa, ab, h3, h5, h6, h7, h12;
h12=(h1*h1+h2*h2)/2;
if (fabs(r)>=0.7) {
r2=1-r*r; r3=sqrt(r2);
if (r<0) h2*=-1;
h3=h1*h2; h7=exp(-h3/2);
if (fabs(r)!=1) {
h6=fabs(h1-h2); h5=h6*h6/2; h6/=r3; aa=.5-h3/8; ab=3-2*aa*h5;
Lh = .13298076*h6*ab*(1-CDFNormal(h6))
- exp(-h5/r2)*(ab+aa*r2)*0.053051647;
for (i=0; i<5; i++) {
r1=r3*x[i]; rr=r1*r1; r2=sqrt(1-rr);
Lh-=w[i]*exp(-h5/rr)*(exp(-h3/(1+r2))/r2/h7-1-aa*rr);
}
}
if (r>0) Lh = Lh*r3*h7+(1-CDFNormal(max2(h1,h2)));
else if (r<0) Lh = (h1<h2?CDFNormal(h2)-CDFNormal(h1):0) - Lh*r3*h7;
}
else {
h3=h1*h2;
if (r!=0)
for (i=0; i<5; i++) {
r1=r*x[i]; r2=1-r1*r1;
Lh+=w[i]*exp((r1*h3-h12)/r2)/sqrt(r2);
}
Lh=(1-CDFNormal(h1))*(1-CDFNormal(h2))+r*Lh;
}
return (Lh);
}
double probBinomial (int n, int k, double p)
{
/* calculates {n\choose k} * p^k * (1-p)^(n-k)
*/
double C, up, down;
if (n<40 || (n<1000&&k<10)) {
for (down=min2(k,n-k),up=n,C=1; down>0; down--,up--) C*=up/down;
if (fabs(p-.5)<1e-6) C *= pow(p,(double)n);
else C *= pow(p,(double)k)*pow((1-p),(double)(n-k));
}
else {
C = exp((LnGamma(n+1.)-LnGamma(k+1.)-LnGamma(n-k+1.))/n);
C = pow(p*C,(double)k) * pow((1-p)*C,(double)(n-k));
}
return C;
}
double CDFBeta(double x, double pin, double qin, double lnbeta)
{
/* Returns distribution function of the beta distribution, that is,
the incomplete beta ratio I_x(p,q) ).
This is called from InverseCDFBeta() in a root-finding loop.
This routine is a translation into C of a Fortran subroutine
by W. Fullerton of Los Alamos Scientific Laboratory.
Bosten and Battiste (1974).
Remark on Algorithm 179, CACM 17, p153, (1974).
*/
double ans, c, finsum, p, ps, p1, q, term, xb, xi, y;
int n, i, ib;
static double eps = 0, alneps = 0, sml = 0, alnsml = 0;
if(x<0 || x>1 || pin<0 || qin<0) error2("out of range in CDFBeta");
if (eps == 0) {/* initialize machine constants ONCE */
eps = pow((double)FLT_RADIX, -(double)DBL_MANT_DIG);
alneps = log(eps);
sml = DBL_MIN;
alnsml = log(sml);
}
y = x; p = pin; q = qin;
/* swap tails if x is greater than the mean */
if (p / (p + q) < x) {
y = 1 - y;
p = qin;
q = pin;
}
if(lnbeta==0) lnbeta=LnGamma(p)+LnGamma(q)-LnGamma(p+q);
if ((p + q) * y / (p + 1) < eps) { /* tail approximation */
ans = 0;
xb = p * log(max2(y, sml)) - log(p) - lnbeta;
if (xb > alnsml && y != 0)
ans = exp(xb);
if (y != x || p != pin)
ans = 1 - ans;
}
else {
/* evaluate the infinite sum first. term will equal */
/* y^p / beta(ps, p) * (1 - ps)-sub-i * y^i / fac(i) */
ps = q - floor(q);
if (ps == 0)
ps = 1;
xb=LnGamma(ps)+LnGamma(p)-LnGamma(ps+p);
xb = p * log(y) - xb - log(p);
ans = 0;
if (xb >= alnsml) {
ans = exp(xb);
term = ans * p;
if (ps != 1) {
n = (int)max2(alneps/log(y), 4.0);
for(i=1 ; i<= n ; i++) {
xi = i;
term = term * (xi - ps) * y / xi;
ans = ans + term / (p + xi);
}
}
}
/* evaluate the finite sum. */
if (q > 1) {
xb = p * log(y) + q * log(1 - y) - lnbeta - log(q);
ib = (int) (xb/alnsml); if(ib<0) ib=0;
term = exp(xb - ib * alnsml);
c = 1 / (1 - y);
p1 = q * c / (p + q - 1);
finsum = 0;
n = (int) q;
if (q == (double)n)
n = n - 1;
for(i=1 ; i<=n ; i++) {
if (p1 <= 1 && term / eps <= finsum)
break;
xi = i;
term = (q - xi + 1) * c * term / (p + q - xi);
if (term > 1) {
ib = ib - 1;
term = term * sml;
}
if (ib == 0)
finsum = finsum + term;
}
ans = ans + finsum;
}
if (y != x || p != pin)
ans = 1 - ans;
if(ans>1) ans=1;
if(ans<0) ans=0;
}
return ans;
}
static volatile double xtrunc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -