LazStats: Show cumulative probabilities in DistribUnit

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7639 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2020-08-28 21:58:45 +00:00
parent 74d1082ccb
commit e65cc723d5
5 changed files with 340 additions and 129 deletions

View File

@ -1429,6 +1429,11 @@
<DebugInfoType Value="dsDwarf2"/>
</Debugging>
<LinkSmart Value="True"/>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>

View File

@ -2,12 +2,12 @@ object DistribFrm: TDistribFrm
Left = 420
Height = 432
Top = 215
Width = 687
Width = 701
HelpType = htKeyword
HelpKeyword = 'html/DistributionPlotsandCriticalValu.htm'
Caption = 'Distributions'
ClientHeight = 432
ClientWidth = 687
ClientWidth = 701
OnActivate = FormActivate
OnShow = FormShow
Position = poMainFormCenter
@ -19,7 +19,7 @@ object DistribFrm: TDistribFrm
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 624
Left = 638
Height = 25
Top = 401
Width = 55
@ -35,7 +35,7 @@ object DistribFrm: TDistribFrm
object ComputeBtn: TButton
AnchorSideTop.Control = CloseBtn
AnchorSideRight.Control = CloseBtn
Left = 540
Left = 554
Height = 25
Top = 401
Width = 76
@ -50,7 +50,7 @@ object DistribFrm: TDistribFrm
object ResetBtn: TButton
AnchorSideTop.Control = CloseBtn
AnchorSideRight.Control = ComputeBtn
Left = 478
Left = 492
Height = 25
Top = 401
Width = 54
@ -72,7 +72,7 @@ object DistribFrm: TDistribFrm
Left = 0
Height = 8
Top = 385
Width = 687
Width = 701
Anchors = [akLeft, akRight, akBottom]
Shape = bsBottomLine
end
@ -84,7 +84,7 @@ object DistribFrm: TDistribFrm
Left = 8
Height = 377
Top = 8
Width = 479
Width = 454
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Left = 8
BorderSpacing.Top = 8
@ -92,7 +92,7 @@ object DistribFrm: TDistribFrm
BevelOuter = bvNone
BorderStyle = bsSingle
ClientHeight = 373
ClientWidth = 475
ClientWidth = 450
Color = clWhite
ParentColor = False
TabOrder = 3
@ -100,7 +100,7 @@ object DistribFrm: TDistribFrm
Left = 6
Height = 361
Top = 6
Width = 463
Width = 438
AxisList = <
item
Grid.Color = clSilver
@ -146,6 +146,12 @@ object DistribFrm: TDistribFrm
end
object VertLineSeries: TLineSeries
Active = False
LinePen.Color = clRed
LinePen.Style = psDot
end
object HorLineSeries: TLineSeries
LinePen.Color = clRed
LinePen.Style = psDot
end
end
end
@ -181,42 +187,42 @@ object DistribFrm: TDistribFrm
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = Bevel1
Left = 499
Left = 474
Height = 377
Top = 8
Width = 180
Width = 219
Anchors = [akTop, akRight, akBottom]
AutoSize = True
BorderSpacing.Top = 8
BorderSpacing.Right = 8
BevelOuter = bvNone
ClientHeight = 377
ClientWidth = 180
ClientWidth = 219
TabOrder = 6
object GroupBox1: TGroupBox
AnchorSideLeft.Control = ParameterPanel
AnchorSideTop.Control = ParameterPanel
AnchorSideRight.Side = asrBottom
Left = 0
Height = 136
Height = 175
Top = 0
Width = 180
Width = 219
AutoSize = True
Caption = 'Plot Distribution:'
Caption = 'Plot Distribution'
ChildSizing.LeftRightSpacing = 16
ChildSizing.TopBottomSpacing = 8
ChildSizing.VerticalSpacing = 8
ChildSizing.EnlargeVertical = crsHomogenousSpaceResize
ChildSizing.EnlargeVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 116
ClientWidth = 176
ClientHeight = 155
ClientWidth = 215
TabOrder = 0
object NDChk: TRadioButton
Left = 16
Height = 19
Top = 8
Width = 144
Width = 183
Caption = 'Normal Distribution'
OnClick = DistributionClick
TabOrder = 0
@ -225,8 +231,8 @@ object DistribFrm: TDistribFrm
Left = 16
Height = 19
Top = 35
Width = 144
Caption = 'Student t Distribution'
Width = 183
Caption = 'Student t Distribution (1-sided)'
OnClick = DistributionClick
TabOrder = 3
end
@ -234,7 +240,7 @@ object DistribFrm: TDistribFrm
Left = 16
Height = 19
Top = 62
Width = 144
Width = 183
Caption = 'Central F Distribution'
OnClick = DistributionClick
TabOrder = 2
@ -243,11 +249,28 @@ object DistribFrm: TDistribFrm
Left = 16
Height = 19
Top = 89
Width = 144
Width = 183
Caption = 'Chi-Square Distribution'
OnClick = DistributionClick
TabOrder = 1
end
object Bevel2: TBevel
Left = 16
Height = 4
Top = 116
Width = 183
Constraints.MaxHeight = 4
Shape = bsBottomLine
end
object CumulativeChk: TCheckBox
Left = 16
Height = 19
Top = 128
Width = 183
Caption = 'Cumulative'
OnChange = CumulativeChkChange
TabOrder = 4
end
end
object GroupBox2: TGroupBox
AnchorSideLeft.Control = GroupBox1
@ -256,21 +279,22 @@ object DistribFrm: TDistribFrm
AnchorSideRight.Control = GroupBox1
AnchorSideRight.Side = asrBottom
Left = 0
Height = 140
Top = 152
Width = 180
Height = 107
Top = 191
Width = 219
Anchors = [akTop, akLeft, akRight]
AutoSize = True
BorderSpacing.Top = 16
BorderSpacing.Bottom = 12
Caption = 'Parameters'
ClientHeight = 120
ClientWidth = 176
ClientHeight = 87
ClientWidth = 215
TabOrder = 1
object AlphaLabel: TLabel
AnchorSideTop.Control = AlphaEdit
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = AlphaEdit
Left = 29
Left = 68
Height = 15
Top = 6
Width = 84
@ -283,7 +307,7 @@ object DistribFrm: TDistribFrm
AnchorSideTop.Control = DF1Edit
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = DF1Edit
Left = 22
Left = 61
Height = 15
Top = 33
Width = 91
@ -297,7 +321,7 @@ object DistribFrm: TDistribFrm
AnchorSideTop.Control = DF2Edit
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = DF2Edit
Left = 22
Left = 61
Height = 15
Top = 60
Width = 91
@ -307,25 +331,11 @@ object DistribFrm: TDistribFrm
Caption = 'Deg. Freedom (2)'
ParentColor = False
end
object MeanLabel: TLabel
AnchorSideTop.Control = MeanEdit
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = MeanEdit
Left = 83
Height = 15
Top = 93
Width = 30
Anchors = [akTop, akRight]
BorderSpacing.Right = 8
Caption = 'Mean'
ParentColor = False
Visible = False
end
object AlphaEdit: TEdit
AnchorSideTop.Control = GroupBox2
AnchorSideRight.Control = GroupBox2
AnchorSideRight.Side = asrBottom
Left = 121
Left = 160
Height = 23
Top = 2
Width = 43
@ -341,7 +351,7 @@ object DistribFrm: TDistribFrm
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = AlphaEdit
AnchorSideRight.Side = asrBottom
Left = 121
Left = 160
Height = 23
Top = 29
Width = 43
@ -351,40 +361,36 @@ object DistribFrm: TDistribFrm
TabOrder = 1
Text = 'DF1Edit'
end
object MeanEdit: TEdit
AnchorSideTop.Control = DF2Edit
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = AlphaEdit
AnchorSideRight.Side = asrBottom
Left = 121
Height = 23
Top = 89
Width = 43
Alignment = taRightJustify
Anchors = [akTop, akRight]
BorderSpacing.Top = 4
BorderSpacing.Bottom = 8
TabOrder = 3
Text = 'MeanEdit'
Visible = False
end
object DF2Edit: TEdit
AnchorSideTop.Control = DF1Edit
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = AlphaEdit
AnchorSideRight.Side = asrBottom
Left = 121
Left = 160
Height = 23
Top = 56
Width = 43
Alignment = taRightJustify
Anchors = [akTop, akRight]
BorderSpacing.Top = 4
BorderSpacing.Bottom = 10
BorderSpacing.Bottom = 8
TabOrder = 2
Text = 'DF2Edit'
end
end
object ShowCriticalValuesChk: TCheckBox
AnchorSideLeft.Control = ParameterPanel
AnchorSideTop.Control = GroupBox2
AnchorSideTop.Side = asrBottom
Left = 0
Height = 19
Top = 310
Width = 123
Caption = 'Show critical values'
Checked = True
State = cbChecked
TabOrder = 2
end
end
object SavePictureDialog: TSavePictureDialog
Filter = 'Graphic (*.png;*.bmp;*.jpeg;*.jpg;*.jpe;*.jfif;*.svg)|*.png;*.bmp;*.jpeg;*.jpg;*.jpe;*.jfif;*.svg|Portable Network Graphic (*.png)|*.png|Bitmaps (*.bmp)|*.bmp|Joint Picture Expert Group (*.jpeg;*.jpg;*.jpe;*.jfif)|*.jpeg;*.jpg;*.jpe;*.jfif|Scaleable Vector Graphic (*.svg)|*.svg|All Files (*.*)|*.*'

View File

@ -23,7 +23,11 @@ type
TDistribFrm = class(TForm)
AlphaEdit: TEdit;
Bevel1: TBevel;
Bevel2: TBevel;
ShowCriticalValuesChk: TCheckBox;
HorLineSeries: TLineSeries;
ChartToolset: TChartToolset;
CumulativeChk: TCheckBox;
PanDragTool: TPanDragTool;
tChk: TRadioButton;
ZoomDragTool: TZoomDragTool;
@ -39,7 +43,6 @@ type
DF1Edit: TEdit;
DF2Edit: TEdit;
FChk: TRadioButton;
MeanEdit: TEdit;
NDChk: TRadioButton;
ChartPanel: TPanel;
ResetBtn: TButton;
@ -49,15 +52,19 @@ type
AlphaLabel: TLabel;
DF1Label: TLabel;
DF2Label: TLabel;
MeanLabel: TLabel;
GroupBox1: TGroupBox;
procedure ComputeBtnClick(Sender: TObject);
procedure CumulativeChkChange(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure CalcChiSq(const AX: Double; out AY: Double);
procedure CalcChi2(const AX: Double; out AY: Double);
procedure CalcChi2_Cumulative(const AX: Double; out AY: Double);
procedure CalcF(const AX: Double; out AY: Double);
procedure CalcF_Cumulative(const AX: Double; out AY: Double);
procedure CalcND(const AX: Double; out AY: Double);
procedure Calct(const AX: Double; out AY: Double);
procedure CalcND_Cumulative(const AX: Double; out AY: Double);
procedure CalcT(const AX: Double; out AY: Double);
procedure CalcT_Cumulative(const AX: Double; out AY: Double);
procedure DistributionClick(Sender: TObject);
procedure PrintBtnClick(Sender: TObject);
procedure ResetBtnClick(Sender: TObject);
@ -67,7 +74,7 @@ type
DF1: Integer;
DF2: Integer;
procedure NormalDistPlot;
procedure ChiPlot;
procedure Chi2Plot;
procedure FPlot;
procedure tPlot;
@ -97,7 +104,6 @@ begin
AlphaEdit.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL);
DF1Edit.Text := '';
DF2Edit.Text := '';
MeanEdit.Text := '';
GroupBox2.Enabled := false;
FuncSeries.OnCalculate := nil;
VertLineSeries.Active := false;
@ -105,6 +111,7 @@ begin
Chart.BottomAxis.Title.Caption := 'Scale';
end;
procedure TDistribFrm.SaveBtnClick(Sender: TObject);
var
ext: String;
@ -121,31 +128,67 @@ begin
end;
end;
procedure TDistribFrm.FormShow(Sender: TObject);
begin
ResetBtnClick(self);
end;
procedure TDistribFrm.CalcF(const AX: Double; out AY: Double);
begin
AY := FDensity(AX, DF1, DF2);
end;
procedure TDistribFrm.CalcF_Cumulative(const AX: Double; out AY: Double);
begin
AY := 1.0 - ProbF(AX, DF1, DF2);
end;
procedure TDistribFrm.CalcND(const AX: Double; out AY: Double);
begin
AY := 1.0 / sqrt(TWO_PI) * exp(-sqr(AX)/ 2.0);
end;
procedure TDistribFrm.CalcChiSq(const AX: Double; out AY: Double);
procedure TDistribFrm.CalcND_Cumulative(const AX: Double; out AY: Double);
begin
// AY := ProbZ(AX); -- very slow
AY := NormalDist(AX); // borrowed from NumLib
end;
procedure TDistribFrm.CalcChi2(const AX: Double; out AY: Double);
begin
AY := Chi2Density(AX, DF1);
end;
procedure TDistribFrm.CalcChi2_Cumulative(const AX: Double; out AY: Double);
begin
AY := ChiSquaredProb(AX, DF1);
end;
procedure TDistribFrm.Calct(const AX: Double; out AY: Double);
begin
AY := tDensity(AX, DF1);
end;
procedure TDistribFrm.CalcT_Cumulative(const AX: Double; out AY: Double);
const
ONE_SIDED = true;
begin
if AX < 0 then
AY := tDist(-AX, DF1, ONE_SIDED)
else
AY := 1.0 - tDist(AX, DF1, ONE_SIDED);
end;
procedure TDistribFrm.DistributionClick(Sender: TObject);
var
rb: TRadiobutton;
@ -162,28 +205,9 @@ begin
DF2Edit.Enabled := (rb = FChk) and rb.Checked;
DF2Label.Enabled := DF2Edit.Enabled;
MeanEdit.Enabled := false;
MeanLabel.Enabled := false;
{
if NDChk.Checked then
begin
GroupBox2.Enabled := true;
AlphaLabel.Enabled := true;
AlphaEdit.Enabled := true;
DF1Edit.Enabled := false;
DF1Label.Enabled := false;
DF2Label.Enabled := false;
MeanLabel.Enabled := false;
DF2Edit.Enabled := false;
MeanEdit.Enabled := false;
end
else
GroupBox2.Enabled := false;
}
end;
procedure TDistribFrm.PrintBtnClick(Sender: TObject);
const
MARGIN = 10;
@ -212,6 +236,7 @@ begin
end;
end;
procedure TDistribFrm.ComputeBtnClick(Sender: TObject);
var
msg: String;
@ -240,7 +265,7 @@ begin
if ChiChk.Checked then
begin
ChiPlot();
Chi2Plot();
ok := true;
end;
@ -254,13 +279,23 @@ begin
MessageDlg('Please select a distribution.', mtError, [mbOK], 0);
end;
procedure TDistribFrm.CumulativeChkChange(Sender: TObject);
begin
if CumulativeChk.Checked then
Chart.LeftAxis.Title.Caption := 'Cumulative probability'
else
Chart.LeftAxis.Title.Caption := 'Probability density';
end;
procedure TDistribFrm.NormalDistPlot;
var
alpha: Double;
zMax, zCrit, pCrit: Double;
zMax, zMin, zCrit, pCrit: Double;
begin
alpha := StrToFloat(AlphaEdit.Text);
zMax := InverseZ(0.9999);
zMin := -zMax;
zCrit := inversez(1.0 - alpha);
CalcND(zCrit, pCrit);
@ -270,28 +305,44 @@ begin
Chart.Title.Text.Add(Format('Critical value = %.3f', [zCrit]));
Chart.Title.Visible := true;
Chart.BottomAxis.Title.Caption := 'z';
FuncSeries.Extent.XMin := -zMax;
FuncSeries.Extent.XMax := +zMax;
FuncSeries.Extent.XMin := zMin;
FuncSeries.Extent.XMax := zMax;
FuncSeries.Extent.UseXMin := true;
FuncSeries.Extent.UseXMax := true;
FuncSeries.OnCalculate := @CalcND;
if CumulativeChk.Checked then
FuncSeries.OnCalculate := @CalcND_Cumulative
else
FuncSeries.OnCalculate := @CalcND;
FuncSeries.DomainExclusions.Clear;
VertLineSeries.Clear;
VertLineSeries.AddXY(zCrit, 0);
VertLineSeries.AddXY(zCrit, pCrit);
VertLineSeries.Active := true;
VertlineSeries.Clear;
if CumulativeChk.Checked then
begin
HorLineSeries.Clear;
HorLineSeries.AddXY(zMin, 1.0 - alpha);
HorLineSeries.AddXY(zCrit, 1.0 - alpha);
VertlineSeries.AddXY(zCrit, 1.0 - alpha);
VertLineSeries.AddXY(zCrit, 0);
end else
begin
VertLineSeries.AddXY(zCrit, 0);
VertLineSeries.AddXY(zCrit, pCrit);
end;
HorLineSeries.Active := ShowCriticalValuesChk.Checked and CumulativeChk.Checked;
VertLineSeries.Active := ShowCriticalValuesChk.Checked;
end;
procedure TDistribFrm.ChiPlot;
procedure TDistribFrm.Chi2Plot;
var
alpha: Double;
Chi2Max, Chi2Crit, pCrit: Double;
chi2Max, chi2Crit, pCrit: Double;
begin
alpha := StrToFloat(AlphaEdit.Text);
DF1 := StrToInt(DF1Edit.Text);
Chi2Max := InverseChi(0.9999, DF1);
Chi2Crit := InverseChi(1.0 - alpha, DF1);
CalcChiSq(Chi2Crit, pCrit);
chi2Max := InverseChi(0.9999, DF1);
chi2Crit := InverseChi(1.0 - alpha, DF1);
CalcChi2(chi2Crit, pCrit);
Chart.Title.Text.Clear;
Chart.Title.Text.Add('<b>Chi-Squared Distribution</b>');
@ -300,17 +351,32 @@ begin
Chart.Title.Visible := true;
Chart.BottomAxis.Title.Caption := '&chi;<sup>2</sup>';
FuncSeries.Extent.XMin := 0;
FuncSeries.Extent.XMax := Chi2Max;
FuncSeries.Extent.XMax := chi2Max;
FuncSeries.Extent.UseXMin := true;
FuncSeries.Extent.UseXMax := true;
FuncSeries.OnCalculate := @CalcChiSq;
if CumulativeChk.Checked then
FuncSeries.OnCalculate := @CalcChi2_Cumulative
else
FuncSeries.OnCalculate := @CalcChi2;
FuncSeries.DomainExclusions.AddRange(-Infinity, 0, [ioOpenEnd]);
VertLineSeries.Clear;
VertLineSeries.AddXY(Chi2Crit, 0);
VertLineSeries.AddXY(Chi2Crit, pCrit);
VertLineSeries.Active := true;
if CumulativeChk.Checked then begin
HorLineSeries.Clear;
HorLineSeries.AddXY(0, 1.0 - alpha);
HorLineSeries.AddXY(chi2Crit, 1.0 - alpha);
VertlineSeries.AddXY(chi2Crit, 1.0 - alpha);
VertLineSeries.AddXY(chi2Crit, 0);
end else
begin
VertLineSeries.AddXY(chi2Crit, 0);
VertLineSeries.AddXY(chi2Crit, pCrit);
end;
HorLineSeries.Active := ShowCriticalValuesChk.Checked and CumulativeChk.Checked;
VertLineSeries.Active := ShowCriticalValuesChk.Checked;
end;
procedure TDistribFrm.FPlot;
var
alpha: Double;
@ -333,22 +399,39 @@ begin
FuncSeries.Extent.XMax := FMax;
FuncSeries.Extent.UseXMin := true;
FuncSeries.Extent.UseXMax := true;
FuncSeries.OnCalculate := @CalcF;
if CumulativeChk.Checked then
FuncSeries.OnCalculate := @CalcF_Cumulative
else
FuncSeries.OnCalculate := @CalcF;
FuncSeries.DomainExclusions.AddRange(-Infinity, 0, [ioOpenEnd]);
VertLineSeries.Clear;
VertLineSeries.AddXY(FCrit, 0);
VertLineSeries.AddXY(FCrit, pCrit);
VertLineSeries.Active := true;
if CumulativeChk.Checked then
begin
HorLineSeries.Clear;
HorLineSeries.AddXY(0, 1.0 - alpha);
HorLineSeries.AddXY(FCrit, 1.0 - alpha);
VertLineSeries.AddXY(FCrit, 1.0 - alpha);
VertLineSeries.AddXY(FCrit, 0);
end else
begin
VertLineSeries.AddXY(FCrit, 0);
VertLineSeries.AddXY(FCrit, pCrit);
end;
HorLineSeries.Active := ShowCriticalValuesChk.Checked and CumulativeChk.Checked;
VertLineSeries.Active := ShowCriticalValuesChk.Checked;
end;
procedure TDistribFrm.tPlot;
var
alpha: Double;
tMax, tCrit, pCrit: Double;
tMin, tMax, tCrit, pCrit: Double;
begin
alpha := StrToFloat(AlphaEdit.Text);
DF1 := StrToInt(DF1Edit.Text);
tMax := Inverset(0.9999, DF1);
tMin := -tMax;
tCrit := Inverset(1.0 - alpha, DF1);
Calct(tCrit, pCrit);
@ -358,18 +441,34 @@ begin
Chart.Title.Text.Add(Format('Critical value = %.3f', [tCrit]));
Chart.Title.Visible := true;
Chart.BottomAxis.Title.Caption := 't';
FuncSeries.Extent.XMin := -tmax;
FuncSeries.Extent.XMin := tMin;
FuncSeries.Extent.XMax := tMax;
FuncSeries.Extent.UseXMin := true;
FuncSeries.Extent.UseXMax := true;
FuncSeries.OnCalculate := @Calct;
if CumulativeChk.Checked then
FuncSeries.OnCalculate := @CalcT_Cumulative
else
FuncSeries.OnCalculate := @CalcT;
FuncSeries.DomainExclusions.Clear;
VertLineSeries.Clear;
VertLineSeries.AddXY(tCrit, 0);
VertLineSeries.AddXY(tCrit, pCrit);
VertLineSeries.Active := true;
if CumulativeChk.Checked then
begin
HorLineSeries.Clear;
HorLineSeries.AddXY(tMin, 1.0 - alpha);
HorLineSeries.AddXY(tCrit, 1.0 - alpha);
VertLineSeries.AddXY(tCrit, 1.0 - alpha);
VertLineSeries.AddXY(tCrit, 0);
end else
begin
VertLineSeries.AddXY(tCrit, 0);
VertLineSeries.AddXY(tCrit, pCrit);
end;
HorLineSeries.Active := ShowCriticalValuesChk.Checked and CumulativeChk.Checked;
VertLineSeries.Active := ShowCriticalValuesChk.Checked;
end;
procedure TDistribFrm.FormActivate(Sender: TObject);
var
w: Integer;

View File

@ -980,16 +980,15 @@ begin
end;
//-------------------------------------------------------------------
function probt(t,df1 : double) : double;
// Returns the probability corresponding to a two-tailed t test.
function ProbT(t, df1: double): double;
var
F, prob : double;
F, prob: double;
begin
// Returns the probability corresponding to a two-tailed t test.
F := t * t;
prob := probf(F,1.0,df1);
Result := prob;
F := t * t;
prob := ProbF(F, 1.0, df1);
Result := prob;
end;
//------------------------------------------------------------------------
function inverset(Probt, DF : double) : double;
var

View File

@ -9,6 +9,10 @@ interface
uses
Classes, SysUtils;
function erf(x: Double): Double;
function erfc(x: Double) : Double;
function NormalDist(x: Double): Double;
function Beta(a, b: Double): Extended;
function BetaI(a,b,x: Double): Extended;
@ -26,6 +30,104 @@ implementation
uses
Math;
// Calculates the error function
// /x
// erf(x) = 2/sqrt(pi) * | exp(-) 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;
function Beta(a, b: Double): Extended;
begin
if (a > 0) and (b > 0) then