SpezFunkt2.mod.m2pp
2122 lines (1889 with data), 75.4 kB
IMPLEMENTATION MODULE SpezFunkt2;
(*========================================================================*)
(* HINWEIS : Bitte nur die Datei SpezFunkt2.mod.m2pp editieren *)
(*========================================================================*)
(* Es sind 2 Versionen enthalten die mit *)
(* *)
(* m2pp -D __{Parameter}__ < SpezFunkt2.mod.m2pp > SpezFunkt2.mod *)
(* *)
(* mit Parameter = {XDS|GM2} erzeugt werden koennen. *)
(* *)
(* XDS : Der Export von Objekten aus lokalen Modulen wird mit *)
(* "IMPORT" angezeigt - das scheint nicht ganz "regelkonform" *)
(* GM2 : Normales "EXPORT" wird genutzt (ELSE-Fall). *)
(* *)
(* ansonsten gibt es keine Aenderungen am Quellcode *)
(*------------------------------------------------------------------------*)
(* Modul fuer einige Formen der Gammafunktion *)
(* Module for the calculation of several forms of the Gamma function *)
(*------------------------------------------------------------------------*)
(* IGamma,JGamm and IBeta are based on work found in dtmath086 Pascal *)
(* library with is in parts based on Cephes library (www.moshier.net) *)
(* Code for aLnGamma,GammaIn and dGamit is a partial translation of *)
(* W. Fullertons Fortran code used in SLATEC. *)
(* CLnGamma is a translation of CERN Library function GLGAMA *)
(*------------------------------------------------------------------------*)
(* Letzte Bearbeitung: *)
(* *)
(* 06.10.15, MRi: ErrorF und CompErrorF eingefuegt (erste Version) *)
(* 07.10.15, MRi: Verschieben von LnGamma,GammaU und Errf aus dem Modul *)
(* LMathLib *)
(* 08.10.15, MRi: dLnGamma & dGamma eingefuegt *)
(* 27.05.16, MRi: Erstellen der ersten Verison von GamSmall aud Basis von *)
(* Konstanten aus dtmath086 Bibliothek (Pascal). *)
(* 29.05.16, MRi: Hilfsprozedure D1Mach in Module F77func verschoben *)
(* GamSmall in dGamma eingebaut. *)
(* 4 Compilerwarnungen eleminiert durch 1. Ersetzen von *)
(* s1 in ErrorF durch B[17] resp. A[18] in Zeilen die mit *)
(* s = BJP2 bzw s = BJ gekennzeichent sind und 2. durch *)
(* Umwandlung der LOOP durch REPEAT-Schleifen in D9GamL *)
(* 27.08.16, MRi: Argument von dGamma ist nicht mehr "VAR" *)
(* 27.08.16, MRi: Erstellen der ersten Verionsn von IGamma,JGamma,IBeta *)
(* 16.02.17, MRi: Erstellen der ersten Version (aLnGamma,GamamaIn,dGamit) *)
(* 14.02.18, MRi: Hinzufuegen von CLnGamma und CGamma *)
(* 14.02.18, MRi: Erstellen der ersten Version von CdGamma *)
(* 23.05.18, MRi: Erweiterung von CdGamma und Aufnahme in SpezFunkt2 *)
(* 19.12.18, MRi: Ersetzen von GammaIn durch Neuuebersetzng von AS239 *)
(* da die alte Routine (basierend auf AS32) fuer grosse X *)
(* teilweise falsche Ergebnisse erzielt hatte. *)
(* 19.12.18, MRi: Erstellen der ersten Version von AlNorm *)
(*------------------------------------------------------------------------*)
(* Testroutinen vorhanden, IBeta gegen unabhaengigen Fortran-Code ge- *)
(* testet, IGamma & JGamma nur gegen Pascal-Aequivalent *)
(* Testcode (parially against Fortran versions) in TstSpzFun2 *)
(* dGamit wird in BoysInt2Lib intensiv genutzt *)
(*------------------------------------------------------------------------*)
(* Offene Punkte *)
(* *)
(* - Modulstruktur durchsehen und eventuell bereinigen. *)
(* - besserer Test fuer CLnGamma, CGamma *)
(*------------------------------------------------------------------------*)
(* Implementation : Michael Riedl *)
(* Licence : GNU Lesser General Public License (LGPL) *)
(*------------------------------------------------------------------------*)
(* $Id: SpezFunkt2.mod.m2pp,v 1.6 2019/02/01 22:24:03 mriedl Exp mriedl $ *)
FROM Errors IMPORT FatalError,ErrOut,Fehler,Fehlerflag;
IMPORT LowLong;
FROM TestReal IMPORT Real8NaNquite,IsNearInteger;
IMPORT TestReal;
FROM LongMath IMPORT pi,sqrt,power,ln,exp,sin,cos,round;
FROM LMathLib IMPORT INF,NAN,MachEps,MinLog,MaxLog,sqrtpi,
sinh,cosh,tanh,arctan2;
IMPORT LongComplexMath;
FROM LongComplexMath IMPORT zero,one,conj,scalarMult;
FROM F77func IMPORT D1Mach,DMIN;
VAR fast : BOOLEAN;
Sqrt2Pi : LONGREAL; (* sqrt(2 pi) *)
bot : LONGREAL; (* wird in d9Gamit genutzt *)
PROCEDURE sqr(x : LONGREAL) : LONGREAL; BEGIN RETURN x*x; END sqr;
PROCEDURE DSIGN(a,b : LONGREAL) : LONGREAL;
BEGIN
IF (b >= 0.0) THEN
RETURN ABS(a);
ELSE
RETURN - ABS(a);
END;
END DSIGN;
PROCEDURE AlNorm(X : LONGREAL;
Upper : BOOLEAN) : LONGREAL;
(*----------------------------------------------------------------*)
(* Algorithm AS66 Applied Statistics (1973) vol22 no.3 *)
(* *)
(* Evaluates the tail area of the standardised normal curve *)
(* from x to infinity if upper is .true. or *)
(* from minus infinity to x if upper is .false. *)
(*----------------------------------------------------------------*)
(* machine dependent constants *)
CONST ltone = 7.0; utzero = 18.66; con = 1.28;
p = 0.398942280444; q = 0.399903485040;
r = 0.398942280385;
a1 = 5.758854804580; a2 = 2.624331216790;
a3 = 5.928857244380;
b1 = -29.821355780700; b2 = 48.695993069200;
c1 = -3.80520000E-08; c2 = 3.98064794E-04;
c3 = -0.151679116635; c4 = 4.838591280800;
c5 = 0.742380924027; c6 = 3.990194170110;
d1 = 1.000006153020; d2 = 1.986153813640;
d3 = 5.293303249260; d4 = -15.150897245100;
d5 = 30.789933034000;
VAR z,y,alnorm : LONGREAL;
up : BOOLEAN;
BEGIN
up := Upper;
z := X;
IF (z < 0.0) THEN
up := NOT up;
z := -z;
END; (* IF *)
IF (((z <= ltone) OR up) AND (z <= utzero)) THEN
y := 0.5*z*z;
IF (z > con) THEN
alnorm := r*exp(-y) / (z + c1 + d1 / (z + c2 + d2 /
(z + c3 + d3 / (z + c4 + d4 /
(z + c5 + d5 / (z + c6))))));
ELSE
alnorm := 0.5 - z*(p-q*y / (y + a1 + b1 /
(y + a2 + b2 / (y + a3))));
END;
ELSE
alnorm := 0.0;
END; (* IF *)
IF (NOT up) THEN
alnorm := 1.0 - alnorm;
END;
RETURN alnorm;
END AlNorm;
PROCEDURE GammaIn( X : LONGREAL;
P : LONGREAL;
VAR Ifault : INTEGER) : LONGREAL;
(*----------------------------------------------------------------*)
(* This is a M2 verions of AS239. Auxiliary functions required *)
(* are the logarithm of the gamma function and AlNorm (AS66). *)
(*----------------------------------------------------------------*)
CONST Tol = 1.0E-14;
Xbig = 1.0E+08; Oflow = LFLOAT(MAX(REAL));
Elimit = -88.0; Plimit = 1000.0;
VAR pn1,pn2,pn3,pn4,pn5,pn6 : LONGREAL;
a,b,c,an,rn,arg,gamma : LONGREAL;
BEGIN
(* Check that we have valid values for X and P *)
IF ((P <= 0.0) OR (X < 0.0)) THEN
Ifault := 1;
RETURN 0.0;
END; (* IF *)
Ifault := 0;
IF (X = 0.0) THEN
RETURN 0.0;
END; (* IF *)
(* Use a normal approximation if P > Plimit *)
IF (P > Plimit) THEN
pn1 := 3.0*sqrt(P)*(power((X/P),(1.0/3.0)) + 1.0/(9.0*P) - 1.0);
RETURN AlNorm(pn1,FALSE);
END; (* IF *)
(* If X is extremely large compared to P then set gamma = 1 *)
IF (X > Xbig) THEN
RETURN 1.0;
END; (* IF *)
IF (X <= 1.0) OR (X < P) THEN
(* Use Pearson's series expansion. *)
(* Note that P is not large enough to force overflow in ALOGAM. *)
(* No need to test IFAULT on exit since P > 0. *)
arg := P*ln(X) - X - aLnGamma(P+1.0,Ifault);
c := 1.0;
gamma := 1.0;
a := P;
LOOP
a := a + 1.0;
c := c*X/a;
gamma := gamma + c;
IF (c <= Tol) THEN
arg := arg + ln(gamma);
gamma := 0.0;
IF (arg >= Elimit) THEN
gamma := exp(arg);
END; (* IF *)
EXIT;
END; (* IF *)
END; (* LOOP *)
ELSE
(* Use a continued fraction expansion *)
arg := P*ln(X) - X - aLnGamma(P,Ifault);
a := 1.0 - P;
b := a + X + 1.0;
c := 0.0;
pn1 := 1.0;
pn2 := X;
pn3 := X + 1.0;
pn4 := X*b;
gamma := pn3/pn4;
LOOP
a := a + 1.0;
b := b + 2.0;
c := c + 1.0;
an := a*c;
pn5 := b*pn3 - an*pn1;
pn6 := b*pn4 - an*pn2;
IF (ABS(pn6) > 0.0) THEN
rn := pn5/pn6;
IF (ABS(gamma-rn) <= DMIN(Tol,Tol*rn)) THEN
arg := arg + ln(gamma);
gamma := 1.0;
IF (arg >= Elimit) THEN
gamma := 1.0 - exp(arg);
END; (* IF *)
EXIT
ELSE
gamma := rn;
END; (* IF *)
END; (* IF *)
pn1 := pn3;
pn2 := pn4;
pn3 := pn5;
pn4 := pn6;
IF (ABS(pn5) >= Oflow) THEN
(* Re-scale terms in continued fraction if terms are large *)
pn1 := pn1 / Oflow;
pn2 := pn2 / Oflow;
pn3 := pn3 / Oflow;
pn4 := pn4 / Oflow;
END; (* IF *)
END; (* LOOP *)
END; (* IF *)
RETURN gamma;
END GammaIn;
PROCEDURE GammaU(a,x : LONGREAL) : LONGREAL;
(*----------------------------------------------------------------*)
(* Ben"otigt die PROCEDURE LnGamma *)
(*----------------------------------------------------------------*)
CONST MaxIter = 100;
eps = 2.5E-16;
VAR Iter : CARDINAL;
Sum,Delta,Fakt,I,Wert : LONGREAL;
g0,g1,b0,b1,a0,a1,ana,anf,ap : LONGREAL;
BEGIN
IF (x < 0.0) OR (a <= 0.0) THEN
FatalError('Argument (x < 0) bzw (a <= 0) (Funkt.GammaU) !)');
END;
IF (x = 0.0) THEN RETURN 0.0; END; (* !!! *)
Iter:=0;
IF (x < (a + 1.0)) THEN (* Reihenentwicklung *)
ap := a; Sum:=1.0 / a; Delta:=Sum;
REPEAT
INC(Iter);
ap := ap + 1.0; Delta:=Delta*x / ap; Sum:=Sum + Delta;
UNTIL (ABS(Delta) < eps*ABS(Sum)) OR (Iter > MaxIter);
Wert := Sum*exp(-x + a*ln(x) - LnGamma(a));
ELSE (* *)
g0:=0.0; a0:=1.0; a1:=x; b0:=0.0; b1:=1.0; Fakt:=1.0;
LOOP
INC(Iter); I:=LFLOAT(Iter);
ana := I - a;
a0 := (a1 + a0*ana)*Fakt;
b0 := (b1 + b0*ana)*Fakt;
anf:=I*Fakt;
a1:=x*a0 + anf*a1;
b1:=x*b0 + anf*b1;
IF (a1 # 0.0) THEN
Fakt := 1.0 / a1;
g1 := b1*Fakt;
IF (ABS((g1- g0) / g1) < eps) OR (Iter > MaxIter) THEN EXIT END;
g0 := g1;
END;
END; (* LOOP *)
Wert := 1.0 - g1*exp(-x + a*ln(x) - LnGamma(a));
END; (* IF x *)
IF (Iter > MaxIter) THEN
Fehler:=TRUE; Fehlerflag:='MaxIter "uberschritten (Funkt.GammaU) !';
ErrOut(Fehlerflag);
END;
RETURN Wert;
END GammaU;
PROCEDURE IGamma(A,X : LONGREAL) : LONGREAL;
CONST MinLn = 1.0 / MAX(LONGREAL);
VAR Ans,Ax,C,R : LONGREAL;
BEGIN
IF (X <= MinLn) OR (A <= 0.0) THEN
RETURN 0.0;
END;
IF (X > 1.0) AND (X > A) THEN
RETURN 1.0 - JGamma(A,X);
END;
(* Ax := A*ln(X) - X - LnGamma(A); *)
Ax := A*ln(X) - X - dLnGamma(A);
IF (Ax < MinLog) THEN
RETURN 0.0;
END;
Ax := exp(Ax);
R := A; C := 1.0; Ans := 1.0;
REPEAT (* Power series *)
R := R + 1.0;
C := C * X / R;
Ans := Ans + C;
UNTIL C / Ans <= MachEps;
RETURN Ans*Ax / A;
END IGamma;
PROCEDURE JGamma(A,X : LONGREAL) : LONGREAL;
CONST Big = 1.0 / MachEps;
VAR Ans,C,Yc,Ax,Y,Z,R,T : LONGREAL;
Pk,Pkm1,Pkm2,Qk,Qkm1,Qkm2 : LONGREAL;
BEGIN
IF (X <= 0.0) OR (A <= 0.0) THEN
RETURN 1.0;
END;
IF (X < 1.0) OR (X < A) THEN
RETURN 1.0 - IGamma(A,X);
END;
Ax := A*ln(X) - X - dLnGamma(A);
IF (Ax < MinLog) THEN
RETURN 0.0;
END;
Ax := exp(Ax);
(* Continued fraction *)
Y := 1.0 - A;
Z := X + Y + 1.0;
C := 0.0;
Pkm2 := 1.0;
Qkm2 := X;
Pkm1 := X + 1.0;
Qkm1 := Z * X;
Ans := Pkm1 / Qkm1;
REPEAT
C := C + 1.0;
Y := Y + 1.0;
Z := Z + 2.0;
Yc := Y * C;
Pk := Pkm1*Z - Pkm2*Yc;
Qk := Qkm1*Z - Qkm2*Yc;
IF (Qk # 0.0) THEN
R := Pk / Qk;
T := ABS((Ans - R) / R);
Ans := R;
ELSE
T := 1.0;
END;
Pkm2 := Pkm1;
Pkm1 := Pk;
Qkm2 := Qkm1;
Qkm1 := Qk;
IF (ABS(Pk) > Big) THEN
Pkm2:=Pkm2 * MachEps;
Pkm1:=Pkm1 * MachEps;
Qkm2:=Qkm2 * MachEps;
Qkm1:=Qkm1 * MachEps;
END;
UNTIL (T <= MachEps);
RETURN Ans*Ax;
END JGamma;
PROCEDURE aLnGamma( X : LONGREAL;
VAR iFehl : INTEGER): LONGREAL; (* SLATEC *)
CONST Hln2pi = 0.918938533204673; (* 0.5*ln(2.0*pi) *)
Xlow = 5.10E+05;
Xlarge = 1.0E+30;
TYPE Vec9 = ARRAY [1..9] OF LONGREAL;
Vec5 = ARRAY [1..5] OF LONGREAL;
CONST r1 = Vec9{
-2.66685511495E+00, -2.44387534237E+01,
-2.19698958928E+01, 1.11667541262E+01,
3.13060547623E+00, 6.07771387771E-01,
1.19400905721E+01, 3.14690115749E+01,
1.52346874070E+01
};
r2 = Vec9{
-7.83359299449E+01, -1.42046296688E+02,
1.37519416416E+02, 7.86994924154E+01,
4.16438922228E+00, 4.70668766060E+01,
3.13399215894E+02, 2.63505074721E+02,
4.33400022514E+01
};
r3 = Vec9{
-2.12159572323E+05, 2.30661510616E+05,
2.74647644705E+04, -4.02621119975E+04,
-2.29660729780E+03, -1.16328495004E+05,
-1.46025937511E+05, -2.42357409629E+04,
-5.70691009324E+02
};
r4 = Vec5{
0.2791953179185250, 0.4917317610505968,
0.0692910599291889, 3.3503438150223040,
6.0124592597641030
};
VAR x1,x2,y,LnG : LONGREAL;
BEGIN
IF (X <= 0.0) THEN (* check the input. *)
iFehl:=1;
RETURN 0.0;
ELSIF (X >= Xlarge) THEN
iFehl:=2;
RETURN 0.0;
END;
iFehl:=0;
(* calculation for 0 < x < 0.5 and 0.5 <= x < 1.5 combined. *)
IF (X < 1.5) THEN
IF (X < 0.5) THEN
LnG := - ln(X);;
y := X + 1.0;
(* test whether x < machine epsilon. *)
IF (y = 1.0) THEN
RETURN LnG;
END;
ELSE
LnG := 0.0;
y := X;
X := (X-0.5) - 0.5;
END;
LnG:=LnG +
X*((((r1[5]*y + r1[4])*y + r1[3])*y + r1[2])*y + r1[1]) /
((((y + r1[9])*y + r1[8])*y + r1[7])*y + r1[6]);
RETURN LnG;
END;
IF (X < 4.0) THEN
(* calculation for 1.5 <= x < 4.0. *)
y := X - 2.0;
LnG := y*((((r2[5]*X + r2[4])*X + r2[3])*X + r2[2])*X + r2[1]) /
((((X + r2[9])*X + r2[8])*X + r2[7])*X + r2[6]);
ELSIF (X < 12.0) THEN
(* calculation for 4.0 <= x < 12.0. *)
LnG := ((((r3[5]*X + r3[4])*X + r3[3])*X + r3[2])*X + r3[1]) /
(((( X + r3[9])*X + r3[8])*X + r3[7])*X + r3[6]);
ELSE
(* calculation for 12.0 <= x. *)
y := ln(X);
LnG := X*(y-1.0) - 0.5*y + Hln2pi;
IF (X <= Xlow) THEN
x1 := 1.0 / X;
x2 := x1*x1;
LnG := LnG + x1*((r4[3]*x2 + r4[2])*x2 + r4[1]) /
((x2 + r4[5])*x2 + r4[4]);
END;
END;
RETURN LnG;
END aLnGamma;
MODULE GAMMA; (* Stellt LnGamma zur Verfuegung *)
IMPORT pi,sqrt,ln,sin,Sqrt2Pi;
<* IF (__XDS__) THEN *>
IMPORT LnGamma; (* EXPORT *)
<* ELSE *>
EXPORT LnGamma;
<* END *>
VAR GamKoeff : ARRAY [0..15] OF LONGREAL;
PROCEDURE LnGamma(z : LONGREAL) : LONGREAL;
(*----------------------------------------------------------------*)
(* Lit.: Luke,Y.L.; "Special Functions and their Approximations", *)
(* Academic Press, New York, USA 1969. *)
(*----------------------------------------------------------------*)
VAR k : CARDINAL;
x,tmp,Sum,Z,N,Hk : LONGREAL;
BEGIN
IF (z = 1.0) THEN RETURN 0.0; END;
IF (z <= 1.0) THEN
x:=1.0 - z; tmp:=pi*x;
RETURN ln(tmp / (sin(tmp))) - LnGamma(x + 1.0); (* !!! *)
END;
x := z - 1.0;
tmp:=x + 5.5; tmp:= (x + 0.5)*ln(tmp) - tmp;
Sum:=0.0; Hk:=1.0; Z:=x; N:=z;
FOR k:=0 TO 15 DO
Sum:=Sum + GamKoeff[k] * Hk;
Hk := (Z / N) * Hk;
Z:=Z - 1.0; N:=N + 1.0;
END;
RETURN tmp + ln(Sqrt2Pi*Sum);
END LnGamma;
BEGIN
GamKoeff[ 0] := 41.624436916439068; GamKoeff[ 1] := -51.224241022374774;
GamKoeff[ 2] := 11.338755813488977; GamKoeff[ 3] := -0.747732687772388;
GamKoeff[ 4] := 0.008782877493061; GamKoeff[ 5] := -0.000001899030264;
GamKoeff[ 6] := 0.000000001946335; GamKoeff[ 7] := -0.000000000199345;
GamKoeff[ 8] := 0.000000000008433; GamKoeff[ 9] := 0.000000000001486;
GamKoeff[10] := -0.000000000000806; GamKoeff[11] := 0.000000000000293;
GamKoeff[12] := -0.000000000000102; GamKoeff[13] := 0.000000000000037;
GamKoeff[14] := -0.000000000000014; GamKoeff[15] := 0.000000000000006;
END GAMMA;
MODULE LibdLnGamma; (* Stellt dLnGamma zur Verfuegung *)
IMPORT TestReal; (* Modul *)
IMPORT ln,sqrt;
IMPORT MachEps;
<* IF (__XDS__) THEN *>
IMPORT dLnGamma; (* EXPORT *)
<* ELSE *>
EXPORT dLnGamma;
<* END *>
(*-----------------------------------------------------------------------*)
(* See also lot of hints given at http://dlmf.nist.gov/5 *)
(*-----------------------------------------------------------------------*)
CONST pnt68 = 0.6796875;
sqrtpi = 0.9189385332046727417803297; (* not sqrt(pi) !!! *)
(* Machine dependent parameters *)
xinf = MAX(LONGREAL);
xbig = 2.0*VAL(LONGREAL,MAX(REAL)); (* ??? *)
VAR frtbig : LONGREAL;
TYPE KoeffVek8 = ARRAY[1..8] OF LONGREAL;
KoeffVek7 = ARRAY[1..7] OF LONGREAL;
(*-------------------------------------------------------------*)
(* Numerator and denominator coefficients for rational minimax *)
(* approximation over (0.5,1.5). *)
(*-------------------------------------------------------------*)
CONST d1 = -5.772156649015328605195174E-01;
P1 = KoeffVek8{
4.945235359296727046734888E+00, 2.018112620856775083915565E+02,
2.290838373831346393026739E+03, 1.131967205903380828685045E+04,
2.855724635671635335736389E+04, 3.848496228443793359990269E+04,
2.637748787624195437963534E+04, 7.225813979700288197698961E+03
};
Q1 = KoeffVek8{
6.748212550303777196073036E+01, 1.113332393857199323513008E+03,
7.738757056935398733233834E+03, 2.763987074403340708898585E+04,
5.499310206226157329794414E+04, 6.161122180066002127833352E+04,
3.635127591501940507276287E+04, 8.785536302431013170870835E+03
};
(*-------------------------------------------------------------*)
(* Numerator and denominator coefficients for rational minimax *)
(* approximation over (1.5,4.0). *)
(*-------------------------------------------------------------*)
CONST d2 = 4.227843350984671393993777E-01;
P2 = KoeffVek8{
4.974607845568932035012064E+00, 5.424138599891070494101986E+02,
1.550693864978364947665077E+04, 1.847932904445632425417223E+05,
1.088204769468828767498470E+06, 3.338152967987029735917223E+06,
5.106661678927352456275255E+06, 3.074109054850539556250927E+06
};
Q2 = KoeffVek8{
1.830328399370592604055942E+02, 7.765049321445005871323047E+03,
1.331903827966074194402448E+05, 1.136705821321969608938755E+06,
5.267964117437946917577538E+06, 1.346701454311101692290052E+07,
1.782736530353274213975932E+07, 9.533095591844353613395747E+06
};
(*-------------------------------------------------------------*)
(* Numerator and denominator coefficients for rational minimax *)
(* approximation over (4.0,12.0). *)
(*-------------------------------------------------------------*)
CONST d4 = 1.791759469228055000094023;
P4 = KoeffVek8{
1.474502166059939948905062E+04, 2.426813369486704502836312E+06,
1.214755574045093227939592E+08, 2.663432449630976949898078E+09,
2.940378956634553899906876E+10, 1.702665737765398868392998E+11,
4.926125793377430887588120E+11, 5.606251856223951465078242E+11
};
Q4 = KoeffVek8{
2.690530175870899333379843E+03, 6.393885654300092398984238E+05,
4.135599930241388052042842E+07, 1.120872109616147941376570E+09,
1.488613728678813811542398E+10, 1.016803586272438228077304E+11,
3.417476345507377132798597E+11, 4.463158187419713286462081E+11
};
(*---------------------------------------------------------*)
(* Coefficients for minimax approximation over (12, INF). *)
(*---------------------------------------------------------*)
CONST C = KoeffVek7 {
-1.910444077728E-03, 8.4171387781295E-04,
-5.952379913043012E-04, 7.93650793500350248E-04,
-2.777777777777681622553E-03, 8.333333333333333331554247E-02,
5.7083835261E-03
};
PROCEDURE dLnGamma (X : LONGREAL) : LONGREAL;
(*----------------------------------------------------------------*)
(* Explanation of machine-dependent constants *)
(* *)
(* beta - radix for the floating-point representation *)
(* maxexp - the smallest positive power of beta that overflows *)
(* XBig - largest argument for which LN(GAMMA(X)) is *)
(* representable in the machine, i.e., the solution *)
(* to the equation ln(GAMMA(XBIG)) = beta**maxexp *)
(* XINF - largest machine representable floating-point *)
(* number; approximately beta**maxexp. *)
(* eps - The smallest positive floating-point number such *)
(* that 1.0 + eps > 1.0 *)
(* FRTBIG - Rough estimate of the fourth root of XBIG *)
(* *)
(* Latest modification: June 16, 1988 *)
(* *)
(* Adapted to Modula-2: Riedl,Michael 03.05.2015 *)
(*----------------------------------------------------------------*)
CONST eps = MachEps;
VAR i : CARDINAL;
res,corr : LONGREAL;
xden,xm1,xm2,xm4,xnum,Xsq : LONGREAL;
BEGIN
IF (X > 0.0) AND (X <= xbig) THEN
IF (X <= eps) THEN
res := -ln(X);
ELSIF (X <= 1.5) THEN (* eps < X <= 1.5 *)
IF (X < pnt68) THEN
corr:= -ln(X);
xm1 := X;
ELSE
corr := 0.0;
xm1 := (X - 0.5) - 0.5; (* Wieso nicht X - 1.0 ??? *)
END;
IF (X <= 0.5) OR (X >= pnt68) THEN
xden := 1.0;
xnum := 0.0;
FOR i:=1 TO 8 DO
xnum:=xnum*xm1 + P1[i];
xden:=xden*xm1 + Q1[i];
(*100:*) END;
res := corr + (xm1*(d1 + xm1*(xnum/xden)));
ELSE
xm2 := (X - 0.5) - 0.5;
xden := 1.0;
xnum := 0.0;
FOR i:=1 TO 8 DO
xnum:=xnum*xm2 + P2[i];
xden:=xden*xm2 + Q2[i];
(*200:*) END;
res := corr+xm2*(d2+xm2*(xnum/xden));
END;
ELSIF (X <= 4.0) THEN (* 1.5 < X <= 4.0 *)
xm2 := X - 2.0;
xden := 1.0;
xnum := 0.0;
FOR i:=1 TO 8 DO
xnum:=xnum*xm2 + P2[i];
xden:=xden*xm2 + Q2[i];
(*300:*) END;
res := xm2*(d2+xm2*(xnum/xden))
ELSIF (X <= 12.0) THEN (* 4 < X <= 12 *)
xm4 := X - 4.0;
xden := -1.0;
xnum := 0.0;
FOR i:=1 TO 8 DO
xnum:=xnum*xm4 + P4[i];
xden:=xden*xm4 + Q4[i];
(*400:*) END;
res := d4+xm4*(xnum/xden)
ELSE (* X >= 12.0 *)
res:=0.0;
IF (X <= frtbig) THEN
res := C[7];
Xsq := X*X;
FOR i:=1 TO 6 DO
res:=res / Xsq + C[i];
END;
END;
res := res / X;
corr := ln(X);
res:=res + sqrtpi - 0.5*corr;
res:=res + X*(corr - 1.0);
END;
ELSIF (X <= 0.0) THEN (* Return for bad arguments *)
res:=TestReal.Real8NaNquite();
ELSE (* this means that X > XBIG and so that log(gamma) overflows *)
res:=TestReal.Real8INF();
END;
RETURN res;
END dLnGamma;
BEGIN
frtbig := sqrt(sqrt(xbig));
END LibdLnGamma;
PROCEDURE GamSmall(X : LONGREAL) : LONGREAL;
(*----------------------------------------------------------------*)
(* Gamma function for small ABS(X) in the Range (0,0.03125] *)
(* *)
(* Ref.: Moshier, Stephen; "Methods and Programs for Mathematical *)
(* Functions", Prentice-Hall, Englewood Cliffs, NY (US) (1989) *)
(*----------------------------------------------------------------*)
VAR P : LONGREAL;
BEGIN
(* IF (X = 0.0) THEN
* (* Singulaer *)
* RETURN MAX(LONGREAL);
* ELSIF (ABS(X) > 0.03125) THEN
* (* Auserhalb des Wertebereichs *)
* RETURN MAX(LONGREAL);
* ELS*)
IF (X > 0.0) THEN (* peak relative error 4.2E-23 *)
P := ((((((((-1.193945051381510095614E-03 *X +
7.220599478036909672331E-03)*X -
9.622023360406271645744E-03)*X -
4.219773360705915470089E-02)*X +
1.665386113720805206758E-01)*X -
4.200263503403344054473E-02)*X -
6.558780715202540684668E-01)*X +
5.772156649015328608253E-01)*X + 1.0);
ELSE
X := - X; (* Peak relative error 5.16E-23 *)
P := (((((((( 1.133374167243894382010E-03 *X +
7.220837261893170325704E-03)*X +
9.621911155035976733706E-03)*X -
4.219773343731191721664E-02)*X -
1.665386113944413519335E-01)*X -
4.200263503402112910504E-02)*X +
6.558780715202536547116E-01)*X +
5.772156649015328608727E-01)*X - 1.0);
END;
RETURN 1.0 / (X * P);
END GamSmall;
MODULE LibdGamma; (* Stellt dGamma zur Verfuegung *)
IMPORT LowLong;
IMPORT TestReal;
IMPORT MachEps;
IMPORT D1Mach;
IMPORT pi,ln,exp,sqrt,sin,power,round;
IMPORT sqr,INF;
IMPORT ErrOut,FatalError;
IMPORT GamSmall;
<* IF (__XDS__) THEN *>
IMPORT dGamma; (* EXPORT *)
<* ELSE *>
EXPORT dGamma;
<* END *>
PROCEDURE DMAX1(x,y:LONGREAL):LONGREAL;
BEGIN
IF (x > y) THEN RETURN x ELSE RETURN y; END;
END DMAX1;
PROCEDURE DMIN(x,y:LONGREAL):LONGREAL;
BEGIN
IF (x > y) THEN RETURN y; ELSE RETURN x; END;
END DMIN;
PROCEDURE DINT(x : LONGREAL) : LONGREAL;
BEGIN
RETURN LowLong.intpart(x);
END DINT;
CONST sq2pil = 0.91893853320467274178032973640562; (* ln(sqrt(2*pi)) *)
TYPE Vektor15 = ARRAY [1..15] OF LONGREAL;
VAR Algmcs : Vektor15;
CONST algmcs = Vektor15{
+0.1666389480451863247205729650822E+00,
-0.1384948176067563840732986059135E-04,
+0.9810825646924729426157171547487E-08,
-0.1809129475572494194263306266719E-10,
+0.6221098041892605227126015543416E-13,
-0.3399615005417721944303330599666E-15,
+0.2683181998482698748957538846666E-17,
-0.2868042435334643284144622399999E-19,
+0.3962837061046434803679306666666E-21,
-0.6831888753985766870111999999999E-23,
+0.1429227355942498147573333333333E-24,
-0.3547598158101070547199999999999E-26,
+0.1025680058010470912000000000000E-27,
-0.3401102254316748799999999999999E-29,
+0.1276642195630062933333333333333E-30
};
TYPE Vektor42 = ARRAY [1..42] OF LONGREAL;
VAR Gamcs : Vektor42;
CONST gamcs = Vektor42{
+0.8571195590989331421920062399942E-02,
+0.4415381324841006757191315771652E-02,
+0.5685043681599363378632664588789E-01,
-0.4219835396418560501012500186624E-02,
+0.1326808181212460220584006796352E-02,
-0.1893024529798880432523947023886E-03,
+0.3606925327441245256578082217225E-04,
-0.6056761904460864218485548290365E-05,
+0.1055829546302283344731823509093E-05,
-0.1811967365542384048291855891166E-06,
+0.3117724964715322277790254593169E-07,
-0.5354219639019687140874081024347E-08,
+0.9193275519859588946887786825940E-09,
-0.1577941280288339761767423273953E-09,
+0.2707980622934954543266540433089E-10,
-0.4646818653825730144081661058933E-11,
+0.7973350192007419656460767175359E-12,
-0.1368078209830916025799499172309E-12,
+0.2347319486563800657233471771688E-13,
-0.4027432614949066932766570534699E-14,
+0.6910051747372100912138336975257E-15,
-0.1185584500221992907052387126192E-15,
+0.2034148542496373955201026051932E-16,
-0.3490054341717405849274012949108E-17,
+0.5987993856485305567135051066026E-18,
-0.1027378057872228074490069778431E-18,
+0.1762702816060529824942759660748E-19,
-0.3024320653735306260958772112042E-20,
+0.5188914660218397839717833550506E-21,
-0.8902770842456576692449251601066E-22,
+0.1527474068493342602274596891306E-22,
-0.2620731256187362900257328332799E-23,
+0.4496464047830538670331046570666E-24,
-0.7714712731336877911703901525333E-25,
+0.1323635453126044036486572714666E-25,
-0.2270999412942928816702313813333E-26,
+0.3896418998003991449320816639999E-27,
-0.6685198115125953327792127999999E-28,
+0.1146998663140024384347613866666E-28,
-0.1967938586345134677295103999999E-29,
+0.3376448816585338090334890666666E-30,
-0.5793070335782135784625493333333E-31
};
VAR ngam : INTEGER; (* Global für dGamma *)
dxrel,xmax,xmin,xsml : LONGREAL;
VAR nalgm : INTEGER; (* Global für D9lnMC *)
xbig,D9lnMCxmax : LONGREAL;
PROCEDURE dGamma(X: LONGREAL): LONGREAL;
PROCEDURE Dcsevl( x : LONGREAL;
VAR A : ARRAY OF LONGREAL;
n : INTEGER) : LONGREAL;
(*-------------------------------------------------------------*)
(* Getestet im Interval (-1,1) fuer beide Koeff.-vektoren *)
(* *)
(* Evaluate the n-term Chebyshev series a at x. *)
(* *)
(* Lit: Broucke,R; Algorithm 446, c.a.c.m., 16, 254 (1973). *)
(* *)
(* Input arguments *)
(* *)
(* x value at which the series is to be evaluated. *)
(* A array of n terms of a chebyshev series. in *)
(* evaluating a, only half the first coef is summed. *)
(* n number of terms in array A. *)
(*-------------------------------------------------------------*)
CONST eps = 1.0E-10;
VAR twox,b0,b1,b2 : LONGREAL;
i : INTEGER;
BEGIN
IF (n < 1) THEN
FatalError('SpezFunkt2.dGamma.Dcsevl: number of terms <= 0');
ELSIF (n > 1000) THEN
FatalError('SpezFunkt2.sGamma.Dcsevl: number of terms > 1000');
END;
IF (x < -(1.0+eps)) OR (x > (1.0+eps)) THEN
ErrOut('SpezFunkt2.dGamma.Dcsevl: x outside (-1,+1)');
END;
twox := 2.0*x;
b1:=0.0; b0:=0.0;
b2:=0.0; (* Wg. Compilerwarnung *)
FOR i:=1 TO n DO
b2 := b1;
b1 := b0;
b0 := twox*b1 - b2 + A[n-i];
END;
RETURN 0.5*(b0-b2);
END Dcsevl;
PROCEDURE D9lnMC(VAR x: LONGREAL): LONGREAL;
(*-------------------------------------------------------------*)
(* Compute the log gamma correction factor for x > 10 so that *)
(* ln (dGamma(x)) = ln(sqrt(2*pi)) + (x-.5)*ln(x) *)
(* - x + D9lnMC(x) *)
(* *)
(* Series for ALGM on the interval 0. to 1.00000E-02 *)
(* with weighted error 1.28E-31 *)
(* ln weighted error 30.89 *)
(* significant figures required 29.81 *)
(* decimal places required 31.48 *)
(*-------------------------------------------------------------*)
BEGIN
IF (x < 10.0) THEN
ErrOut('SpezFunkt2.dGamma.D9lnMC: x must be > 10');
END;
IF (x >= xmax) THEN
ErrOut('SpezFunkt2.dGamma.D9lnMC: x so big D9lnMC underflows');
RETURN 0.0;
END;
IF (x < xbig) THEN
RETURN Dcsevl(2.0*sqr(10.0/x) - 1.0,Algmcs,nalgm) / x;
ELSE
RETURN 1.0 / (12.0*x);
END;
END D9lnMC;
VAR i,n : INTEGER;
sinpiy,y : LONGREAL;
result : LONGREAL;
BEGIN (* dGamma *)
(*
VAR x:LONGREAL;
x:=1.0;
REPEAT
y := Dcsevl(x,Gamcs,ngam);
y := Dcsevl(x,Algmcs,nalgm);
TIO.WrLngReal(x,12,5); TIO.WrChar(";"); TIO.WrLngReal(y,30,20); TIO.WrLn;
x:=x - 0.01;
UNTIL (x < -1.0);
*)
IF (ABS(X) < 0.03125) AND (ABS(X) > 0.0) THEN (* MRi, 29.05.16 *)
RETURN GamSmall(X);
END;
y := ABS(X);
IF (y > 10.0) THEN
(* gamma(x) for ABS(x) .gt. 10.0. recall y = ABS(x). *)
IF (X > xmax) THEN
ErrOut('SpezFunkt2.dGamma: x so big gamma overflows');
RETURN INF;
END;
IF (X < xmin) THEN
ErrOut('SpezFunkt2.dGamma: x so small gamma underflows');
RETURN 0.0;
END;
result := exp((y-0.5)*ln(y) - y + sq2pil + D9lnMC(y));
IF (X > 0.0) THEN RETURN result;END;
IF (ABS((X - DINT(X-0.5)) / X) < dxrel ) THEN
ErrOut('SpezFunkt2.dGamma answer lt half precision');
ErrOut(' x too near negative integer');
END;
sinpiy := sin(pi*y);
IF (sinpiy = 0.0) THEN
ErrOut('SpezFunkt2.dGamma x is a negative integer');
END;
RETURN -pi/(y*sinpiy*result);
ELSE
(* compute gamma(x) for -xbnd .le. x .le. xbnd. reduce interval *)
(* and find gamma(1+y) for 0.0 .le. y .lt. 1.0 first of all. *)
n := round(X);
IF (X < 0.0) THEN DEC(n); END;
y := X - VAL(LONGREAL,n);
DEC(n);
result := 0.9375 + Dcsevl(2.0*y-1.0,Gamcs,ngam);
IF (n = 0) THEN
RETURN result;
ELSIF (n <= 0) THEN
(* compute gamma(x) for x .lt. 1.0 *)
n:=-n;
IF (X = 0.0) THEN ErrOut('SpezFunkt2.dGamma: x is 0'); END;
IF (X < 0.0) AND ((X+VAL(LONGREAL,(n-2))) = 0.0) THEN
FatalError('dgamma: x is a negative integer');
END;
IF (X < -0.5) AND (ABS((X-DINT(X-0.5)) / X) < dxrel) THEN
ErrOut('SpezFunkt2.dGamma answer lt half precision because');
ErrOut(' x too near negative integer');
END;
IF (y < xsml) THEN
ErrOut('SpezFunkt2.dGamma x is so close to 0.0 that');
ErrOut(' the result overflows');
RETURN INF;
END;
FOR i:=1 TO n DO
result :=result / (X + VAL(LONGREAL,(i-1)));
END;
RETURN result;
END; (* IF n *)
END; (* IF x < 10 *)
(* gamma(x) for x .ge. 2.0 and x .le. 10.0 *)
FOR i:=1 TO n DO
result:=result*(y+VAL(LONGREAL,i));
END;
RETURN result;
END dGamma;
PROCEDURE InitDS(VAR Koeff : ARRAY OF LONGREAL;
NKoeff : CARDINAL;
eta : LONGREAL) : CARDINAL;
(*--------------------------------------------------------------*)
(* Global für Initialisierung-Code *)
(* *)
(* Determine the number of terms needed in an orthogonal *)
(* polynomial series so that it meets a specified accuracy. *)
(* *)
(* Initialize the orthogonal series, represented by the *)
(* array Koeff, so that InitDS is the number of terms needed to *)
(* insure the error is no larger than eta. Ordinarily, eta will *)
(* be chosen to be one-tenth machine precision. *)
(* *)
(* KoeffVek : Array of coefficients in an orthogonal series. *)
(* NKoeff : Number of coefficients in OS. *)
(* eta : Scalar containing requested accuracy of series. *)
(*--------------------------------------------------------------*)
VAR err : LONGREAL;
i,ii : CARDINAL;
BEGIN
IF (NKoeff < 1) THEN
FatalError('InitDS: Number of coefficients is less than 1');
END;
err:=0.0; ii:=0;
REPEAT (* Im Original ist eta & err REAL*4 *)
INC(ii);
i := NKoeff - ii;
err:=err + ABS(Koeff[i]);
(*
TIO.WrStr("InitDS: i,ii = "); TIO.WrCard(i,3); TIO.WrCard(ii,3);
TIO.WrLn;
*)
UNTIL (err > eta) OR (ii = NKoeff);
IF (i = 0) THEN
ErrOut('InitDS: Chebyshev series too short for specified accuracy');
END;
(*
TIO.WrLn;
TIO.WrStr("InitDS: NKoeff,i = "); TIO.WrCard(NKoeff,3); TIO.WrCard(i,3);
TIO.WrLn;
*)
RETURN i+1;
END InitDS;
PROCEDURE D9GamL(VAR Xmin,Xmax : LONGREAL);
(*----------------------------------------------------------------*)
(* Calculate the minimum and maximum legal bounds for x in *)
(* dGamma(x). Xmin and Xmax are not the only bounds, but they are *)
(* the only non trivial ones to calculate. *)
(* *)
(* Output arguments *)
(* *)
(* xmin minimum legal value of x in gamma(x). Any smaller *)
(* value of x might result in underflow. *)
(* xmax maximum legal value of x in gamma(x). Any larger *)
(* value of x might cause overflow. *)
(* *)
(* Only called once in the Module initialisation code *)
(*----------------------------------------------------------------*)
VAR i : INTEGER;
alnbig,alnsml,xln,xold : LONGREAL;
found : BOOLEAN;
BEGIN
alnsml := ln(D1Mach(1));
Xmin:=-alnsml;
i:=0;
REPEAT
INC(i);
xold := Xmin; xln := ln(Xmin);
Xmin := Xmin - Xmin*((Xmin+0.5)*xln - Xmin - 0.2258 + alnsml) /
(Xmin*xln + 0.5);
found := (ABS(Xmin - xold) < 0.005);
UNTIL found OR (i > 10);
IF NOT found THEN FatalError('d9gaml: unable to find xmin'); END;
(* LOOP
* FOR i:=1 TO 10 DO
* xold := Xmin; xln := ln(Xmin);
* Xmin := Xmin - Xmin*((Xmin+0.5)*xln - Xmin - 0.2258 + alnsml) /
* (Xmin*xln + 0.5);
* IF (ABS(Xmin - xold) < 0.005) THEN EXIT; END;
* END;
* FatalError('d9gaml: unable to find xmin'); HALT;
* END; *)
Xmin := -Xmin + 0.01;
alnbig := ln(D1Mach(2));
Xmax := alnbig;
i:=0;
REPEAT
INC(i);
xold := Xmax; xln := ln(Xmax);
Xmax := Xmax - Xmax*((Xmax - 0.5)*xln - Xmax + 0.9189 - alnbig) /
(Xmax*xln - 0.5);
found := (ABS(Xmax - xold) < 0.005);
UNTIL found OR (i > 10);
IF NOT found THEN FatalError('d9gaml: unable to find xmax'); END;
(* LOOP
* FOR i:=1 TO 10 DO
* xold := Xmax; xln := ln(Xmax);
* Xmax := Xmax - Xmax*((Xmax - 0.5)*xln - Xmax + 0.9189 - alnbig) /
* (Xmax*xln - 0.5);
* IF (ABS(Xmax - xold) < 0.005) THEN EXIT; END;
* END;
* FatalError('d9gaml: unable to find xmax'); HALT;
* END; *)
Xmax := Xmax - 0.01;
Xmin := DMAX1(Xmin,-Xmax + 1.0);
END D9GamL;
BEGIN
Gamcs:=gamcs; (* For efficiency reasons *)
Algmcs:=algmcs;
(* Initialisierungcode für dGaD1mma *)
ngam := InitDS(Gamcs,42,0.1*D1Mach(3));
D9GamL(xmin,xmax);
(* xsml = 2.247436222560E-308 *)
xsml := exp(DMAX1(ln(D1Mach(1)),-ln(D1Mach(2))) + 0.01);
dxrel := sqrt(D1Mach(4));
(* Initialisierungcode für D9lnMC *)
nalgm := InitDS(Algmcs,15,0.1*D1Mach(3));
xbig := 1.0/sqrt(D1Mach(3));
D9lnMCxmax := exp(DMIN(ln(D1Mach(2)/12.0),-ln(12.0*D1Mach(1))));
END LibdGamma;
PROCEDURE Errf(x : LONGREAL) : LONGREAL;
(*----------------------------------------------------------------*)
(* Ben"otigt die PROCEDURE GammaU *)
(* Reihenentwicklung : *)
(* Errf x = {2 \over {\sqrt \pi}} \cdot *)
(* \sum_{i=0}^\infty {{-1}^i x^{2i+1} \over {(2i+1) i!}} *)
(*----------------------------------------------------------------*)
CONST genau = 1.0E-15;
Konst = 1.128379167095512570; (* 2.0/sqrt(pi) *)
VAR i : CARDINAL;
Sum,y : LONGREAL;
x2,x2i1,fact : LONGREAL;
BEGIN
IF (x < 0.0) THEN RETURN - GammaU(0.5,x*x); END;
IF (x = 0.0) THEN
RETURN 0.0;
ELSIF (x > 6.0) THEN
RETURN 1.0;
ELSIF (x < 1.0) THEN (* Reihenentwicklung *)
x2:=x*x; Sum:=x;
i:=1; fact:=1.0; x2i1:=-x*x2;
LOOP
y := x2i1 / (LFLOAT(2*i+1)*fact);
Sum:=Sum+y;
IF (ABS(y) < genau*ABS(Sum)) THEN EXIT END;
x2i1:=-x2i1*x2;
INC(i);
fact:=fact*LFLOAT(i);
END;
RETURN Konst*Sum;
ELSE (* x \in [1,6] *)
RETURN GammaU(0.5,x*x);
END;
END Errf;
MODULE ErrorFunction; (* Kapselt Daten für ErrorF,CompErrorF *)
IMPORT LowLong;
IMPORT sqrtpi,exp;
<* IF (__XDS__) THEN *>
IMPORT ErrorF,CompErrorF; (* EXPORT *)
<* ELSE *>
EXPORT ErrorF,CompErrorF;
<* END *>
TYPE Vek18 = ARRAY [1..18] OF LONGREAL;
Vek17 = ARRAY [1..17] OF LONGREAL;
CONST xup = 6.25;
A = Vek18{
1.9449071068178803E+00, 4.20186582324414E-02,
-1.86866103976769E-02, 5.1281061839107E-03,
-1.0683107461726E-03, 1.744737872522E-04,
-2.15642065714E-05, 1.7282657974E-06,
-2.00479241E-08, -1.64782105E-08,
2.0008475E-09, 2.57716E-11,
-3.06343E-11, 1.9158E-12,
3.703E-13, -5.43E-14,
-4.0E-15, 1.2E-15
};
B = Vek17{
1.4831105640848036E+00, -3.010710733865950E-01,
6.89948306898316E-02, -1.39162712647222E-02,
2.4207995224335E-03, -3.658639685849E-04,
4.86209844323E-05, -5.7492565580E-06,
6.113243578E-07, -5.89910153E-08,
5.2070091E-09, -4.232976E-010,
3.18811E-11, -2.2361E-012,
1.467E-13, -9.0E-15,
5.0E-16
};
PROCEDURE ErrorF(x : LONGREAL) : LONGREAL;
VAR t,s,s1,s2,x2 : LONGREAL;
i : CARDINAL;
BEGIN
t:=ABS(x); (* t = XV *)
IF (t <= 2.0) THEN
x2 := x*x - 2.0;
s1 := B[17];
s2 := 0.0;
s := x2*B[17] + B[16]; (* s = BJP2 *)
FOR i:=15 TO 1 BY -1 DO
s2 := s1;
s1 := s;
s := x2*s1 - s2 + B[i];
END;
RETURN (s - s2)*x / 2.0;
ELSIF (t < xup) THEN
x2 := 2.0 - 20.0 / (t + 3.0);
s1 := A[18];
s2 := 0.0;
s := x2*A[18] + A[17]; (* s = BJ *)
FOR i:=16 TO 1 BY -1 DO
s2 := s1;
s1 := s;
s := x2*s1 - s2 + A[i];
END;
x2 := ((s - s2) / (2.0*t))*exp(-x*x) / sqrtpi;
RETURN (1.0 - x2)*LowLong.sign(x);
ELSE
RETURN LowLong.sign(x);
END;
END ErrorF;
TYPE Vek23 = ARRAY [1..23] OF LONGREAL;
CONST xlow = -6.25;
xhigh = 27.28;
C = Vek23{
1.455897212750385E-01, -2.734219314954260E-01,
2.260080669166197E-01, -1.635718955239687E-01,
1.026043120322792E-01, -5.480232669380236E-02,
2.414322397093253E-02, -8.220621168415435E-03,
1.802962431316418E-03, -2.553523453642242E-05,
-1.524627476123466E-04, 4.789838226695987E-05,
3.584014089915968E-06, -6.182369348098529E-06,
7.478317101785790E-07, 6.575825478226343E-07,
-1.822565715362025E-07, -7.043998994397452E-08,
3.026547320064576E-08, 7.532536116142436E-09,
-4.066088879757269E-09, -5.718639670776992E-10,
3.328130055126039E-10
};
PROCEDURE CompErrorF(x : LONGREAL) : LONGREAL;
(*----------------------------------------------------------------*)
(* Maximale Abweichung mit F77 Routine ist *)
(* *)
(* im Intervall (0 ,2 ) *)
(* im Intervall (2 ,5 ) *)
(* im Intervall (5 ,10) *)
(* im Intervall (10,15) *)
(* im Intervall (15,25) *)
(*----------------------------------------------------------------*)
CONST xlow = -6.25;
xhigh = 27.28;
VAR t,s,polx : LONGREAL;
i : CARDINAL;
BEGIN
IF (x <= xlow) THEN
RETURN 2.0;
ELSIF (x >= xhigh) THEN
RETURN 0.0;
ELSE
t := 1.0 - 7.5 / (ABS(x) + 3.75);
polx := 0.0;
FOR i:=23 TO 1 BY -1 DO polx:=polx*t + C[i]; END;
s := exp(-x*x)*polx;
IF (x < 0.0) THEN
RETURN 2.0 - s;
ELSE
RETURN s;
END;
END;
END CompErrorF;
END ErrorFunction;
PROCEDURE CLnGamma(Z : LONGCOMPLEX) : LONGCOMPLEX; (* CERN *)
TYPE V10 = ARRAY [1..10] OF LONGREAL;
CONST C1 = 9.18938533204672742E-01;
C2 = 1.14472988584940017E+00;
Ci = V10{
8.33333333333333333E-02, -2.77777777777777778E-03,
7.93650793650793651E-04, -5.95238095238095238E-04,
8.41750841750841751E-04, -1.91752691752691753E-03,
6.41025641025641026E-03, -2.95506535947712418E-02,
1.79644372368830573E-01, -1.39243221690590112E+00
};
VAR a,x,y,t,ui,ur,ya : LONGREAL;
i : INTEGER;
u,h,p,r : LONGCOMPLEX;
BEGIN
x := RE(Z);
y := IM(Z);
IF (x <= 0.0) AND (y = 0.0) AND (ABS(x) = LFLOAT(TRUNC(ABS(x)))) THEN
h := CMPLX(INF,INF);
ErrOut("Argument equals non-positive integer (CLnGamma)");
ELSE
ya := ABS(y);
u := CMPLX(x,ya);
IF (x < 0.0) THEN
u := one - u;
END;
h := zero;
ur := RE(u);
IF (ur < 7.0) THEN
ui := IM(u);
a := arctan2(ui,ur);
h := u;
FOR i:=1 TO 6-VAL(INTEGER,ur) DO
ur := ur + 1.0;
u := CMPLX(ur,ui);
h := h*u;
a := a + arctan2(ui,ur);
END;
h := CMPLX(0.5*ln(sqr(RE(h)) + sqr(IM(h))),a);
u := u + one;
END; (* IF *)
r := one / (u*u);
p := scalarMult(Ci[10],r);
FOR i:=9 TO 2 BY - 1 DO
p := r*CMPLX(Ci[i] + RE(p), IM(p));
END;
h := CMPLX(C1,0.0) + CMPLX(RE(u)-0.5,IM(u))*LongComplexMath.ln(u) - u +
CMPLX(Ci[1] + RE(p),IM(p)) / u - h;
IF (x < 0.0) THEN
ur := LFLOAT(VAL(INTEGER,x) - 1);
ui := pi*(x - ur);
x := pi*ya;
t := exp(-x-x);
a := sin(ui);
t := x + 0.5*ln(t*(a*a) + sqr(0.5*(1.0 - t)));
a := arctan2(cos(ui)*tanh(x),a) - ur*pi;
h := CMPLX(C2 - t,a) - h;
END; (* IF *)
IF (y < 0.0) THEN
h := conj(h);
END;
END; (* IF *)
RETURN h;
END CLnGamma;
PROCEDURE CGamma(Z : LONGCOMPLEX) : LONGCOMPLEX; (* MRi *)
VAR lnZ : LONGCOMPLEX;
BEGIN
IF (Z = zero) THEN
RETURN CMPLX(INF, INF);
ELSIF (RE(Z) >= MaxGam) THEN
RETURN CMPLX(INF, INF);
ELSE
lnZ := CLnGamma(Z);
IF (lnZ = CMPLX(INF,INF)) THEN
RETURN lnZ;
ELSE
RETURN LongComplexMath.exp(lnZ);
END;
END;
END CGamma;
PROCEDURE CdGamma(z : LONGCOMPLEX) : LONGCOMPLEX;
(*----------------------------------------------------------------*)
(* This code is a Modula-2 translation of the fftlog subroutine *)
(* form github.com/coccoinomane/fftlog-f90/blob/master/cdgamma.f *)
(* published under the MIT licence. It is based on work of *)
(* Takuya Ooura, Research Institute for Mathematical Sciences, *)
(* Kyoto University with modification by Andrew Hamilton *)
(*----------------------------------------------------------------*)
PROCEDURE ANINT(x : LONGREAL) : LONGREAL;
(* Fortran ANINT function *)
BEGIN
IF (x < 0.0) THEN
RETURN LFLOAT(INT(x-0.5));
ELSE
RETURN LFLOAT(INT(x+0.5));
END;
END ANINT;
CONST IfLn = FALSE; (* calculate gamma(z) *)
Huge = LFLOAT(MAX(REAL));
OneP = 1.0 + 4.0*MachEps;
CONST PV = 7.31790632447016203E+00; PU = 3.48064577727581257E+00;
PR = 3.27673720261526849E-02;
P1 = 1.05400280458730808E+01; P2 = 4.73821439163096063E+01;
P3 = 9.11395751189899762E+01; P4 = 6.62756400966213521E+01;
P5 = 1.32280130755055088E+01; P6 = 2.93729529320536228E-01;
Q1 = 9.99999999999975753E-01; Q2 = 2.00000000000603851E+00;
Q3 = 2.99999999944915534E+00; Q4 = 4.00000003016801681E+00;
Q5 = 4.99999857982434025E+00; Q6 = 6.00009857740312429E+00;
VAR xr,xi,yr,yi,ur,ui,vr,vi,wr,wi,t : LONGREAL;
BEGIN
xr := RE(z); xi := IM(z);
IF (ABS(xr) < 2.0*MachEps) AND (ABS(xi) < 2.0*MachEps) THEN
ErrOut("CdGamma) is (+infinity,+infinity) (CdGamma)");
yi := INF; yr := INF;
ELSIF (xr <= 0.0) AND (ABS(xi) <= 2.0*MachEps) AND IsNearInteger(xr) THEN
(* x = 0, -1, -2 *)
IF IfLn THEN (* lngamma *)
(* real part is +infinity *)
ErrOut("RE(CdGamma) is + infinity (CdGamma)");
yr := INF;
yi := pi*LFLOAT(INT(xr));
ELSE (* gamma *)
IF ODD(INT(xr*OneP)) THEN
yr := -INF;
ErrOut("RE(CdGamma) is - infinity (CdGamma)");
ELSE (* + infinity at even negative integers *)
yr := INF;
ErrOut("RE(CdGamma) is + infinity (CdGamma)");
END;
yi := 0.0;
END; (* IfLn *)
ELSE
(* re(x) < 1/2 : use reflection formula *)
IF (xr < 0.5) THEN
wr := 1.0 - xr;
wi := -xi;
ELSE
wr := xr;
wi := xi;
END;
(* large |x|: keep only leading term of rational function *)
t := wr*wr + wi*wi;
IF (t > Huge) THEN (* Assume we calculete with LONGREAL *)
(* rational function v *)
vr := wr/t + PR;
vi := -wi/t;
(* ln(overall factor) u = ln(x + pv) - 1 *)
yr := wr + PV;
ur := yr; IF (ur < 0.0) THEN ur := -ur; END;
ui := wi; IF (ui < 0.0) THEN ui := -ui; END;
IF (ur >= ui) THEN
t := wi / yr;
ur := ln(ur) + 0.5*ln(1.0 + t*t) - 1.0;
ELSE
t := yr/wi;
ur := ln(ui) + 0.5*ln(1.0 + t*t) - 1.0;
END;
ui := arctan2(wi,yr);
ELSE
(* not large |x| *)
ur := wr + Q6;
vr := ur*(wr + Q5) - wi*wi;
vi := wi*(wr + Q5) + ur*wi;
yr := P6 + (P5*ur + P4*vr);
yi := P5*wi + P4*vi;
ur := vr*(wr + Q4) - vi*wi;
ui := vi*(wr + Q4) + vr*wi;
vr := ur*(wr + Q3) - ui*wi;
vi := ui*(wr + Q3) + ur*wi;
yr := yr + (P3*ur + P2*vr);
yi := yi + (P3*ui + P2*vi);
ur := vr*(wr + Q2) - vi*wi;
ui := vi*(wr + Q2) + vr*wi;
vr := ur*(wr + Q1) - ui*wi;
vi := ui*(wr + Q1) + ur*wi;
yr := yr + (P1*ur + vr);
yi := yi + (P1*ui + vi);
ur := vr*wr - vi*wi;
ui := vi*wr + vr*wi;
t := ur*ur + ui*ui;
vr := (yr*ur + yi*ui)/t + PR;
vi := (yi*ur - yr*ui)/t;
yr := wr + PV;
ur := 0.5*ln(yr*yr + wi*wi) - 1.0;
ui := arctan2(wi,yr);
END; (* IF t *)
yr := ur*(wr - 0.5) - ui*wi - PU;
yi := ui*(wr - 0.5) + ur*wi;
yr := yr + 0.5*ln(vr*vr + vi*vi);
yi := yi + arctan2(vi,vr);
t := 1.0;
IF (xr < 0.5) THEN
wi := ANINT(xr);
wr := xr - wi;
IF (wi > xr) THEN wi := wi - 1.0; END;
IF (xi = 0.0) THEN (* case of real x *)
wr := ln(sin(pi*ABS(wr)));
IF IfLn THEN
wi := -pi*wi;
ELSE
IF (wi # 2.0*LFLOAT(INT(0.5*wi))) THEN t := -1.0; END;
wi:=0.0;
END;
ELSIF (ABS(xi) < 1.0) THEN
(* imaginary part of x is < 1 in absolute value *)
IF IfLn THEN
ui := -pi*wi;
IF (xi < 0.0) THEN ui := -ui; END;
ELSE
IF (wi # 2.0*LFLOAT(INT(0.5*wi))) THEN
t := -1.0;
END;
ui := 0.0;
END; (* IfLn *)
wr := pi*wr;
wi := pi*xi;
vr := sin(wr)*cosh(wi);
vi := cos(wr)*sinh(wi);
IF (wr < 0.0) THEN
vr := -vr;
vi := -vi;
END;
wr := 0.5*ln(vr*vr + vi*vi);
wi := ui + arctan2(vi,vr);
ELSE
(* imaginary part of x is >= 1 in absolute value *)
IF IfLn THEN
ui := pi*(0.5 - xr);
ELSE
IF (wi # 2.0*LFLOAT(INT(0.5*wi))) THEN
t := -1.0;
END; (* IF *)
IF (wr >= 0.0) THEN
ui := pi*(+0.5 - wr);
ELSE
ui := pi*(-0.5 - wr);
END;
END;
wi := exp(-2.0*pi*ABS(xi));
wr := 2.0*pi*wr;
vr := 0.5*(1.0 - cos(wr)*wi);
vi := -0.5*sin(wr)*wi;
ur := pi*xi;
(* w = ln[sin(pi x)] *)
IF (xi > 0.0) THEN
wr := ur + 0.5*ln(vr*vr + vi*vi);
wi := ui + arctan2(vi,vr);
ELSIF (xi < 0.0) THEN
wr := -ur + 0.5*ln(vr*vr + vi*vi);
wi := -ui - arctan2(vi,vr);
END;
END; (* IF xi *)
(* y = ln[gamma(x)] *)
yr := ln(pi) - yr - wr;
yi := -yi - wi;
END; (* IF *)
IF NOT IfLn THEN (* gamma *)
ur := exp(yr);
IF (xi = 0.0) THEN
yr := t*ur;
yi := 0.0;
ELSE
yr := t*ur*cos(yi);
yi := ur*sin(yi);
END;
END;
END; (* IF NOT z = 0, -1, -2, ... *)
RETURN CMPLX(yr,yi);
END CdGamma;
PROCEDURE IBeta(A,B : LONGREAL;
X : LONGREAL) : LONGREAL;
PROCEDURE PSeries(A,B : LONGREAL;
X : LONGREAL) : LONGREAL;
(*---------------------------------------------------------------*)
(* Power series for incomplete beta integral. *)
(* Use when B*X is small *)
(*---------------------------------------------------------------*)
VAR S,T,U,V,T1,Z,Ai : LONGREAL;
N : INTEGER;
BEGIN
Ai := 1.0 / A;
U := (1.0 - B) * X;
V := U / (A + 1.0);
T1 := V;
T := U;
N := 2;
S := 0.0;
Z := MachEps*Ai;
WHILE (ABS(V) > Z) DO
U := (LFLOAT(N) - B) * X / LFLOAT(N);
T := T * U;
V := T / (A + LFLOAT(N));
S := S + V;
INC(N);
END;
S := S + T1;
S := S + Ai;
U := A*ln(X);
IF (A + B < MaxGam) AND (ABS(U) < MaxLog) THEN
T := dGamma(A + B) / (dGamma(A)*dGamma(B));
S:=S * T*power(X,A);
ELSE
T := dLnGamma(A + B) - dLnGamma(A) - dLnGamma(B) + U + ln(S);
IF T < MinLog THEN
S := 0.0
ELSE
S := exp(T);
END;
END;
RETURN S;
END PSeries;
PROCEDURE CFrac1(A,B : LONGREAL;
X : LONGREAL) : LONGREAL;
(* Continued fraction expansion #1 for incomplete beta integral *)
CONST Big = 1.0 / MachEps;
Thresh = 3.0 * MachEps;
VAR Xk,Pk,Pkm1,Pkm2,Qk,Qkm1,Qkm2 : LONGREAL;
K1,K2,K3,K4,K5,K6,K7,K8 : LONGREAL;
R,T,Ans : LONGREAL;
N : INTEGER;
BEGIN
K1 := A;
K2 := A + B;
K3 := A;
K4 := A + 1.0;
K5 := 1.0;
K6 := B - 1.0;
K7 := K4;
K8 := A + 2.0;
Pkm2 := 0.0;
Qkm2 := 1.0;
Pkm1 := 1.0;
Qkm1 := 1.0;
Ans := 1.0;
R := 1.0;
N := 0;
LOOP
Xk := - (X * K1 * K2) / (K3 * K4);
Pk := Pkm1 + Pkm2 * Xk;
Qk := Qkm1 + Qkm2 * Xk;
Pkm2 := Pkm1;
Pkm1 := Pk;
Qkm2 := Qkm1;
Qkm1 := Qk;
Xk := (X * K5 * K6) / (K7 * K8);
Pk := Pkm1 + Pkm2 * Xk;
Qk := Qkm1 + Qkm2 * Xk;
Pkm2 := Pkm1;
Pkm1 := Pk;
Qkm2 := Qkm1;
Qkm1 := Qk;
IF (Qk <> 0.0) THEN R := Pk / Qk; END;
IF (R <> 0.0) THEN
T := ABS((Ans - R) / R);
Ans := R;
ELSE T := 1.0;END;
IF (T < Thresh) THEN EXIT; END;
K1 := K1 + 1.0;
K2 := K2 + 1.0;
K3 := K3 + 2.0;
K4 := K4 + 2.0;
K5 := K5 + 1.0;
K6 := K6 - 1.0;
K7 := K7 + 2.0;
K8 := K8 + 2.0;
IF (ABS(Qk) + ABS(Pk) > Big) THEN
Pkm2:=Pkm2 * MachEps;
Pkm1:=Pkm1 * MachEps;
Qkm2:=Qkm2 * MachEps;
Qkm1:=Qkm1 * MachEps;
END;
IF (ABS(Qk) < MachEps) OR (ABS(Pk) < MachEps) THEN
Pkm2:=Pkm2 * Big;
Pkm1:=Pkm1 * Big;
Qkm2:=Qkm2 * Big;
Qkm1:=Qkm1 * Big;
END;
INC(N);
IF (N > 400) THEN
Fehler:=TRUE;
Fehlerflag:="FPLoss (CFrac1)";
END;
END; (* LOOP *)
RETURN Ans;
END CFrac1;
PROCEDURE CFrac2(A,B : LONGREAL;
X : LONGREAL) : LONGREAL;
(* Continued fraction expansion #2 for incomplete beta integral *)
CONST Big = 1.0 / MachEps;
Thresh = 3.0 * MachEps;
VAR Xk,Pk,Pkm1,Pkm2,Qk,Qkm1,Qkm2 : LONGREAL;
K1,K2,K3,K4,K5,K6,K7,K8 : LONGREAL;
R,T,Z,Ans : LONGREAL;
N : INTEGER;
BEGIN
K1 := A;
K2 := B - 1.0;
K3 := A;
K4 := A + 1.0;
K5 := 1.0;
K6 := A + B;
K7 := A + 1.0;
K8 := A + 2.0;
Pkm2 := 0.0;
Qkm2 := 1.0;
Pkm1 := 1.0;
Qkm1 := 1.0;
Z := X / (1.0 - X);
Ans := 1.0;
R := 1.0;
N := 0;
LOOP
Xk := - (Z * K1 * K2) / (K3 * K4);
Pk := Pkm1 + Pkm2 * Xk;
Qk := Qkm1 + Qkm2 * Xk;
Pkm2 := Pkm1;
Pkm1 := Pk;
Qkm2 := Qkm1;
Qkm1 := Qk;
Xk := (Z * K5 * K6) / (K7 * K8);
Pk := Pkm1 + Pkm2 * Xk;
Qk := Qkm1 + Qkm2 * Xk;
Pkm2 := Pkm1;
Pkm1 := Pk;
Qkm2 := Qkm1;
Qkm1 := Qk;
IF (Qk <> 0.0) THEN R := Pk / Qk; END;
IF (R <> 0.0) THEN
T := ABS((Ans - R) / R);
Ans := R;
ELSE
T := 1.0;
END;
IF (T < Thresh) THEN EXIT; END;
K1 := K1 + 1.0;
K2 := K2 - 1.0;
K3 := K3 + 2.0;
K4 := K4 + 2.0;
K5 := K5 + 1.0;
K6 := K6 + 1.0;
K7 := K7 + 2.0;
K8 := K8 + 2.0;
IF (ABS(Qk) + ABS(Pk) > Big) THEN
Pkm2:=Pkm2 * MachEps;
Pkm1:=Pkm1 * MachEps;
Qkm2:=Qkm2 * MachEps;
Qkm1:=Qkm1 * MachEps;
END;
IF (ABS(Qk) < MachEps) OR (ABS(Pk) < MachEps) THEN
Pkm2:=Pkm2 * Big;
Pkm1:=Pkm1 * Big;
Qkm2:=Qkm2 * Big;
Qkm1:=Qkm1 * Big;
END;
INC(N);
N := N + 1;
IF (N > 400) THEN
Fehler:=TRUE;
Fehlerflag:="FPLoss (CFrac1)";
END;
END; (* LOOP *)
RETURN Ans;
END CFrac2;
VAR A1,B1,X1,T,W,Xc,Y : LONGREAL;
flag : BOOLEAN;
BEGIN
IF (A <= 0.0) OR (B <= 0.0) OR (X < 0.0) THEN
RETURN NAN;
END;
IF (X > 1.0) THEN
RETURN 1.0;
END;
IF (X = 0.0) OR (X = 1.0) THEN
RETURN X;
END;
flag := FALSE;
IF (B * X <= 1.0) AND (X <= 0.95) THEN
T := PSeries(A, B, X);
ELSE
W := 1.0 - X;
IF (X > (A / (A + B))) THEN
(* Reverse a and b if x is greater than the mean. *)
flag := TRUE;
A1 := B;
B1 := A;
Xc := X;
X1 := W;
ELSE
A1 := A;
B1 := B;
Xc := W;
X1 := X;
END;
IF flag AND (B1 * X1 <= 1.0) AND (X1 <= 0.95) THEN
T := PSeries(A1, B1, X1);
ELSE
(* Choose expansion for optimal convergence *)
Y := X1 * (A1 + B1 - 2.0) - (A1 - 1.0);
IF Y < 0.0 THEN
W := CFrac1(A1, B1, X1)
ELSE
W := CFrac2(A1, B1, X1) / Xc;
END;
(* Multiply w by the factor *)
(* a b _ _ _ *)
(* x (1-x) | (a+b) / ( a | (a) | (b) ) *)
Y := A1*ln(X1);
T := B1*ln(Xc);
IF (A1 + B1 < MaxGam) AND (ABS(Y) < MaxLog) AND (ABS(T) < MaxLog) THEN
T:= power(Xc,B1);
T:=T * power(X1,A1);
T:=T / A1;
T:=T * W;
T:=T * dGamma(A1 + B1) / (dGamma(A1)*dGamma(B1));
ELSE
(* Resort to logarithms *)
Y:=Y + T + dLnGamma(A1 + B1) - dLnGamma(A1)
- dLnGamma(B1) + ln(W/A1);
IF Y < MinLog THEN
T := 0.0
ELSE
T := exp(Y);
END;
END;
END; (* IF ELSE *)
END; (* IF ELSE *)
IF flag THEN
IF (T <= MachEps) THEN
T := 1.0 - MachEps
ELSE
T := 1.0 - T;
END;
END;
RETURN T;
END IBeta;
PROCEDURE SetGamitFast(opt : BOOLEAN);
BEGIN
fast:=opt;
END SetGamitFast;
PROCEDURE dGamit(A,X : LONGREAL): LONGREAL; (* SLATEC *)
PROCEDURE dLnGamSmall( X : LONGREAL;
VAR dLnGam : LONGREAL;
VAR SignGam : LONGREAL);
(*--------------------------------------------------------------*)
(* dLnGamSmall(x,dLnGam,SignGam) calculates the natural *)
(* logarithm of the absolute value of the gamma function for *)
(* real argumentx and stores the result in argument dLnGam. *)
(*--------------------------------------------------------------*)
VAR iFehl : INTEGER;
BEGIN (* +++ *)
IF fast THEN
dLnGam := aLnGamma(ABS(X),iFehl);
ELSE
dLnGam := dLnGamma(ABS(X));
END;
SignGam := 1.0;
IF (X <= 0.0) AND (TRUNC((X / 2.0) + 0.1) = 0) THEN
SignGam := - 1.0;
END;
END dLnGamSmall;
PROCEDURE d9Gamit( A,X : LONGREAL; (* SLATEC *)
VAR aLnAp1,SignGam : LONGREAL) : LONGREAL;
(*--------------------------------------------------------------*)
(* Compute Tricomis incomplete gamma function for small x. *)
(*--------------------------------------------------------------*)
CONST eps = 0.5*1.11E-16;
VAR RetVal,s,sgng2,t,te : LONGREAL;
ae,aeps,algs,alg2,fk : LONGREAL;
k,m,ma : INTEGER;
BEGIN
IF (X <= 0.0) THEN
ErrOut('x should be > 0 (d9gmit)');
(* Fehler:=TRUE; *)
RETURN MAX(LONGREAL);
END;
ma := VAL(INTEGER,(A + 0.5));
IF (A < 0.0) THEN
ma := VAL(INTEGER,(A - 0.5));
END;
aeps := A - VAL(LONGREAL,ma);
ae := A;
IF (A < -0.5) THEN
ae := aeps;
END;
te := ae;
s := 1.0;
k:=0;
REPEAT
k:=k + 1;
fk := VAL(LONGREAL,k);
te := -X*te / fk;
t := te / (ae + fk);
s := s + t;
UNTIL (ABS(t) < eps*ABS(s)) OR (k > 200);
IF (k > 200) THEN
ErrOut('No convergence in 200 terms of taylor-s series');
END;
IF (A >= -0.5) THEN
algs := -aLnAp1 + ln(s);
RetVal := exp(algs);
ELSE
algs := - dLnGamma(1.0 + aeps) + ln(s);
s := 1.0;
m := -ma - 1;
IF (m # 0) THEN
t := 1.0;
k:=0;
REPEAT
k:=k + 1;
t := X*t / (aeps - VAL(LONGREAL,(m+1-k)));
s := s + t;
UNTIL (ABS(t) < eps*ABS(s)) OR (k = m);
END;
RetVal := 0.0;
algs := -VAL(LONGREAL,ma)*ln(X) + algs;
IF (s = 0.0) OR (aeps = 0.0) THEN
RetVal := exp(algs);
ELSE
sgng2 := SignGam*DSIGN(1.0,s);
alg2 := -X - aLnAp1 + ln(ABS(s));
IF (alg2 > bot) THEN
RetVal := sgng2*exp(alg2);
END;
IF (algs > bot) THEN
RetVal:=RetVal + exp(algs);
END;
END;
END;
RETURN RetVal;
END d9Gamit;
PROCEDURE dGamR(X : LONGREAL): LONGREAL; (* SLATEC *)
(*--------------------------------------------------------------*)
(* dGamR(x) calculates the reciprocal of the complete gamma *)
(* function for real argument x. *)
(*--------------------------------------------------------------*)
VAR alngx,sgngx : LONGREAL;
BEGIN
IF (X <= 0.0) AND (VAL(LONGREAL,(VAL(INTEGER,X))) = X ) THEN
RETURN 0.0;
ELSE
IF (ABS(X) > 10.0) THEN
dLnGamSmall(X,alngx,sgngx);
RETURN sgngx*exp(-alngx);
ELSE
RETURN 1.0 / dGamma(X);
END;
END;
END dGamR;
VAR aeps,ainta,aLnAp1 : LONGREAL;
sga,SignGam,RetVal : LONGREAL;
iFehl : INTEGER;
BEGIN
sga := 1.0;
IF (A # 0.0) THEN
sga := DSIGN(1.0,A);
END;
ainta := VAL(LONGREAL,VAL(INTEGER,A + 0.5*sga));
aeps := A - ainta;
IF (X <= 0.0) THEN
RetVal := 0.0;
IF (ainta > 0.0) OR (aeps # 0.0) THEN
RetVal := dGamR(A+1.0);
END;
ELSIF (X <= 1.0) THEN (* Special case for small X *)
IF (A >= -0.5) OR (aeps # 0.0) THEN
dLnGamSmall(A+1.0,aLnAp1,SignGam);
END;
RetVal := d9Gamit(A,X,aLnAp1,SignGam);
ELSE
IF (A = 0.0) THEN
(* Bitte pruefen, das kann nicht funktionieren !!! *)
RetVal := GammaU(0.0,X) / sqrt(X);
ELSE
IF fast THEN
RetVal := GammaIn(X,A,iFehl) / power(X,A);
ELSE
RetVal := GammaU(A ,X) / power(X,A);
END;
END;
END;
RETURN RetVal;
END dGamit;
BEGIN
Sqrt2Pi := sqrt(2.0*pi);
bot := ln(1.0/MAX(LONGREAL));
fast := TRUE;
END SpezFunkt2.