home *** CD-ROM | disk | FTP | other *** search
- # Various 'special' functions of mathematics and statistics
- # Most are based on details and algorithms given in
- # "Numerical Recipes - Art Of Scientific Computing" by Press, et al.
- #
- # gamma, beta, factorial functions
- # incomplete gamma functions
- # error function and it's complement
- # standard and generalised univariate normal distribution
- #
- # nb: routines assume array base is 1
- # mws, February, 1992.
-
- echo "Defining gamma, factorial and related functions"
- silent
-
- ROOT2PI = sqrt(2*PI)
- array gammcoef[6] = {
- 76.18009173, -86.50532033,
- 24.01409822, -1.231739516,
- 0.120858003e-2, -0.536382e-5
- }
-
- # ln(gamma(z))
- func gammaln(z) = {
- local tmp, ser, j
- z -= 1
- tmp = z+5.5; tmp = (z+0.5)*ln(tmp)-tmp
- ser = 1
- for (j = 1; j < 7; j += 1) {
- z += 1
- ser += gammcoef[j]/z
- }
- tmp+ln(ROOT2PI*ser)
- }
-
- func gamma(z) = exp(gammaln(z))
-
- array facttab[33] = {1} #table for speed
- facttop = 0 #filled as required
- func fact(n) = {
- local j
- if (n < 0) error(1)
- if (n <= facttop) {
- facttab[n+1] # implicit return (last expr evaluated)
- } else if (n <= 32) {
- for (j = facttop+1; j <= n; j += 1)
- facttab[j+1] = j*facttab[j]
- facttop = n
- facttab[n+1] # implicit return
- } else gamma(n+1)
- }
-
- func beta(z,w) = exp(gammaln(z) + gammaln(w) - gammaln(z+w))
-
-
- GITMAX = 100 # max iterations to calculate gamma functions
- GEPS = 3e-7 #
-
- func gamser(a,x) = { # evaluate P(a,x) by series
- local gln,ap,sum,del,n
-
- gln = gammaln(a)
- if (x == 0) return 0 else {
- ap = a
- sum = 1/a
- del = sum
- for (n = 1; n <= GITMAX; n += 1) {
- ap += 1
- del *= x/ap
- sum += del
- if (abs(del) < abs(sum)*GEPS)
- return sum*exp(-x+a*ln(x)-gln)
- }
- error(2) # can't reach desired accuracy
- }
- }
-
- func gamcf(a,x) = { # evaluate Q(a,x) by continued fraction
- local gln,gold,a0,a1,b0,b1,factor,n,na,nf,g
-
- gln = gammaln(a)
- gold = 0
- a0 = 1; a1 = x; b0 = 0; b1 = 1
- factor = 1
- for (n = 1; n <= GITMAX; n += 1) {
- na = n-a
- a0 = (a1+a0*na)*factor
- b0 = (b1+b0*na)*factor
- nf = n*factor
- a1 = x*a0+nf*a1
- b1 = x*b0+nf*b1
- if (a1 != 0) {
- factor = 1/a1
- g = b1*factor
- if ((abs(g-gold)/g) < GEPS)
- return exp(-x+a*ln(x)-gln)*g
- gold = g
- }
- }
- error(3) # can't reach desired accuracy
- }
-
- # incomplete gamma function P(a,x) (by standard symbology)
- func gammap(a,x) = {
- if (x < 0 || a <= 0) error(4) # invalid parameters
- if (x < a+1) gamser(a,x) else 1-gamcf(a,x)
- }
-
- # and the other, Q(a,x) = 1 - P(a,x)
- func gammaq(a,x) = 1-gammap(a,x)
-
- # and the error function erf(x) and its complement erfc(x)
- func erf(x) = x < 0 ? -gammap(0.5,sqr(x)) : gammap(0.5,sqr(x))
- func erfc(x) = x < 0 ? 1+gammap(0.5,sqr(x)) : gammaq(0.5,sqr(x))
-
- # BUT a (much) quicker calculation of erfc (and hence erf), with fractional
- # error less than 1.2e-7 is:
- func Erfc(x) = {
- local z,t,rv
- z = abs(x)
- t = 1/(1+0.5*z)
- rv = t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+ \
- t*(0.09678418+t*(-0.18628806+t*(0.27886807+t*(-1.13520398+ \
- t*(1.48851587+t*(-0.82215223+t*0.17087277)))))))))
-
- x >= 0 ? rv : 2-rv
- }
-
- func Erf(x) = 1-Erfc(x)
-
- # cumulative normal distribution functions
- ROOT2 = sqrt(2)
-
- # standard normal - mean 0, variance 1
- func snorm(x) = 1 - 0.5*Erfc(x/ROOT2)
-
- # generalised normal - mean mu, variance sigma
- func gnorm(x,mu,sigma) = 1 - 0.5*Erfc((x-mu)/(sigma*ROOT2))
-
- verbose # turn messages back on
- echo "Done."
-