LazStats: Refactoring away some GOTOs in unit FunctionsLib.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7535 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-07-10 13:11:56 +00:00
parent 8db8946955
commit d3b5ba9322
5 changed files with 188 additions and 186 deletions

View File

@ -5,15 +5,15 @@ unit FunctionsLib;
interface
uses
Forms, Controls, LResources, ExtCtrls, StdCtrls, Classes, SysUtils, Globals,
Graphics, Dialogs, Math, MainUnit, OutPutUnit, dataprocs;
Forms, Controls, LResources, ExtCtrls, Classes, SysUtils, Globals,
Graphics, Dialogs, Math,
MainUnit, dataprocs;
function chisquaredprob(X : double; k : integer) : double;
function gammln(xx : double) : double;
PROCEDURE matinv(VAR a, vtimesw, v, w: DblDyneMat; n: integer);
FUNCTION sign(a,b: double): double;
FUNCTION isign(a,b : integer): integer;
FUNCTION max(a,b: double): double;
function inversez(prob : double) : double;
function zprob(p : double; VAR errorstate : boolean) : double;
function probz(z : double) : double;
@ -22,7 +22,7 @@ function zdensity(z : real) : real;
function probf(f,df1,df2 : extended) : extended;
FUNCTION alnorm(x : double; upper : boolean): double;
procedure ppnd7 (p : double; VAR normal_dev : double; VAR ifault : integer);
FUNCTION poly(c : Array of double; nord : integer; x : double): double; // RESULT(fn_val)
function poly(const c: Array of double; nord: integer; x: double): double; // RESULT(fn_val)
procedure swilk (var init : boolean; const x: DblDyneVec; n, n1, n2: integer;
const a: DblDyneVec; var w, pw: double; out ifault: integer);
procedure SVDinverse(VAR a : DblDyneMat; N : integer);
@ -39,7 +39,7 @@ function ProdSums(N, A : double) : double;
function combos(X, N : double) : double;
function ordinate(z : double) : double;
procedure Rank(v1col : integer; VAR Values : DblDyneVec);
procedure PRank(v1col : integer; VAR Values : DblDyneVec);
procedure PRank(v1col : integer; VAR Values : DblDyneVec; AReport: TStrings);
function UniStats(N : integer; VAR X : DblDyneVec; VAR z : DblDyneVec;
VAR Mean : double; VAR variance : double; VAR SD : double;
VAR Skew : double; VAR Kurtosis : double; VAR SEmean : double;
@ -50,9 +50,11 @@ function WholeValue(value : double) : double;
function FractionValue(value : double) : double;
function Quartiles(TypeQ : integer; pcntile : double; N : integer;
VAR values : DblDyneVec) : double;
function KolmogorovProb(z : double) : double;
function KolmogorovTest(na : integer; VAR a : DblDyneVec; nb : integer;
VAR b : DblDyneVec; option : String) : double;
function KolmogorovProb(z: double): double;
function KolmogorovTest(na: integer; const a: DblDyneVec; nb: integer;
const b: DblDyneVec; option: String; AReport: TStrings): double;
procedure poisson_cdf ( x : integer; a : double; VAR cdf : double );
procedure poisson_cdf_values (VAR n : integer; VAR a : double; VAR x : integer;
VAR fx : double );
@ -61,7 +63,6 @@ procedure poisson_check ( a : double );
function factorial(x : integer) : integer;
procedure poisson_pdf ( x : integer; VAR a : double; VAR pdf : double );
function DegToRad(Deg: Double): Double;
implementation
@ -136,9 +137,10 @@ PROCEDURE matinv(VAR a, vtimesw, v, w: DblDyneMat; n: integer);
(* adapted from the singular value decomposition of a matrix *)
(* a is a symetric matrix with the inverse returned in a *)
LABEL 1,2,3;
label
Lbl1, Lbl2, Lbl3;
VAR
var
// vtimesw, v, ainverse : matrix;
// w : vector;
ainverse : array of array of double;
@ -292,10 +294,10 @@ BEGIN
FOR its := 1 to 30 DO BEGIN
FOR l := k DOWNTO 0 DO BEGIN
nm := l-1;
IF ((abs(rv1[l])+anorm) = anorm) THEN GOTO 2;
IF ((abs(w[nm,nm])+anorm) = anorm) THEN GOTO 1
IF ((abs(rv1[l])+anorm) = anorm) THEN GOTO Lbl2;
IF ((abs(w[nm,nm])+anorm) = anorm) THEN GOTO Lbl1
END;
1:
Lbl1:
// c := 0.0;
s := 1.0;
FOR i := l to k DO BEGIN
@ -315,7 +317,7 @@ BEGIN
END
END
END;
2: z := w[k,k];
Lbl2: z := w[k,k];
IF (l = k) THEN BEGIN
IF (z < 0.0) THEN BEGIN
w[k,k] := -z;
@ -323,7 +325,7 @@ BEGIN
v[j,k] := -v[j,k]
END
END;
GOTO 3
GOTO Lbl3
END;
IF (its = 30) THEN BEGIN
{ showmessage('No convergence in 30 SVDCMP iterations');}
@ -379,7 +381,8 @@ BEGIN
rv1[k] := f;
w[k,k] := x
END;
3: END;
Lbl3:
END;
{ mat_print(m,a,'U matrix');
mat_print(n,v,'V matrix');
writeln(lst,'Diagonal values of W inverse matrix');
@ -423,12 +426,6 @@ BEGIN
END;
//-------------------------------------------------------------------
FUNCTION max(a,b: double): double;
BEGIN
IF (a > b) THEN max := a ELSE max := b
END;
//-------------------------------------------------------------------
function inversez(prob : double) : double;
var
z, p : double;
@ -522,16 +519,15 @@ begin
until abs(integral - lastint) < error;
simpsonintegral := integral/3
end; (* of SimpsonIntegral *)
//---------------------------------------------------------------------
{ Density function of the standard normal distribution }
function zdensity(z : real) : real;
(* the density function of the standard normal distribution *)
const a = 0.39894228; (* 1 / sqrt(2*pi) *)
const
a = 0.39894228; (* 1 / sqrt(2*pi) *)
begin
Result := a * exp(-0.5 * z*z )
end; (* of normal *)
//----------------------------------------------------------------------
function probf(f,df1,df2 : extended) : extended;
@ -572,8 +568,7 @@ BEGIN
END;
//-----------------------------------------------------------------
FUNCTION betacf(a,b,x: double): extended;
LABEL 1;
function betacf(a,b,x: double): extended;
CONST
itmax=100;
eps=3.0e-7;
@ -582,7 +577,6 @@ VAR
bz,bpp,bp,bm,az,app: extended;
am,aold,ap: extended;
m: integer;
BEGIN
am := 1.0;
bm := 1.0;
@ -611,10 +605,11 @@ BEGIN
bm := bp/bpp;
az := app/bpp;
bz := 1.0;
IF ((abs(az-aold)) < (eps*abs(az))) THEN GOTO 1
IF ((abs(az-aold)) < (eps*abs(az))) THEN
Break;
END;
{ ShowMessage('WARNING! a or b too big, or itmax too small in betacf');}
1: betacf := az
Result := az
END;
FUNCTION betai(a,b,x: extended): extended;
@ -648,72 +643,75 @@ begin { fprob function }
end; // of fprob function
//--------------------------------------------------------------------
FUNCTION alnorm(x : double; upper : boolean): double;
// Algorithm AS66 Applied Statistics (1973) vol.22, 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.
// ELF90-compatible version by Alan Miller
// Latest revision - 29 November 1997
{ Algorithm AS66 Applied Statistics (1973) vol.22, no.3
label L10, L20, L30, L40;
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.
ELF90-compatible version by Alan Miller
Latest revision - 29 November 1997 }
function alnorm(x: double; upper: boolean): double;
label
Lbl20, Lbl30, Lbl40;
const
zero = 0.0;
one = 1.0;
half = 0.5;
con = 1.28;
ltone = 7.0;
utzero = 18.66;
p = 0.398942280444;
q = 0.39990348504;
r = 0.398942280385;
a1 = 5.75885480458;
a2 = 2.62433121679;
a3 = 5.92885724438;
b1 = -29.8213557807;
b2 = 48.6959930692;
c1 = -3.8052E-8;
c2 = 3.98064794E-4;
c3 = -0.151679116635;
c4 = 4.8385912808;
c5 = 0.742380924027;
c6 = 3.99019417011;
d1 = 1.00000615302;
d2 = 1.98615381364;
d3 = 5.29330324926;
d4 = -15.1508972451;
d5 = 30.789933034;
var
fn_val : double;
// sp : integer;
zero, one, half, con : double;
z, y : double;
up : boolean;
ltone, utzero : double;
p, q, r, a1, a2, a3, b1, b2, c1, c2, c3, c4, c5, c6 : double;
d1, d2, d3, d4, d5 : double;
fn_val: double;
z, y: double;
up: boolean;
begin
zero := 0.0;
one := 1.0;
half := 0.5;
con := 1.28;
ltone := 7.0;
utzero := 18.66;
p := 0.398942280444;
q := 0.39990348504;
r := 0.398942280385;
a1 := 5.75885480458;
a2 := 2.62433121679;
a3 := 5.92885724438;
b1 := -29.8213557807;
b2 := 48.6959930692;
c1 := -3.8052E-8;
c2 := 3.98064794E-4;
c3 := -0.151679116635;
c4 := 4.8385912808;
c5 := 0.742380924027;
c6 := 3.99019417011;
d1 := 1.00000615302;
d2 := 1.98615381364;
d3 := 5.29330324926;
d4 := -15.1508972451;
d5 := 30.789933034;
up := upper;
z := x;
IF(z >= zero) then GOTO L10;
up := NOT up;
z := -z;
L10 :
IF ((z <= ltone) OR (up) AND (z <= utzero)) then GOTO L20;
fn_val := zero;
GOTO L40;
L20 :
up := upper;
z := x;
if (z < zero) then begin
up := not up;
z := -z;
end;
if ((z <= ltone) or (up) and (z <= utzero)) then GOTO Lbl20;
fn_val := zero;
GOTO Lbl40;
Lbl20 :
y := half*z*z;
IF(z > con) then GOTO L30;
if (z > con) then GOTO Lbl30;
fn_val := half - z*(p-q*y/(y+a1+b1/(y+a2+b2/(y+a3))));
GOTO L40;
L30 :
fn_val := r*EXP(-y)/(z+c1+d1/(z+c2+d2/(z+c3+d3/(z+c4+d4/(z+c5+d5/(z+c6))))));
L40 :
IF(NOT up) then fn_val := one - fn_val;
fn_val := half - z*(p-q*y/(y+a1+b1/(y+a2+b2/(y+a3))));
GOTO Lbl40;
result := fn_val;
Lbl30 :
fn_val := r*exp(-y)/(z+c1+d1/(z+c2+d2/(z+c3+d3/(z+c4+d4/(z+c5+d5/(z+c6))))));
Lbl40 :
if (not up) then
fn_val := one - fn_val;
result := fn_val;
END; // FUNCTION alnorm
//-----------------------------------------------------------------------------------
@ -788,41 +786,40 @@ begin
exit;
end; // if
end; // procedure ppnd7
//---------------------------------------------------------------------
FUNCTION poly(c : Array of double; nord : integer; x : double): double; // RESULT(fn_val)
// Algorithm AS 181.2 Appl. Statist. (1982) Vol. 31, No. 2
// Calculates the algebraic polynomial of order nored-1 with
// array of coefficients c. Zero order coefficient is c(1)
label 20;
{ Algorithm AS 181.2 Appl. Statist. (1982) Vol. 31, No. 2
Calculates the algebraic polynomial of order nored-1 with
array of coefficients c. Zero order coefficient is c(1) }
function poly(const c: Array of double; nord: integer; x: double): double;
var
fn_val, p : double;
i, j, n2 : integer;
c2 : array[1..6] of double;
fn_val, p: double;
i, j, n2: integer;
c2: array[1..6] of double;
begin
// copy into array for access starting at 1 instead of zero
for i := 1 to nord do c2[i] := c[i-1];
// copy into array for access starting at 1 instead of zero
for i := 1 to nord do
c2[i] := c[i-1];
fn_val := c2[1];
IF (nord = 1) then
fn_val := c2[1];
if (nord = 1) then
begin
result := fn_val;
exit;
end;
p := x * c2[nord];
if (nord <> 2) then
begin
n2 := nord - 2;
j := n2 + 1;
for i := 1 to n2 do
begin
result := fn_val;
exit; // RETURN
p := (p + c2[j])*x;
j := j - 1;
end;
p := x * c2[nord];
IF (nord = 2) then GOTO 20;
n2 := nord - 2;
j := n2 + 1;
for i := 1 to n2 do
begin
p := (p + c2[j])*x;
j := j - 1;
END; // DO
20: fn_val := fn_val + p;
result := fn_val;
END; // FUNCTION poly
//-----------------------------------------------------------------------
end;
Result := fn_val + p;
end; // FUNCTION poly
procedure swilk (var init: boolean; const x: DblDyneVec; n, n1, n2: integer;
const a: DblDyneVec; var w, pw: double; out ifault: integer);
@ -1598,7 +1595,7 @@ begin
end;
//--------------------------------------------------------------------
procedure PRank(v1col: integer; var Values: DblDyneVec);
procedure PRank(v1col: integer; var Values: DblDyneVec; AReport: TStrings);
// computes the percentile ranks of values stored in the data grid
// at column v1col
var
@ -1668,13 +1665,13 @@ begin
pcntiles[i] := cumfm[i] / ncases;
end;
OutPutFrm.AddLine('PERCENTILE RANKS');
OutPutFrm.AddLine('Score Value Frequency Cum.Freq. Percentile Rank');
OutPutFrm.AddLine('----------- --------- --------- ---------------');
// OutPutFrm.AddLine('___________ __________ __________ ______________');
AReport.Add('PERCENTILE RANKS');
AReport.Add('Score Value Frequency Cum.Freq. Percentile Rank');
AReport.Add('----------- --------- --------- ---------------');
// AReport.Add('___________ __________ __________ ______________');
for i := 1 to nocats do
OutputFrm.AddLine(' %10.3f %8d %8d %12.2f%%', [CatValues[i-1], freq[i-1], cumf[i-1], pcntiles[i-1]*100.0]);
OutPutFrm.AddLine('');
AReport.Add(' %10.3f %8d %8d %12.2f%%', [CatValues[i-1], freq[i-1], cumf[i-1], pcntiles[i-1]*100.0]);
AReport.Add('');
// convert original values to their corresponding percentile ranks
for i := 1 to ncases do
@ -1911,19 +1908,18 @@ begin
result := p;
end;
function KolmogorovTest(na : integer; VAR a : DblDyneVec; nb : integer;
VAR b : DblDyneVec; option : String) : double;
function KolmogorovTest(na : integer; const a: DblDyneVec; nb: integer;
const b: DblDyneVec; option: String; AReport: TStrings): double;
VAR
prob : double;
opt : string;
rna : double; // = na;
rnb : double; // = nb;
sa : double; // = 1./rna;
sb : double; // = 1./rnb;
sa : double; // = 1./rna;
sb : double; // = 1./rnb;
rdiff, rdmax, x, z : double;
i, ia, ib : integer;
ok : boolean;
bugstr : string;
begin
// Statistical test whether two one-dimensional sets of points are compatible
// with coming from the same parent distribution, using the Kolmogorov test.
@ -1937,20 +1933,21 @@ begin
// "M" Return the Maximum Kolmogorov distance instead of prob
//
// Output:
// The returned value prob is a calculated confidence level which gives a
// statistical test for compatibility of a and b.
// Values of prob close to zero are taken as indicating a small probability
// of compatibility. For two point sets drawn randomly from the same parent
// distribution, the value of prob should be uniformly distributed between
// zero and one.
// in case of error the function return -1
// If the 2 sets have a different number of points, the minimum of
// the two sets is used.
// The returned value prob is a calculated confidence level which gives a
// statistical test for compatibility of a and b.
// Values of prob close to zero are taken as indicating a small probability
// of compatibility. For two point sets drawn randomly from the same parent
// distribution, the value of prob should be uniformly distributed between
// zero and one.
//
// Method:
// The Kolmogorov test is used. The test statistic is the maximum deviation
// between the two integrated distribution functions, multiplied by the
// normalizing factor (rdmax*sqrt(na*nb/(na+nb)).
// in case of error the function return -1
// If the 2 sets have a different number of points, the minimum of
// the two sets is used.
//
// Method:
// The Kolmogorov test is used. The test statistic is the maximum deviation
// between the two integrated distribution functions, multiplied by the
// normalizing factor (rdmax*sqrt(na*nb/(na+nb)).
//
// Code adapted by Rene Brun from CERNLIB routine TKOLMO (Fred James)
// (W.T. Eadie, D. Drijard, F.E. James, M. Roos and B. Sadoulet,
@ -2066,14 +2063,14 @@ begin
z := rdmax * Sqrt(rna * rnb / (rna + rnb));
prob := KolmogorovProb(z);
end;
// debug printout
if (opt = 'D') then
begin
bugstr := format(' Kolmogorov Probability = %g, Max Dist = %g',[prob,rdmax]);
OutPutFrm.RichEdit.Lines.Add(bugstr);
end;
if(opt = 'M') then result := rdmax
else result := prob;
AReport.Add(' Kolmogorov Probability: %g, Max Dist: %g', [prob, rdmax]);
if(opt = 'M') then
result := rdmax
else
result := prob;
end;
@ -2411,10 +2408,5 @@ begin
// pdf := exp ( - a ) * power(a,x) / exp(logfactorial( x ));
end;
function DegToRad(Deg: Double): Double;
begin
Result := Deg * Pi / 180.0;
end;
end.