2020-08-26 21:20:02 +00:00
|
|
|
unit MathUnit;
|
|
|
|
|
|
|
|
{ extract some math functions from functionslib for easier testing }
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
|
|
|
Classes, SysUtils;
|
|
|
|
|
2020-08-28 21:58:45 +00:00
|
|
|
function erf(x: Double): Double;
|
|
|
|
function erfc(x: Double) : Double;
|
|
|
|
function NormalDist(x: Double): Double;
|
|
|
|
|
2020-08-26 21:20:02 +00:00
|
|
|
function Beta(a, b: Double): Extended;
|
|
|
|
function BetaI(a,b,x: Double): Extended;
|
|
|
|
|
|
|
|
function GammaLn(x: double): Extended;
|
|
|
|
|
|
|
|
function tDist(x: Double; N: Integer; OneSided: Boolean): Double;
|
|
|
|
function tDensity(x: Double; N: Integer): Double;
|
|
|
|
|
|
|
|
function FDensity(x: Double; DF1, DF2: Integer): Double;
|
|
|
|
|
|
|
|
function Chi2Density(x: Double; N: Integer): Double;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
uses
|
|
|
|
Math;
|
|
|
|
|
2020-08-28 21:58:45 +00:00
|
|
|
// Calculates the error function
|
|
|
|
// /x
|
|
|
|
// erf(x) = 2/sqrt(pi) * | exp(-t²) dt
|
|
|
|
// /0
|
|
|
|
// borrowed from NumLib
|
|
|
|
function erf(x: Double): Double;
|
|
|
|
const
|
|
|
|
xup = 6.25;
|
|
|
|
SQRT_PI = 1.7724538509055160;
|
|
|
|
c: array[1..18] of Double = (
|
|
|
|
1.9449071068178803e0, 4.20186582324414e-2, -1.86866103976769e-2,
|
|
|
|
5.1281061839107e-3, -1.0683107461726e-3, 1.744737872522e-4,
|
|
|
|
-2.15642065714e-5, 1.7282657974e-6, -2.00479241e-8,
|
|
|
|
-1.64782105e-8, 2.0008475e-9, 2.57716e-11,
|
|
|
|
-3.06343e-11, 1.9158e-12, 3.703e-13,
|
|
|
|
-5.43e-14, -4.0e-15, 1.2e-15
|
|
|
|
);
|
|
|
|
d: array[1..17] of Double = (
|
|
|
|
1.4831105640848036e0, -3.010710733865950e-1, 6.89948306898316e-2,
|
|
|
|
-1.39162712647222e-2, 2.4207995224335e-3, -3.658639685849e-4,
|
|
|
|
4.86209844323e-5, -5.7492565580e-6, 6.113243578e-7,
|
|
|
|
-5.89910153e-8, 5.2070091e-9, -4.232976e-10,
|
|
|
|
3.18811e-11, -2.2361e-12, 1.467e-13,
|
|
|
|
-9.0e-15, 5.0e-16
|
|
|
|
);
|
|
|
|
var
|
|
|
|
t, s, s1, s2, x2: Double;
|
|
|
|
bovc, bovd, j: Integer;
|
|
|
|
sgn: Integer;
|
|
|
|
begin
|
|
|
|
bovc := SizeOf(c) div SizeOf(Double);
|
|
|
|
bovd := SizeOf(d) div SizeOf(Double);
|
|
|
|
t := abs(x);
|
|
|
|
if t <= 2 then
|
|
|
|
begin
|
|
|
|
x2 := sqr(x) - 2;
|
|
|
|
s1 := d[bovd];
|
|
|
|
s2 := 0;
|
|
|
|
j := bovd - 1;
|
|
|
|
s := x2*s1 - s2 + d[j];
|
|
|
|
while j > 1 do
|
|
|
|
begin
|
|
|
|
s2 := s1;
|
|
|
|
s1 := s;
|
|
|
|
j := j-1;
|
|
|
|
s := x2*s1 - s2 + d[j];
|
|
|
|
end;
|
|
|
|
Result := (s - s2) * x / 2;
|
|
|
|
end else
|
|
|
|
if t < xup then
|
|
|
|
begin
|
|
|
|
x2 := 2 - 20 / (t+3);
|
|
|
|
s1 := c[bovc];
|
|
|
|
s2 := 0;
|
|
|
|
j := bovc - 1;
|
|
|
|
s := x2*s1 - s2 + c[j];
|
|
|
|
while j > 1 do
|
|
|
|
begin
|
|
|
|
s2 := s1;
|
|
|
|
s1 := s;
|
|
|
|
j := j-1;
|
|
|
|
s := x2*s1 - s2 + c[j];
|
|
|
|
end;
|
|
|
|
x2 := ((s-s2) / (2*t)) * exp(-sqr(x)) / SQRT_PI;
|
|
|
|
if x < 0 then sgn := -1 else sgn := +1;
|
|
|
|
Result := (1 - x2) * sgn
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if x < 0 then
|
|
|
|
Result := -1.0
|
|
|
|
else
|
|
|
|
Result := +1.0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ calculates the complementary error function erfc(x) = 1 - erf(x) }
|
|
|
|
function erfc(x: Double) : Double;
|
|
|
|
begin
|
|
|
|
Result := 1.0 - erf(x);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
// Cumulative normal distribution
|
|
|
|
// x = -INF ... INF --> 0 ... 1
|
|
|
|
function NormalDist(x: Double): Double;
|
|
|
|
const
|
|
|
|
SQRT2 = sqrt(2.0);
|
|
|
|
begin
|
|
|
|
if x > 0 then
|
|
|
|
Result := (erf(x / SQRT2) + 1) * 0.5
|
|
|
|
else
|
|
|
|
if x < 0 then
|
|
|
|
Result := (1.0 - erf(-x / SQRT2)) * 0.5
|
|
|
|
else
|
|
|
|
Result := 0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-08-26 21:20:02 +00:00
|
|
|
function Beta(a, b: Double): Extended;
|
|
|
|
begin
|
|
|
|
if (a > 0) and (b > 0) then
|
|
|
|
Result := exp(GammaLn(a) + GammaLn(b) - GammaLn(a+b))
|
|
|
|
else
|
|
|
|
raise Exception.Create('Invalid argument for beta function.');
|
|
|
|
end;
|
|
|
|
|
|
|
|
function BetaCF(a, b, x: double): Extended;
|
|
|
|
const
|
|
|
|
itmax = 100;
|
|
|
|
eps = 3.0e-7;
|
|
|
|
var
|
|
|
|
tem,qap,qam,qab,em,d: extended;
|
|
|
|
bz,bpp,bp,bm,az,app: extended;
|
|
|
|
am,aold,ap: extended;
|
|
|
|
term1, term2, term3, term4, term5, term6: extended;
|
|
|
|
m: integer;
|
|
|
|
BEGIN
|
|
|
|
am := 1.0;
|
|
|
|
bm := 1.0;
|
|
|
|
az := 1.0;
|
|
|
|
qab := a+b;
|
|
|
|
qap := a+1.0;
|
|
|
|
qam := a-1.0;
|
|
|
|
bz := 1.0 - qab * x / qap;
|
|
|
|
for m := 1 to itmax do begin
|
|
|
|
em := m;
|
|
|
|
tem := em+em;
|
|
|
|
d := em * (b - m) * x / ((qam + tem) * (a + tem));
|
|
|
|
ap := az + d * am;
|
|
|
|
bp := bz + d * bm;
|
|
|
|
term1 := -(a + em);
|
|
|
|
term2 := qab + em;
|
|
|
|
term3 := term1 * term2 * x;
|
|
|
|
term4 := a + tem;
|
|
|
|
term5 := qap + tem;
|
|
|
|
term6 := term4 * term5;
|
|
|
|
d := term3 / term6;
|
|
|
|
app := ap + d * az;
|
|
|
|
bpp := bp + d * bz;
|
|
|
|
aold := az;
|
|
|
|
am := ap/bpp;
|
|
|
|
bm := bp/bpp;
|
|
|
|
az := app/bpp;
|
|
|
|
bz := 1.0;
|
|
|
|
if ((abs(az-aold)) < (eps*abs(az))) then
|
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ ShowMessage('WARNING! a or b too big, or itmax too small in betacf');}
|
|
|
|
Result := az
|
|
|
|
end;
|
|
|
|
|
|
|
|
function BetaI(a,b,x: Double): extended;
|
|
|
|
var
|
|
|
|
bt: extended;
|
|
|
|
term1, term2, term3, term4, term5: extended;
|
|
|
|
begin
|
|
|
|
if ((x < 0.0) or (x > 1.0)) then begin
|
|
|
|
{ ShowMessage('ERROR! Problem in routine BETAI');}
|
|
|
|
Result := 0.5;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if ((x <= 0.0) or (x >= 1.0)) then
|
|
|
|
bt := 0.0
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
term1 := GammaLn(a + b) - GammaLn(a) - GammaLn(b);
|
|
|
|
term2 := a * ln(x);
|
|
|
|
term3 := b * ln(1.0 - x);
|
|
|
|
term4 := term1 + term2 + term3;
|
|
|
|
bt := exp(term4);
|
|
|
|
end;
|
|
|
|
term5 := (a + 1.0) / (a + b + 2.0);
|
|
|
|
if x < term5 then
|
|
|
|
Result := bt * betacf(a,b,x) / a
|
|
|
|
else
|
|
|
|
Result := 1.0 - bt * betacf(b,a,1.0-x) / b
|
|
|
|
end;
|
|
|
|
|
|
|
|
function GammaLn(x: double): Extended;
|
|
|
|
var
|
|
|
|
tmp, ser: double;
|
|
|
|
cof: array[0..5] of double;
|
|
|
|
j: integer;
|
|
|
|
begin
|
|
|
|
cof[0] := 76.18009173;
|
|
|
|
cof[1] := -86.50532033;
|
|
|
|
cof[2] := 24.01409822;
|
|
|
|
cof[3] := -1.231739516;
|
|
|
|
cof[4] := 0.00120858003;
|
|
|
|
cof[5] := -0.00000536382;
|
|
|
|
|
|
|
|
x := x - 1.0;
|
|
|
|
tmp := x + 5.5;
|
|
|
|
tmp := tmp - (x + 0.5) * ln(tmp);
|
|
|
|
ser := 1.0;
|
|
|
|
for j := 0 to 5 do
|
|
|
|
begin
|
|
|
|
x := x + 1.0;
|
|
|
|
ser := ser + cof[j] / x;
|
|
|
|
end;
|
|
|
|
Result := -tmp + ln(2.50662827465 * ser);
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Calculates the (cumulative) t distribution function for N degrees of freedom
|
|
|
|
function tDist(x: Double; N: Integer; OneSided: Boolean): Double;
|
|
|
|
begin
|
|
|
|
Result := betai(0.5*N, 0.5, N/(N + sqr(x)));
|
|
|
|
if OneSided then Result := Result * 0.5;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Returns the density curve for the t statistic with N degrees of freedom
|
|
|
|
function tDensity(x: Double; N: Integer): Double;
|
|
|
|
var
|
|
|
|
factor: Double;
|
|
|
|
begin
|
|
|
|
factor := exp(gammaLn((N+1)/2) - gammaLn(N/2)) / sqrt(N * pi);
|
|
|
|
Result := factor * Power(1 + sqr(x)/N, (1-n)/2);
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Returns the density curve for the F statistic for DF1 and DF2 degrees of freedom.
|
|
|
|
function FDensity(x: Double; DF1, DF2: Integer): Double;
|
|
|
|
var
|
|
|
|
ratio1, ratio2, ratio3, ratio4: double;
|
|
|
|
part1, part2, part3, part4, part5, part6, part7, part8, part9: double;
|
|
|
|
begin
|
|
|
|
ratio1 := (DF1 + DF2) / 2.0;
|
|
|
|
ratio2 := (DF1 - 2.0) / 2.0;
|
|
|
|
ratio3 := DF1 / 2.0;
|
|
|
|
ratio4 := DF2 / 2.0;
|
|
|
|
part1 := exp(gammaln(ratio1));
|
|
|
|
part2 := power(DF1, ratio3);
|
|
|
|
part3 := power(DF2, ratio4);
|
|
|
|
part4 := exp(gammaln(ratio3));
|
|
|
|
part5 := exp(gammaln(ratio4));
|
|
|
|
part6 := power(x, ratio2);
|
|
|
|
part7 := power((x*DF1 + DF2), ratio1);
|
|
|
|
part8 := (part1 * part2 * part3) / (part4 * part5);
|
|
|
|
if (part7 = 0.0) then
|
|
|
|
part9 := 0.0
|
|
|
|
else
|
|
|
|
part9 := part6 / part7;
|
|
|
|
Result := part8 * part9;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
// Returns the density curve of the chi2 statistic for N degrees of freedom
|
|
|
|
function Chi2Density(x: Double; N: Integer): Double;
|
|
|
|
var
|
|
|
|
factor: Double;
|
|
|
|
begin
|
|
|
|
factor := Power(2.0, N * 0.5) * exp(gammaLN(N * 0.5));
|
|
|
|
Result := power(x, (N-2.0) * 0.5) / (factor * exp(x * 0.5));
|
|
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|
|
|