You've already forked lazarus-ccr
2339 lines
66 KiB
ObjectPascal
2339 lines
66 KiB
ObjectPascal
![]() |
// Upgraded to Delphi 2009: Sebastian Zierer
|
||
|
|
||
|
(* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Version: MPL 1.1
|
||
|
*
|
||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
|
* the License. You may obtain a copy of the License at
|
||
|
* http://www.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* License.
|
||
|
*
|
||
|
* The Original Code is TurboPower SysTools
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is
|
||
|
* TurboPower Software
|
||
|
*
|
||
|
* Portions created by the Initial Developer are Copyright (C) 1996-2002
|
||
|
* the Initial Developer. All Rights Reserved.
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
*
|
||
|
* ***** END LICENSE BLOCK ***** *)
|
||
|
|
||
|
{*********************************************************}
|
||
|
{* SysTools: StStat.pas 4.04 *}
|
||
|
{*********************************************************}
|
||
|
{* SysTools: Statistical math functions modeled on *}
|
||
|
{* those in Excel *}
|
||
|
{*********************************************************}
|
||
|
|
||
|
{$IFDEF FPC}
|
||
|
{$mode DELPHI}
|
||
|
{$ENDIF}
|
||
|
|
||
|
//{$I StDefine.inc}
|
||
|
|
||
|
unit StStat;
|
||
|
|
||
|
{ The statistical distribution functions return results in singles }
|
||
|
{ since the fractional accuracy of these is typically about 3e-7. }
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
Windows,
|
||
|
{$IFDEF UseMathUnit}
|
||
|
Math,
|
||
|
{$ELSE}
|
||
|
StMath,
|
||
|
{$ENDIF}
|
||
|
SysUtils, StConst, StBase;
|
||
|
|
||
|
{AVEDEV}
|
||
|
function AveDev(const Data: array of Double) : Double;
|
||
|
function AveDev16(const Data; NData : Integer) : Double;
|
||
|
{-Returns the average of the absolute deviations of data points from their
|
||
|
mean. AveDev is a measure of the variability in a data set.
|
||
|
}
|
||
|
|
||
|
{CONFIDENCE}
|
||
|
function Confidence(Alpha, StandardDev : Double; Size : LongInt) : Double;
|
||
|
{-Returns the confidence interval for a population mean.
|
||
|
The confidence interval is a range on either side of a sample mean.
|
||
|
Alpha is the significance level used to compute the confidence level.
|
||
|
The confidence level equals 100*(1 - Alpha)%, or in other words,
|
||
|
an Alpha of 0.05 indicates a 95 percent confidence level.
|
||
|
StandardDev is the population standard deviation for the data range
|
||
|
and is assumed to be known.
|
||
|
Size is the sample Size.
|
||
|
}
|
||
|
|
||
|
{CORREL}
|
||
|
function Correlation(const Data1, Data2 : array of Double) : Double;
|
||
|
function Correlation16(const Data1, Data2; NData : Integer) : Double;
|
||
|
{-Returns the correlation coefficient of the Data1 and Data2 arrays.
|
||
|
Use the correlation coefficient to determine the relationship between
|
||
|
two data sets.
|
||
|
This function also returns the same value as the PEARSON function
|
||
|
in Excel.
|
||
|
}
|
||
|
|
||
|
{COVAR}
|
||
|
function Covariance(const Data1, Data2 : array of Double) : Double;
|
||
|
function Covariance16(const Data1, Data2; NData : Integer) : Double;
|
||
|
{-Returns covariance, the average of products of deviations, for the Data1
|
||
|
and Data2 arrays. Use covariance to determine the relationship between
|
||
|
two data sets.
|
||
|
}
|
||
|
|
||
|
{DEVSQ}
|
||
|
function DevSq(const Data : array of Double) : Double;
|
||
|
function DevSq16(const Data; NData : Integer) : Double;
|
||
|
{-Returns the sum of squares of deviations of data points from their
|
||
|
sample mean.
|
||
|
}
|
||
|
|
||
|
{FREQUENCY}
|
||
|
procedure Frequency(const Data : array of Double; const Bins : array of Double;
|
||
|
var Counts : array of LongInt);
|
||
|
procedure Frequency16(const Data; NData : Integer; const Bins; NBins : Integer;
|
||
|
var Counts);
|
||
|
{-Calculates how often values occur within an array of data,
|
||
|
and then returns an array of counts.
|
||
|
Data is an array of values for which you want to count frequencies.
|
||
|
Bins is an array of intervals into which you want to group the values in
|
||
|
Data.
|
||
|
Counts is an array into which the frequency counts are returned. Counts
|
||
|
must have one more element than does Bins. The first element of Counts
|
||
|
has all items less than the first number in Bins. The next element of
|
||
|
Counts is the items that fall between Bins[0] and Bins[1]. The last
|
||
|
element of Counts has all items greater than the last number in Bins.
|
||
|
}
|
||
|
|
||
|
{GEOMEAN}
|
||
|
function GeometricMean(const Data : array of Double) : Double;
|
||
|
function GeometricMean16(const Data; NData : Integer) : Double;
|
||
|
{-Returns the geometric mean of an array of positive data. The geometric
|
||
|
mean is the n'th root of the product of n positive numbers.}
|
||
|
|
||
|
{HARMEAN}
|
||
|
function HarmonicMean(const Data : array of Double) : Double;
|
||
|
function HarmonicMean16(const Data; NData : Integer) : Double;
|
||
|
{-Returns the harmonic mean of an array of data. The harmonic mean is the
|
||
|
reciprocal of the arithmetic mean of reciprocals.}
|
||
|
|
||
|
{LARGE}
|
||
|
function Largest(const Data : array of Double; K : Integer) : Double;
|
||
|
function Largest16(const Data; NData : Integer; K : Integer) : Double;
|
||
|
{-Returns the K'th largest value in an array of data. You can use this
|
||
|
function to select a value based on its relative standing.}
|
||
|
|
||
|
{MEDIAN}
|
||
|
function Median(const Data : array of Double) : Double;
|
||
|
function Median16(const Data; NData : Integer) : Double;
|
||
|
{-Returns the median of the given numbers. The median is the number in the
|
||
|
middle of a set of numbers; that is, half the numbers have values that
|
||
|
are greater than the median, and half have values that are less.
|
||
|
If there is an even number of numbers in the set, MEDIAN calculates
|
||
|
the average of the two numbers in the middle.
|
||
|
}
|
||
|
|
||
|
{MODE}
|
||
|
function Mode(const Data: array of Double) : Double;
|
||
|
function Mode16(const Data; NData : Integer) : Double;
|
||
|
{-Returns the most frequently occurring, or repetitive, value in an array
|
||
|
of data. In case of duplicate frequencies it returns the smallest
|
||
|
such value.}
|
||
|
|
||
|
{PERCENTILE}
|
||
|
function Percentile(const Data : array of Double; K : Double) : Double;
|
||
|
function Percentile16(const Data; NData : Integer; K : Double) : Double;
|
||
|
{-Returns the value of the K'th percentile of an array of data.
|
||
|
K is the percentile value, a number between 0 and 1. If K is not a
|
||
|
multiple of 1/(n-1) where n is the size of Data, Percentile
|
||
|
interpolates between the closest bins.
|
||
|
}
|
||
|
|
||
|
{PERCENTRANK}
|
||
|
function PercentRank(const Data : array of Double; X : Double) : Double;
|
||
|
function PercentRank16(const Data; NData : Integer; X : Double) : Double;
|
||
|
{-Returns the percentile position of a value within an array of data.
|
||
|
X is a data value. If X is not found within the array, PercentRank
|
||
|
interpolates between the closest data points.
|
||
|
}
|
||
|
|
||
|
{PERMUT}
|
||
|
function Permutations(Number, NumberChosen : Integer) : Extended;
|
||
|
{-Returns the number of permutations for a given Number of objects that
|
||
|
can be selected from Number objects. A permutation is any set or subset
|
||
|
of objects or events where internal order is significant.
|
||
|
Permutations are different from combinations, for which the internal order
|
||
|
is not significant.
|
||
|
Number is an Integer that describes the number of objects.
|
||
|
NumberChosen is an Integer that describes the number of objects in
|
||
|
each permutation.
|
||
|
}
|
||
|
|
||
|
{COMBIN}
|
||
|
function Combinations(Number, NumberChosen : Integer) : Extended;
|
||
|
{-Returns the number of combinations for a given Number of objects that
|
||
|
can be selected from Number objects. A combination is any set or subset
|
||
|
of objects or events where internal order is not significant.
|
||
|
Number is an Integer that describes the number of objects.
|
||
|
NumberChosen is an Integer that describes the number of objects in
|
||
|
each permutation.
|
||
|
}
|
||
|
|
||
|
{FACT}
|
||
|
function Factorial(N : Integer) : Extended;
|
||
|
{-Returns N! as a floating point number.
|
||
|
Extended is used for range, not accuracy.
|
||
|
}
|
||
|
|
||
|
{RANK}
|
||
|
function Rank(Number : Double; const Data : array of Double;
|
||
|
Ascending : Boolean) : Integer;
|
||
|
function Rank16(Number : Double; const Data; NData : Integer;
|
||
|
Ascending : Boolean) : Integer;
|
||
|
{-Returns the rank of a number in a list of numbers. If you were to sort
|
||
|
a list that contained no duplicates, the rank of the Number would be its
|
||
|
position within the sorted list.
|
||
|
Number is the number whose rank you want.
|
||
|
Data is the list of numbers.
|
||
|
If Ascending is True the rank is measured from the beginning of the
|
||
|
array; otherwise from the end of the array.
|
||
|
If the Number is not found in the array, 0 is returned. Numbers that
|
||
|
appear multiple times all have the same rank, but they affect the
|
||
|
rank of numbers appearing after them. For example, in a list of
|
||
|
Integers, if the number 10 appears twice and has a rank of 5,
|
||
|
then 11 would have a rank of 7 (no number would have a rank of 6).
|
||
|
Be sure to sort Data before calling this routine if you want an
|
||
|
unambiguous ranking.
|
||
|
}
|
||
|
|
||
|
{SMALL}
|
||
|
function Smallest(const Data : array of Double; K : Integer) : Double;
|
||
|
function Smallest16(const Data; NData : Integer; K : Integer) : Double;
|
||
|
{-Returns the K'th smallest value in an array of data. You can use this
|
||
|
function to select a value based on its relative standing.}
|
||
|
|
||
|
{TRIMMEAN}
|
||
|
function TrimMean(const Data : array of Double; Percent : Double) : Double;
|
||
|
function TrimMean16(const Data; NData : Integer; Percent : Double) : Double;
|
||
|
{-Returns the mean of Data after trimming Percent points from the data set.
|
||
|
If Percent is 0.2 and there are 20 points in Data, the 2 largest and 2
|
||
|
smallest points would be dropped before computing the mean. Percent must
|
||
|
be a number between 0 and 1.
|
||
|
}
|
||
|
|
||
|
{--------------------------------------------------------------------------}
|
||
|
|
||
|
type
|
||
|
{full statistics for a linear regression}
|
||
|
TStLinEst = record
|
||
|
B0, B1 : Double; {model coefficients}
|
||
|
seB0, seB1 : Double; {standard error of model coefficients}
|
||
|
R2 : Double; {coefficient of determination}
|
||
|
sigma : Double; {standard error of regression}
|
||
|
SSr, SSe : Double; {elements for ANOVA table}
|
||
|
F0 : Double; {F-statistic to test B1=0}
|
||
|
df : Integer; {denominator degrees of freedom for F-statistic}
|
||
|
end;
|
||
|
|
||
|
{LINEST}
|
||
|
procedure LinEst(const KnownY : array of Double;
|
||
|
const KnownX : array of Double; var LF : TStLinEst; ErrorStats : Boolean);
|
||
|
procedure LinEst16(const KnownY; const KnownX; NData : Integer;
|
||
|
var LF : TStLinEst; ErrorStats : Boolean);
|
||
|
{-Performs linear fit to data and returns coefficients and error
|
||
|
statistics.
|
||
|
KnownY is the dependent array of known data points.
|
||
|
KnownX is the independent array of known data points.
|
||
|
NData must be greater than 2.
|
||
|
If ErrorStats is FALSE, only B0 and B1 are computed; the other fields
|
||
|
of TStLinEst are set to 0.0.
|
||
|
See declaration of TStLinEst for returned data.
|
||
|
|
||
|
}
|
||
|
|
||
|
{LOGEST}
|
||
|
procedure LogEst(const KnownY : array of Double;
|
||
|
const KnownX : array of Double; var LF : TStLinEst; ErrorStats : Boolean);
|
||
|
procedure LogEst16(const KnownY; const KnownX; NData : Integer;
|
||
|
var LF : TStLinEst; ErrorStats : Boolean);
|
||
|
{-Performs log-linear fit to data and returns coefficients and error
|
||
|
statistics.
|
||
|
KnownY is the dependent array of known data points.
|
||
|
KnownX is the independent array of known data points.
|
||
|
NData must be greater than 2.
|
||
|
KnownY is transformed using ln(KnownY) before fitting:
|
||
|
y = B0*B1^x implies that ln(y) = ln(B0)+X*ln(B1)
|
||
|
In the returned LF, B0 and B1 are returned as shown. Other values in LF
|
||
|
are in terms of the log transformation.
|
||
|
If ErrorStats is FALSE, only B0 and B1 are computed; the other fields
|
||
|
of TStLinEst are set to 0.0.
|
||
|
See declaration of TStLinEst for returned data.
|
||
|
}
|
||
|
|
||
|
{FORECAST}
|
||
|
function Forecast(X : Double; const KnownY: array of Double;
|
||
|
const KnownX : array of Double) : Double;
|
||
|
function Forecast16(X : Double; const KnownY; const KnownX;
|
||
|
NData : Integer) : Double;
|
||
|
{-Calculates a future value by using existing values. The predicted value
|
||
|
is a y-value for a given X-value. The known values are existing X-values
|
||
|
and y-values, and the new value is predicted by using linear regression.
|
||
|
X is the data point for which you want to predict a value.
|
||
|
KnownY is the dependent array of known data points.
|
||
|
KnownX is the independent array of known data points.
|
||
|
}
|
||
|
|
||
|
{similar to GROWTH but more consistent with FORECAST}
|
||
|
function ForecastExponential(X : Double; const KnownY : array of Double;
|
||
|
const KnownX : array of Double) : Double;
|
||
|
function ForecastExponential16(X : Double; const KnownY; const KnownX;
|
||
|
NData : Integer) : Double;
|
||
|
{-Calculates a future value by using existing values. The predicted value
|
||
|
is a y-value for a given X-value. The known values are existing X-values
|
||
|
and y-values, and the new value is predicted by using linear regression
|
||
|
to an exponential growth model, y = B0*B1^X.
|
||
|
X is the data point for which you want to predict a value.
|
||
|
KnownY is the dependent array of known data points.
|
||
|
KnownX is the independent array of known data points.
|
||
|
}
|
||
|
|
||
|
{INTERCEPT}
|
||
|
function Intercept(const KnownY : array of Double;
|
||
|
const KnownX : array of Double) : Double;
|
||
|
function Intercept16(const KnownY; const KnownX; NData : Integer) : Double;
|
||
|
{-Calculates the point at which a line will intersect the y-axis by using
|
||
|
existing X-values and y-values. The intercept point is based on a best-fit
|
||
|
regression line plotted through the known X-values and known y-values.
|
||
|
Use the intercept when you want to determine the value of the dependent
|
||
|
variable when the independent variable is 0 (zero).
|
||
|
}
|
||
|
|
||
|
{RSQ}
|
||
|
function RSquared(const KnownY : array of Double;
|
||
|
const KnownX : array of Double) : Double;
|
||
|
function RSquared16(const KnownY; const KnownX; NData : Integer) : Double;
|
||
|
{-Returns the square of the Pearson product moment correlation coefficient
|
||
|
through data points in KnownY's and KnownX's. The r-squared value can
|
||
|
be interpreted as the proportion of the variance in y attributable to
|
||
|
the variance in X.
|
||
|
}
|
||
|
|
||
|
{SLOPE}
|
||
|
function Slope(const KnownY : array of Double;
|
||
|
const KnownX : array of Double) : Double;
|
||
|
function Slope16(const KnownY; const KnownX; NData : Integer) : Double;
|
||
|
{-Returns the slope of the linear regression line through data points in
|
||
|
KnownY's and KnownX's. The slope is the vertical distance divided by the
|
||
|
horizontal distance between any two points on the line, which is the rate
|
||
|
of change along the regression line.
|
||
|
}
|
||
|
|
||
|
{STEYX}
|
||
|
function StandardErrorY(const KnownY : array of Double;
|
||
|
const KnownX : array of Double) : Double;
|
||
|
function StandardErrorY16(const KnownY; const KnownX;
|
||
|
NData : Integer) : Double;
|
||
|
{-Returns the standard error of the predicted y-value for each X in a linear
|
||
|
regression. The standard error is a measure of the amount of error in the
|
||
|
prediction of y for an individual X.
|
||
|
}
|
||
|
|
||
|
{--------------------------------------------------------------------------}
|
||
|
|
||
|
{BETADIST}
|
||
|
function BetaDist(X, Alpha, Beta, A, B : Single) : Single;
|
||
|
{-Returns the cumulative beta probability density function.
|
||
|
The cumulative beta probability density function is commonly used to
|
||
|
study variation in the percentage of something across samples.
|
||
|
X is the value at which to evaluate the function, A <= X <= B.
|
||
|
Alpha is a parameter to the distribution.
|
||
|
Beta is a parameter to the distribution.
|
||
|
A is the lower bound to the interval of X.
|
||
|
B is the upper bound to the interval of X.
|
||
|
The standard beta distribution has A=0 and B=1.
|
||
|
Fractional error less than 3.0e-7.
|
||
|
}
|
||
|
|
||
|
{BETAINV}
|
||
|
function BetaInv(Probability, Alpha, Beta, A, B : Single) : Single;
|
||
|
{-Returns the inverse of the cumulative beta probability density function.
|
||
|
That is, if Probability = BetaDist(X,...), then
|
||
|
BetaInv(Probability,...) = X.
|
||
|
Probability is a probability (0 <= p <= 1) associated with the
|
||
|
beta distribution.
|
||
|
Alpha is a parameter to the distribution.
|
||
|
Beta is a parameter to the distribution.
|
||
|
A is the lower bound to the interval of the distribution.
|
||
|
B is the upper bound to the interval of the distribution.
|
||
|
Fractional error less than 3.0e-7.
|
||
|
}
|
||
|
|
||
|
{BINOMDIST}
|
||
|
function BinomDist(NumberS, Trials : Integer; ProbabilityS : Single;
|
||
|
Cumulative : Boolean) : Single;
|
||
|
{-Returns the individual term binomial distribution probability.
|
||
|
Use BinomDist in problems with a fixed number of tests or Trials,
|
||
|
when the outcomes of any trial are only success or failure,
|
||
|
when Trials are independent, and when the probability of success is
|
||
|
constant throughout the experiment.
|
||
|
NumberS is the number of successes in Trials.
|
||
|
Trials is the number of independent trials.
|
||
|
ProbabilityS is the probability of success on each trial.
|
||
|
Cumulative is a logical value that determines the form of the function.
|
||
|
If Cumulative is TRUE, then BinomDist returns the cumulative
|
||
|
distribution function, which is the probability that there are at most
|
||
|
NumberS successes; if FALSE, it returns the probability mass function,
|
||
|
which is the probability that there are NumberS successes.
|
||
|
}
|
||
|
|
||
|
{CRITBINOM}
|
||
|
function CritBinom(Trials : Integer; ProbabilityS, Alpha : Single) : Integer;
|
||
|
{-Returns the smallest value for which the cumulative binomial distribution
|
||
|
is greater than or equal to a criterion value.
|
||
|
Trials is the number of Bernoulli trials.
|
||
|
ProbabilityS is the probability of a success on each trial.
|
||
|
Alpha is the criterion value.
|
||
|
}
|
||
|
|
||
|
{CHIDIST}
|
||
|
function ChiDist(X : Single; DegreesFreedom : Integer) : Single;
|
||
|
{-Returns the one-tailed probability of the chi-squared distribution.
|
||
|
The chi-squared distribution is associated with a chi-squared test.
|
||
|
Use the chi-squared test to compare observed and expected values.
|
||
|
X is the value at which you want to evaluate the distribution.
|
||
|
DegreesFreedom is the number of degrees of freedom.
|
||
|
}
|
||
|
|
||
|
{CHIINV}
|
||
|
function ChiInv(Probability : Single; DegreesFreedom : Integer) : Single;
|
||
|
{-Returns the inverse of the one-tailed probability of the chi-squared
|
||
|
distribution. If Probability = ChiDist(X,...), then
|
||
|
ChiInv(Probability,...) = X.
|
||
|
Probability is a probability associated with the chi-squared
|
||
|
distribution.
|
||
|
DegreesFreedom is the number of degrees of freedom.
|
||
|
}
|
||
|
|
||
|
{EXPONDIST}
|
||
|
function ExponDist(X, Lambda : Single; Cumulative : Boolean) : Single;
|
||
|
{-Returns the exponential distribution. Use ExponDist to model the time
|
||
|
between events.
|
||
|
X is the value of the function.
|
||
|
Lambda is the parameter value.
|
||
|
Cumulative is a logical value that indicates which form of the
|
||
|
exponential function to provide. If Cumulative is TRUE, ExponDist
|
||
|
returns the cumulative distribution function; if FALSE, it returns
|
||
|
the probability density function.
|
||
|
}
|
||
|
|
||
|
{FDIST}
|
||
|
function FDist(X : Single; DegreesFreedom1, DegreesFreedom2 : Integer) : Single;
|
||
|
{-Returns the F probability distribution. You can use this function to
|
||
|
determine whether two data sets have different degrees of diversity.
|
||
|
X is the value at which to evaluate the function.
|
||
|
DegreesFreedom1 is the numerator degrees of freedom.
|
||
|
DegreesFreedom2 is the denominator degrees of freedom.
|
||
|
Fractional error less than 3.0e-7.
|
||
|
}
|
||
|
|
||
|
{FINV}
|
||
|
function FInv(Probability : Single;
|
||
|
DegreesFreedom1, DegreesFreedom2 : Integer) : Single;
|
||
|
{-Returns the inverse of the F probability distribution. If
|
||
|
p = FDist(X,...), then FInv(p,...) = X.
|
||
|
Probability is a probability associated with the F cumulative
|
||
|
distribution.
|
||
|
DegreesFreedom1 is the numerator degrees of freedom.
|
||
|
DegreesFreedom2 is the denominator degrees of freedom.
|
||
|
Fractional error less than 3.0e-7.
|
||
|
}
|
||
|
|
||
|
{LOGNORMDIST}
|
||
|
function LogNormDist(X, Mean, StandardDev : Single) : Single;
|
||
|
{-Returns the cumulative lognormal distribution of X, where ln(X) is
|
||
|
normally distributed with parameters Mean and StandardDev.
|
||
|
Use this function to analyze data that has been logarithmically
|
||
|
transformed.
|
||
|
X is the value at which to evaluate the function.
|
||
|
Mean is the mean of ln(X).
|
||
|
StandardDev is the standard deviation of ln(X).
|
||
|
}
|
||
|
|
||
|
{LOGINV}
|
||
|
function LogInv(Probability, Mean, StandardDev : Single) : Single;
|
||
|
{-Returns the inverse of the lognormal cumulative distribution function of
|
||
|
X, where ln(X) is normally distributed with parameters Mean and
|
||
|
StandardDev. If p = LogNormDist(X,...) then LogInv(p,...) = X.
|
||
|
Probability is a probability associated with the lognormal distribution.
|
||
|
Mean is the mean of ln(X).
|
||
|
StandardDev is the standard deviation of ln(X).
|
||
|
}
|
||
|
|
||
|
{NORMDIST}
|
||
|
function NormDist(X, Mean, StandardDev : Single; Cumulative : Boolean) : Single;
|
||
|
{-Returns the normal cumulative distribution for the specified Mean and
|
||
|
standard deviation.
|
||
|
X is the value for which you want the distribution.
|
||
|
Mean is the arithmetic mean of the distribution.
|
||
|
StandardDev is the standard deviation of the distribution.
|
||
|
Cumulative is a logical value that determines the form of the function.
|
||
|
If Cumulative is TRUE, NormDist returns the cumulative distribution
|
||
|
function; if FALSE, it returns the probability density function.
|
||
|
}
|
||
|
|
||
|
{NORMINV}
|
||
|
function NormInv(Probability, Mean, StandardDev : Single) : Single;
|
||
|
{-Returns the inverse of the normal cumulative distribution for the
|
||
|
specified mean and standard deviation.
|
||
|
Probability is a probability corresponding to the normal distribution.
|
||
|
Mean is the arithmetic mean of the distribution.
|
||
|
StandardDev is the standard deviation of the distribution.
|
||
|
}
|
||
|
|
||
|
{NORMSDIST}
|
||
|
function NormSDist(Z : Single) : Single;
|
||
|
{-Returns the standard normal cumulative distribution function.
|
||
|
The distribution has a mean of 0 (zero) and a standard deviation of one.
|
||
|
Z is the value for which you want the distribution.
|
||
|
}
|
||
|
|
||
|
{NORMSINV}
|
||
|
function NormSInv(Probability : Single) : Single;
|
||
|
{-Returns the inverse of the standard normal cumulative distribution.
|
||
|
The distribution has a mean of zero and a standard deviation of one.
|
||
|
Probability is a probability corresponding to the normal distribution.
|
||
|
}
|
||
|
|
||
|
{POISSON}
|
||
|
function Poisson(X : Integer; Mean : Single; Cumulative : Boolean) : Single;
|
||
|
{-Returns the Poisson distribution.
|
||
|
X is the number of events.
|
||
|
Mean is the expected numeric value.
|
||
|
Cumulative is a logical value that determines the form of the
|
||
|
probability distribution returned. If Cumulative is TRUE, Poisson
|
||
|
returns the cumulative Poisson probability that the number of random
|
||
|
events occurring will be between zero and X inclusive; if FALSE,
|
||
|
it returns the Poisson probability mass function that the number of
|
||
|
events occurring will be exactly X.
|
||
|
}
|
||
|
|
||
|
{TDIST}
|
||
|
function TDist(X : Single; DegreesFreedom : Integer; TwoTails : Boolean) : Single;
|
||
|
{-Returns the Student's t-distribution. The t-distribution is used in the
|
||
|
hypothesis testing of small sample data sets. Use this function in place
|
||
|
of a table of critical values for the t-distribution.
|
||
|
X is the numeric value at which to evaluate the distribution.
|
||
|
DegreesFreedom is an Integer indicating the number of degrees of freedom.
|
||
|
TwoTails if a logical value that indicates the number of distribution
|
||
|
tails to return. If FALSE, TDist returns the one-tailed distribution;
|
||
|
otherwise it returns the two-tailed distribution.
|
||
|
}
|
||
|
|
||
|
{TINV}
|
||
|
function TInv(Probability : Single; DegreesFreedom : Integer) : Single;
|
||
|
{-Returns the inverse of the Student's t-distribution for the specified
|
||
|
degrees of freedom.
|
||
|
Probability is the probability associated with the two-tailed Student's
|
||
|
t-distribution.
|
||
|
DegreesFreedom is the number of degrees of freedom to characterize
|
||
|
the distribution.
|
||
|
}
|
||
|
|
||
|
{--------------------------------------------------------------------------}
|
||
|
{undocumented functions you can call if you need}
|
||
|
|
||
|
function Erfc(X : Single) : Single;
|
||
|
{-Returns the complementary error function with fractional error
|
||
|
everywhere less than 1.2e-7. X is any finite value.
|
||
|
}
|
||
|
|
||
|
function GammaLn(X : Single) : Single;
|
||
|
{-Returns ln(Gamma(X)) where X > 0.0.}
|
||
|
|
||
|
{--------------------------------------------------------------------------}
|
||
|
|
||
|
{.$DEFINE Debug}
|
||
|
{$IFDEF Debug}
|
||
|
{like Largest and Smallest but using slower simpler algorithm}
|
||
|
function LargestSort(const Data: array of Double; K : Integer) : Double;
|
||
|
function SmallestSort(const Data: array of double; K : Integer) : Double;
|
||
|
{$ENDIF}
|
||
|
|
||
|
implementation
|
||
|
|
||
|
procedure RaiseStatError(Code : LongInt);
|
||
|
{-Generate a statistics exception}
|
||
|
var
|
||
|
E : EStStatError;
|
||
|
begin
|
||
|
E := EStStatError.CreateResTP(Code, 0);
|
||
|
E.ErrorCode := Code;
|
||
|
raise E;
|
||
|
end;
|
||
|
|
||
|
procedure DoubleArraySort(var Data; NData : Integer);
|
||
|
{-Heapsort an array of Doubles into Ascending order}
|
||
|
type
|
||
|
TDoubleArray1 = array[1..StMaxBlockSize div SizeOf(Double)] of Double;
|
||
|
var
|
||
|
i : Integer;
|
||
|
T : Double;
|
||
|
DA : TDoubleArray1 absolute Data;
|
||
|
|
||
|
procedure Adjust(i, N : Integer);
|
||
|
var
|
||
|
j : Integer;
|
||
|
S : Double;
|
||
|
begin
|
||
|
{j is left child of i}
|
||
|
j := 2*i;
|
||
|
{save i'th element temporarily}
|
||
|
S := DA[i];
|
||
|
while (j <= N) do begin
|
||
|
{compare left and right child}
|
||
|
if (j < N) and (DA[j] < DA[j+1]) then
|
||
|
{j indexes larger child}
|
||
|
inc(j);
|
||
|
if (S >= DA[j]) then
|
||
|
{a position for item is found}
|
||
|
break;
|
||
|
{move the larger child up a level}
|
||
|
DA[j shr 1] := DA[j];
|
||
|
{look at left child of j}
|
||
|
j := j shl 1;
|
||
|
end;
|
||
|
{store saved item}
|
||
|
DA[j shr 1] := S;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
{transform the elements into a heap}
|
||
|
for i := (NData shr 1) downto 1 do
|
||
|
Adjust(i, NData);
|
||
|
|
||
|
{repeatedly exchange the maximum at top of heap with the last element}
|
||
|
for i := NData downto 2 do begin
|
||
|
T := DA[1];
|
||
|
DA[1] := DA[i];
|
||
|
DA[i] := T;
|
||
|
{update the heap for the remaining elements}
|
||
|
Adjust(1, i-1);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function CopyAndSort(const Data; NData : Integer;
|
||
|
var SD : PDoubleArray) : Cardinal;
|
||
|
{-Allocates heap space for an array copy, moves data, sorts, and returns size}
|
||
|
var
|
||
|
Size : LongInt;
|
||
|
begin
|
||
|
Size := LongInt(NData)*sizeof(Double);
|
||
|
{if (Size > MaxBlockSize) then}
|
||
|
{ RaiseStatError(stscStatBadCount);}
|
||
|
Result := Size;
|
||
|
getmem(SD, Size); {raises exception if insufficient memory}
|
||
|
try
|
||
|
move(Data, SD^, Size);
|
||
|
DoubleArraySort(SD^, NData);
|
||
|
except
|
||
|
freemem(SD, Size);
|
||
|
raise;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function AveDev(const Data: array of Double) : Double;
|
||
|
begin
|
||
|
Result := AveDev16(Data, High(Data)+1);
|
||
|
end;
|
||
|
|
||
|
function Mean(const Data; NData : Integer) : Extended;
|
||
|
{-Computes the mean of an array of Doubles}
|
||
|
var
|
||
|
i : Integer;
|
||
|
s : Extended;
|
||
|
begin
|
||
|
s := 0.0;
|
||
|
for I := 0 to NData-1 do
|
||
|
s := s+TDoubleArray(Data)[I];
|
||
|
Result := s/NData;
|
||
|
end;
|
||
|
|
||
|
function AveDev16(const Data; NData : Integer) : Double;
|
||
|
var
|
||
|
i : Integer;
|
||
|
m, s : Extended;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{compute sum of absolute deviations}
|
||
|
m := Mean(Data, NData);
|
||
|
s := 0.0;
|
||
|
for i := 0 to NData-1 do
|
||
|
s := s+abs(TDoubleArray(Data)[i]-m);
|
||
|
|
||
|
Result := s/NData;
|
||
|
end;
|
||
|
|
||
|
function Confidence(Alpha, StandardDev : Double; Size : LongInt) : Double;
|
||
|
begin
|
||
|
if (StandardDev <= 0) or (Size < 1) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
Result := NormSInv(1.0-Alpha/2.0)*StandardDev/sqrt(Size);
|
||
|
end;
|
||
|
|
||
|
function Correlation(const Data1, Data2 : array of Double) : Double;
|
||
|
begin
|
||
|
if (High(Data1) <> High(Data2)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Result := Correlation16(Data1, Data2, High(Data1)+1);
|
||
|
end;
|
||
|
|
||
|
function Correlation16(const Data1, Data2; NData : Integer) : Double;
|
||
|
var
|
||
|
sx, sy, xmean, ymean, sxx, sxy, syy, x, y : Extended;
|
||
|
i : Integer;
|
||
|
begin
|
||
|
if (NData <= 1) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{compute basic sums}
|
||
|
sx := 0.0;
|
||
|
sy := 0.0;
|
||
|
sxx := 0.0;
|
||
|
sxy := 0.0;
|
||
|
syy := 0.0;
|
||
|
for i := 0 to NData-1 do begin
|
||
|
x := TDoubleArray(Data1)[i];
|
||
|
y := TDoubleArray(Data2)[i];
|
||
|
sx := sx+x;
|
||
|
sy := sy+y;
|
||
|
sxx := sxx+x*x;
|
||
|
syy := syy+y*y;
|
||
|
sxy := sxy+x*y;
|
||
|
end;
|
||
|
xmean := sx/NData;
|
||
|
ymean := sy/NData;
|
||
|
sxx := sxx-NData*xmean*xmean;
|
||
|
syy := syy-NData*ymean*ymean;
|
||
|
sxy := sxy-NData*xmean*ymean;
|
||
|
|
||
|
Result := sxy/sqrt(sxx*syy);
|
||
|
end;
|
||
|
|
||
|
function Covariance(const Data1, Data2 : array of Double) : Double;
|
||
|
begin
|
||
|
if (High(Data1) <> High(Data2)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Result := Covariance16(Data1, Data2, High(Data1)+1);
|
||
|
end;
|
||
|
|
||
|
function Covariance16(const Data1, Data2; NData : Integer) : Double;
|
||
|
var
|
||
|
sx, sy, xmean, ymean, sxy, x, y : Extended;
|
||
|
i : Integer;
|
||
|
begin
|
||
|
if (NData <= 1) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{compute basic sums}
|
||
|
sx := 0.0;
|
||
|
sy := 0.0;
|
||
|
sxy := 0.0;
|
||
|
for i := 0 to NData-1 do begin
|
||
|
x := TDoubleArray(Data1)[i];
|
||
|
y := TDoubleArray(Data2)[i];
|
||
|
sx := sx+x;
|
||
|
sy := sy+y;
|
||
|
sxy := sxy+x*y;
|
||
|
end;
|
||
|
xmean := sx/NData;
|
||
|
ymean := sy/NData;
|
||
|
sxy := sxy-NData*xmean*ymean;
|
||
|
|
||
|
Result := sxy/NData;
|
||
|
end;
|
||
|
|
||
|
function DevSq(const Data: array of Double) : Double;
|
||
|
begin
|
||
|
Result := DevSq16(Data, High(Data)+1);
|
||
|
end;
|
||
|
|
||
|
function DevSq16(const Data; NData : Integer) : Double;
|
||
|
var
|
||
|
i : Integer;
|
||
|
sx, sxx, x : Extended;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
sx := 0.0;
|
||
|
sxx := 0.0;
|
||
|
for i := 0 to NData-1 do begin
|
||
|
x := TDoubleArray(Data)[i];
|
||
|
sx := sx+x;
|
||
|
sxx := sxx+x*x;
|
||
|
end;
|
||
|
Result := sxx-sqr(sx)/NData;
|
||
|
end;
|
||
|
|
||
|
procedure Frequency(const Data: array of Double; const Bins: array of Double;
|
||
|
var Counts: array of LongInt);
|
||
|
begin
|
||
|
if (High(Counts) <= High(Bins)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Frequency16(Data, High(Data)+1, Bins, High(Bins)+1, Counts);
|
||
|
end;
|
||
|
|
||
|
procedure Frequency16(const Data; NData : Integer; const Bins; NBins : Integer;
|
||
|
var Counts);
|
||
|
var
|
||
|
b, i : Integer;
|
||
|
Size : Cardinal;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
if (NData <= 0) or (NBins <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{copy and sort array}
|
||
|
Size := CopyAndSort(Data, NData, SD);
|
||
|
try
|
||
|
{initialize all counts to zero}
|
||
|
fillchar(Counts, (NBins+1)*sizeof(Integer), 0);
|
||
|
|
||
|
{scan all data elements, putting into correct bin}
|
||
|
b := 0;
|
||
|
i := 0;
|
||
|
while (i < NData) do begin
|
||
|
if (SD^[i] <= TDoubleArray(Bins)[b]) then begin
|
||
|
{current data element falls into this bin}
|
||
|
inc(TIntArray(Counts)[b]);
|
||
|
inc(i);
|
||
|
end else begin
|
||
|
{move to next bin that collects data}
|
||
|
repeat
|
||
|
inc(b);
|
||
|
until (b = NBins) or (TDoubleArray(Bins)[b] > SD^[i]);
|
||
|
if (b = NBins) then begin
|
||
|
{add remaining elements to the catchall bin}
|
||
|
inc(TIntArray(Counts)[b], NData-i);
|
||
|
i := NData;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function GeometricMean(const Data: array of Double) : Double;
|
||
|
begin
|
||
|
Result := GeometricMean16(Data, High(Data)+1);
|
||
|
end;
|
||
|
|
||
|
function GeometricMean16(const Data; NData : Integer) : Double;
|
||
|
var
|
||
|
i : Integer;
|
||
|
s, t : Extended;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
s := 1.0;
|
||
|
for i := 0 to NData-1 do begin
|
||
|
t := TDoubleArray(Data)[i];
|
||
|
if (t <= 0.0) then
|
||
|
RaiseStatError(stscStatBadData);
|
||
|
s := s*t;
|
||
|
end;
|
||
|
|
||
|
Result := Power(s, 1.0/NData);
|
||
|
end;
|
||
|
|
||
|
function HarmonicMean(const Data: array of Double) : Double;
|
||
|
begin
|
||
|
Result := HarmonicMean16(Data, High(Data)+1);
|
||
|
end;
|
||
|
|
||
|
function HarmonicMean16(const Data; NData : Integer) : Double;
|
||
|
var
|
||
|
i : Integer;
|
||
|
s, t : Extended;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
s := 0.0;
|
||
|
for i := 0 to NData-1 do begin
|
||
|
t := TDoubleArray(Data)[i];
|
||
|
if (t = 0.0) then
|
||
|
RaiseStatError(stscStatBadData);
|
||
|
s := s+(1.0/t);
|
||
|
end;
|
||
|
Result := NData/s;
|
||
|
end;
|
||
|
|
||
|
function Largest(const Data: array of Double; K : Integer) : Double;
|
||
|
begin
|
||
|
Result := Largest16(Data, High(Data)+1, K);
|
||
|
end;
|
||
|
|
||
|
function Largest16(const Data; NData : Integer; K : Integer) : Double;
|
||
|
var
|
||
|
b, t, i, j : integer;
|
||
|
Size : LongInt;
|
||
|
temp, pval : Double;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
if (K <= 0) or (K > NData) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
Size := LongInt(NData)*sizeof(Double);
|
||
|
{if (Size > MaxBlockSize) then}
|
||
|
{ RaiseStatError(stscStatBadCount);}
|
||
|
getmem(SD, Size); {raises exception if insufficient memory}
|
||
|
try
|
||
|
move(Data, SD^, Size);
|
||
|
|
||
|
{make K 0-based}
|
||
|
dec(K);
|
||
|
|
||
|
{use quicksort-like selection}
|
||
|
b := 0;
|
||
|
t := NData-1;
|
||
|
while (t > b) do begin
|
||
|
{use random pivot in case of already-sorted data}
|
||
|
pval := SD^[b+random(t-b+1)];
|
||
|
i := b;
|
||
|
j := t;
|
||
|
repeat
|
||
|
while (SD^[i] > pval) do
|
||
|
inc(i);
|
||
|
while (pval > SD^[j]) do
|
||
|
dec(j);
|
||
|
if (i <= j) then begin
|
||
|
temp := SD^[i];
|
||
|
SD^[i] := SD^[j];
|
||
|
SD^[j] := temp;
|
||
|
inc(i);
|
||
|
dec(j);
|
||
|
end;
|
||
|
until (i > j);
|
||
|
if (j < K) then
|
||
|
b := i;
|
||
|
if (K < i) then
|
||
|
t := j;
|
||
|
end;
|
||
|
Result := SD^[K];
|
||
|
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{debug version of Largest: slower but simpler}
|
||
|
{$IFDEF Debug}
|
||
|
function LargestSort(const Data: array of Double; K : Integer) : Double;
|
||
|
var
|
||
|
Size : Cardinal;
|
||
|
NData : Integer;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
NData := High(Data)+1;
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
if (K <= 0) or (K > NData) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
{copy and sort array}
|
||
|
Size := CopyAndSort(Data, NData, SD);
|
||
|
try
|
||
|
{K=1 returns largest value, K=NData returns smallest}
|
||
|
Result := SD^[NData-K];
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
function Median(const Data: array of Double) : Double;
|
||
|
begin
|
||
|
Result := Median16(Data, High(Data)+1);
|
||
|
end;
|
||
|
|
||
|
function Median16(const Data; NData : Integer) : Double;
|
||
|
var
|
||
|
m : Integer;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
m := NData shr 1;
|
||
|
if odd(NData) then
|
||
|
Result := Largest16(Data, NData, m+1)
|
||
|
else
|
||
|
Result := (Largest16(Data, NData, m+1)+Largest16(Data, NData, m))/2.0;
|
||
|
end;
|
||
|
|
||
|
function Mode(const Data: array of Double) : Double;
|
||
|
begin
|
||
|
Result := Mode16(Data, High(Data)+1);
|
||
|
end;
|
||
|
|
||
|
function Mode16(const Data; NData : Integer) : Double;
|
||
|
var
|
||
|
maxf, i, f : Integer;
|
||
|
Size : Cardinal;
|
||
|
last, max : Double;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{copy and sort array}
|
||
|
Size := CopyAndSort(Data, NData, SD);
|
||
|
try
|
||
|
{find the value with highest frequency}
|
||
|
last := SD^[0];
|
||
|
max := last;
|
||
|
f := 1;
|
||
|
maxf := f;
|
||
|
|
||
|
for i := 1 to NData-1 do begin
|
||
|
if SD^[i] = last then
|
||
|
{keep count of identical values}
|
||
|
inc(f)
|
||
|
else begin
|
||
|
{start a new series}
|
||
|
if f > maxf then begin
|
||
|
max := last;
|
||
|
maxf := f;
|
||
|
end;
|
||
|
last := SD^[i];
|
||
|
f := 1;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{test last group}
|
||
|
if f > maxf then
|
||
|
max := last;
|
||
|
|
||
|
Result := max;
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function Percentile(const Data: array of Double; K : Double) : Double;
|
||
|
begin
|
||
|
Result := Percentile16(Data, High(Data)+1, K);
|
||
|
end;
|
||
|
|
||
|
function Percentile16(const Data; NData : Integer; K : Double) : Double;
|
||
|
const
|
||
|
eps = 1.0e-10;
|
||
|
var
|
||
|
ibin : Integer;
|
||
|
Size : Cardinal;
|
||
|
rbin, l, h : Double;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
if (K < 0.0) or (K > 1.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
{copy and sort array}
|
||
|
Size := CopyAndSort(Data, NData, SD);
|
||
|
try
|
||
|
{find nearest bins}
|
||
|
rbin := K*(NData-1);
|
||
|
ibin := Trunc(rbin);
|
||
|
if Frac(rbin) < eps then
|
||
|
{very close to array index below}
|
||
|
Result := SD^[ibin]
|
||
|
else if (Int(rbin)+1.0-rbin) < eps then
|
||
|
{very close to array index above}
|
||
|
Result := SD^[ibin+1]
|
||
|
else begin
|
||
|
{need to interpolate between two bins}
|
||
|
l := SD^[ibin];
|
||
|
h := SD^[ibin+1];
|
||
|
Result := l+(h-l)*(K*(NData-1)-ibin);
|
||
|
end;
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function PercentRank(const Data: array of Double; X : Double) : Double;
|
||
|
begin
|
||
|
Result := PercentRank16(Data, High(Data)+1, X);
|
||
|
end;
|
||
|
|
||
|
function PercentRank16(const Data; NData : Integer; X : Double) : Double;
|
||
|
var
|
||
|
b, t, m : Integer;
|
||
|
Size : Cardinal;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{copy and sort array}
|
||
|
Size := CopyAndSort(Data, NData, SD);
|
||
|
try
|
||
|
{test end conditions}
|
||
|
if (X < SD^[0]) or (X > SD^[NData-1]) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
{find nearby bins using binary search}
|
||
|
b := 0;
|
||
|
t := NData-1;
|
||
|
while (t-b) > 1 do begin
|
||
|
m := (b+t) shr 1;
|
||
|
if (X >= SD^[m]) then
|
||
|
{search upper half}
|
||
|
b := m
|
||
|
else
|
||
|
{search lower half}
|
||
|
t := m;
|
||
|
end;
|
||
|
|
||
|
{now X is known to be between b (inclusive) and b+1}
|
||
|
{handle duplicate elements below b}
|
||
|
while (b > 0) and (SD^[b-1] = X) do
|
||
|
dec(b);
|
||
|
|
||
|
if (SD^[b] = X) then
|
||
|
{an exact match}
|
||
|
Result := b/(NData-1)
|
||
|
else
|
||
|
{interpolate}
|
||
|
Result := (b+(X-SD^[b])/(SD^[b+1]-SD^[b]))/(NData-1);
|
||
|
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
const
|
||
|
sqrt2pi = 2.5066282746310005; {sqrt(2*pi)}
|
||
|
|
||
|
function GammaLn(X : Single) : Single;
|
||
|
{-Returns ln(Gamma(X)) where X > 0}
|
||
|
const
|
||
|
cof : array[0..5] of Double = (
|
||
|
76.18009172947146, -86.50532032941677, 24.01409824083091,
|
||
|
-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5);
|
||
|
var
|
||
|
y, tmp, ser : Double;
|
||
|
j : Integer;
|
||
|
begin
|
||
|
if (X <= 0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
y := X;
|
||
|
tmp := X+5.5;
|
||
|
tmp := tmp-(X+0.5)*ln(tmp);
|
||
|
ser := 1.000000000190015;
|
||
|
for j := low(cof) to high(cof) do begin
|
||
|
y := y+1.0;
|
||
|
ser := ser+cof[j]/y;
|
||
|
end;
|
||
|
Result := -tmp+ln(sqrt2pi*ser/X);
|
||
|
end;
|
||
|
|
||
|
const
|
||
|
MFactLnA = 65;
|
||
|
var
|
||
|
FactLnA : array[2..MFactLna] of Single; {lookup table of FactLn values}
|
||
|
|
||
|
function FactLn(N : Integer) : Single;
|
||
|
{-Returns ln(N!) for N >= 0}
|
||
|
begin
|
||
|
if (N <= 1) then
|
||
|
Result := 0.0
|
||
|
else if (N <= MFactLnA) then
|
||
|
{use lookup table}
|
||
|
Result := FactLnA[N]
|
||
|
else
|
||
|
{compute each time}
|
||
|
Result := GammaLn(N+1.0);
|
||
|
end;
|
||
|
|
||
|
const
|
||
|
MFactA = 33;
|
||
|
var
|
||
|
FactA : array[2..MFactA] of Double; {lookup table of factorial values}
|
||
|
|
||
|
function Factorial(N : Integer) : Extended;
|
||
|
begin
|
||
|
if (N < 0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
if (N <= 1) then
|
||
|
Result := 1.0
|
||
|
else if (N <= MFactA) then
|
||
|
{use lookup table}
|
||
|
Result := FactA[N]
|
||
|
else
|
||
|
{bigger than lookup table allows. may overflow!}
|
||
|
Result := exp(GammaLn(N+1.0))
|
||
|
end;
|
||
|
|
||
|
function Permutations(Number, NumberChosen : Integer) : Extended;
|
||
|
begin
|
||
|
if (Number < 0) or (NumberChosen < 0) or (Number < NumberChosen) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
{the 0.5 and Int function clean up roundoff error for smaller N and K}
|
||
|
Result := Int(0.5+exp(FactLn(Number)-FactLn(Number-NumberChosen)));
|
||
|
end;
|
||
|
|
||
|
function Combinations(Number, NumberChosen : Integer) : Extended;
|
||
|
begin
|
||
|
if (Number < 0) or (NumberChosen < 0) or (Number < NumberChosen) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
{the 0.5 and Int function clean up roundoff error for smaller N and K}
|
||
|
Result := Int(0.5+exp(FactLn(Number)-FactLn(NumberChosen)
|
||
|
-FactLn(Number-NumberChosen)));
|
||
|
end;
|
||
|
|
||
|
function Rank(Number: Double; const Data: array of Double;
|
||
|
Ascending: Boolean) : Integer;
|
||
|
begin
|
||
|
Result := Rank16(Number, Data, High(Data)+1, Ascending);
|
||
|
end;
|
||
|
|
||
|
function Rank16(Number: Double; const Data; NData : Integer;
|
||
|
Ascending: Boolean) : Integer;
|
||
|
var
|
||
|
r : Integer;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{Data not known to be sorted, so must search linearly}
|
||
|
if (Ascending) then begin
|
||
|
for r := 0 to NData-1 do
|
||
|
if TDoubleArray(Data)[r] = Number then begin
|
||
|
Result := r+1;
|
||
|
exit;
|
||
|
end;
|
||
|
end else begin
|
||
|
for r := NData-1 downto 0 do
|
||
|
if TDoubleArray(Data)[r] = Number then begin
|
||
|
Result := NData-r;
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
Result := 0;
|
||
|
end;
|
||
|
|
||
|
function Smallest(const Data: array of Double; K : Integer) : Double;
|
||
|
begin
|
||
|
Result := Smallest16(Data, High(Data)+1, K);
|
||
|
end;
|
||
|
|
||
|
function Smallest16(const Data; NData : Integer; K : Integer) : Double;
|
||
|
var
|
||
|
b, t, i, j : integer;
|
||
|
Size : LongInt;
|
||
|
temp, pval : Double;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
if (K <= 0) or (K > NData) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
Size := LongInt(NData)*sizeof(Double);
|
||
|
{if (Size > MaxBlockSize) then}
|
||
|
{ RaiseStatError(stscStatBadCount);}
|
||
|
getmem(SD, Size); {raises exception if insufficient memory}
|
||
|
try
|
||
|
move(Data, SD^, Size);
|
||
|
|
||
|
{make K 0-based}
|
||
|
dec(K);
|
||
|
{use quicksort-like selection}
|
||
|
b := 0;
|
||
|
t := NData-1;
|
||
|
while (t > b) do begin
|
||
|
{use random pivot in case of already-sorted data}
|
||
|
pval := SD^[b+random(t-b+1)];
|
||
|
i := b;
|
||
|
j := t;
|
||
|
repeat
|
||
|
while (SD^[i] < pval) do
|
||
|
inc(i);
|
||
|
while (pval < SD^[j]) do
|
||
|
dec(j);
|
||
|
if (i <= j) then begin
|
||
|
temp := SD^[i];
|
||
|
SD^[i] := SD^[j];
|
||
|
SD^[j] := temp;
|
||
|
inc(i);
|
||
|
dec(j);
|
||
|
end;
|
||
|
until (i > j);
|
||
|
|
||
|
if (j < K) then
|
||
|
b := i;
|
||
|
if (K < i) then
|
||
|
t := j;
|
||
|
end;
|
||
|
Result := SD^[K];
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{debug version of Smallest: slower but simpler}
|
||
|
{$IFDEF Debug}
|
||
|
function SmallestSort(const Data: array of double; K : Integer) : Double;
|
||
|
var
|
||
|
Size : Cardinal;
|
||
|
NData : Integer;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
NData := High(Data)+1;
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
if (K <= 0) or (K > NData) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
{copy and sort array}
|
||
|
Size := CopyAndSort(Data, NData, SD);
|
||
|
try
|
||
|
{K=1 returns smallest value, K=NData returns largest}
|
||
|
Result := SD^[K-1];
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
function TrimMean(const Data: array of Double; Percent : Double) : Double;
|
||
|
begin
|
||
|
Result := TrimMean16(Data, High(Data)+1, Percent);
|
||
|
end;
|
||
|
|
||
|
function TrimMean16(const Data; NData : Integer; Percent : Double) : Double;
|
||
|
var
|
||
|
ntrim : Integer;
|
||
|
Size : Cardinal;
|
||
|
SD : PDoubleArray;
|
||
|
begin
|
||
|
if (NData <= 0) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
if (Percent < 0.0) or (Percent > 1.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
{compute total number of trimmed points, rounding down to an even number}
|
||
|
ntrim := trunc(Percent*NData);
|
||
|
if odd(ntrim) then
|
||
|
dec(ntrim);
|
||
|
|
||
|
{take the easy way out when possible}
|
||
|
if (ntrim = 0) then begin
|
||
|
Result := Mean(Data, NData);
|
||
|
exit;
|
||
|
end;
|
||
|
|
||
|
{copy and sort array}
|
||
|
Size := CopyAndSort(Data, NData, SD);
|
||
|
try
|
||
|
{return Mean of remaining data points}
|
||
|
Result := Mean(SD^[ntrim shr 1], NData-ntrim);
|
||
|
finally
|
||
|
freemem(SD, Size);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{------------------------------------------------------------------------}
|
||
|
|
||
|
procedure LinEst(const KnownY: array of Double;
|
||
|
const KnownX: array of Double; var LF : TStLinEst; ErrorStats : Boolean);
|
||
|
begin
|
||
|
if (High(KnownY) <> High(KnownX)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
LinEst16(KnownY, KnownX, High(KnownY)+1, LF, ErrorStats);
|
||
|
end;
|
||
|
|
||
|
procedure LinEst16(const KnownY; const KnownX; NData : Integer;
|
||
|
var LF : TStLinEst; ErrorStats : Boolean);
|
||
|
var
|
||
|
i : Integer;
|
||
|
sx, sy, xmean, ymean, sxx, sxy, syy, x, y : Extended;
|
||
|
begin
|
||
|
if (NData <= 2) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{compute basic sums}
|
||
|
sx := 0.0;
|
||
|
sy := 0.0;
|
||
|
sxx := 0.0;
|
||
|
sxy := 0.0;
|
||
|
syy := 0.0;
|
||
|
for i := 0 to NData-1 do begin
|
||
|
x := TDoubleArray(KnownX)[i];
|
||
|
y := TDoubleArray(KnownY)[i];
|
||
|
sx := sx+x;
|
||
|
sy := sy+y;
|
||
|
sxx := sxx+x*x;
|
||
|
syy := syy+y*y;
|
||
|
sxy := sxy+x*y;
|
||
|
end;
|
||
|
xmean := sx/NData;
|
||
|
ymean := sy/NData;
|
||
|
sxx := sxx-NData*xmean*xmean;
|
||
|
syy := syy-NData*ymean*ymean;
|
||
|
sxy := sxy-NData*xmean*ymean;
|
||
|
|
||
|
{check for zero variance}
|
||
|
if (sxx <= 0.0) or (syy <= 0.0) then
|
||
|
RaiseStatError(stscStatBadData);
|
||
|
|
||
|
{initialize returned parameters}
|
||
|
fillchar(LF, sizeof(LF), 0);
|
||
|
|
||
|
{regression coefficients}
|
||
|
LF.B1 := sxy/sxx;
|
||
|
LF.B0 := ymean-LF.B1*xmean;
|
||
|
|
||
|
{error statistics}
|
||
|
if (ErrorStats) then begin
|
||
|
LF.ssr := LF.B1*sxy;
|
||
|
LF.sse := syy-LF.ssr;
|
||
|
LF.R2 := LF.ssr/syy;
|
||
|
LF.df := NData-2;
|
||
|
LF.sigma := sqrt(LF.sse/LF.df);
|
||
|
if LF.sse = 0.0 then
|
||
|
{pick an arbitrarily large number for perfect fit}
|
||
|
LF.F0 := 1.7e+308
|
||
|
else
|
||
|
LF.F0 := (LF.ssr*LF.df)/LF.sse;
|
||
|
LF.seB1 := LF.sigma/sqrt(sxx);
|
||
|
LF.seB0 := LF.sigma*sqrt((1.0/NData)+(xmean*xmean/sxx));
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure LogEst(const KnownY: array of Double;
|
||
|
const KnownX: array of Double; var LF : TStLinEst; ErrorStats : Boolean);
|
||
|
begin
|
||
|
if (High(KnownY) <> High(KnownX)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
LogEst16(KnownY, KnownX, High(KnownY)+1, LF, ErrorStats);
|
||
|
end;
|
||
|
|
||
|
procedure LogEst16(const KnownY; const KnownX; NData : Integer;
|
||
|
var LF : TStLinEst; ErrorStats : Boolean);
|
||
|
var
|
||
|
i : Integer;
|
||
|
Size : LongInt;
|
||
|
lny : PDoubleArray;
|
||
|
begin
|
||
|
if (NData <= 2) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
|
||
|
{allocate array for the log-transformed data}
|
||
|
Size := LongInt(NData)*sizeof(Double);
|
||
|
{f (Size > MaxBlockSize) then}
|
||
|
{ RaiseStatError(stscStatBadCount);}
|
||
|
getmem(lny, Size);
|
||
|
try
|
||
|
{initialize transformed data}
|
||
|
for i := 0 to NData-1 do
|
||
|
lny^[i] := ln(TDoubleArray(KnownY)[i]);
|
||
|
|
||
|
{fit transformed data}
|
||
|
LinEst16(lny^, KnownX, NData, LF, ErrorStats);
|
||
|
|
||
|
{return values for B0 and B1 in exponential model y=B0*B1^x}
|
||
|
LF.B0 := exp(LF.B0);
|
||
|
LF.B1 := exp(LF.B1);
|
||
|
{leave other values in LF in log form}
|
||
|
finally
|
||
|
freemem(lny, Size);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function Forecast(X : Double; const KnownY: array of Double;
|
||
|
const KnownX: array of Double) : Double;
|
||
|
begin
|
||
|
if (High(KnownY) <> High(KnownX)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Result := Forecast16(X, KnownY, KnownX, High(KnownY)+1);
|
||
|
end;
|
||
|
|
||
|
function Forecast16(X : Double; const KnownY; const KnownX;
|
||
|
NData : Integer) : Double;
|
||
|
var
|
||
|
LF : TStLinEst;
|
||
|
begin
|
||
|
LinEst16(KnownY, KnownX, NData, LF, false);
|
||
|
Result := LF.B0+LF.B1*X;
|
||
|
end;
|
||
|
|
||
|
function ForecastExponential(X : Double; const KnownY: array of Double;
|
||
|
const KnownX: array of Double) : Double;
|
||
|
begin
|
||
|
if (High(KnownY) <> High(KnownX)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Result := ForecastExponential16(X, KnownY, KnownX, High(KnownY)+1);
|
||
|
end;
|
||
|
|
||
|
function ForecastExponential16(X : Double; const KnownY; const KnownX;
|
||
|
NData : Integer) : Double;
|
||
|
var
|
||
|
LF : TStLinEst;
|
||
|
begin
|
||
|
LogEst16(KnownY, KnownX, NData, LF, false);
|
||
|
Result := LF.B0*Power(LF.B1, X);
|
||
|
end;
|
||
|
|
||
|
function Intercept(const KnownY: array of Double;
|
||
|
const KnownX: array of Double) : Double;
|
||
|
begin
|
||
|
if (High(KnownY) <> High(KnownX)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Result := Intercept16(KnownY, KnownX, High(KnownY)+1);
|
||
|
end;
|
||
|
|
||
|
function Intercept16(const KnownY; const KnownX; NData : Integer) : Double;
|
||
|
var
|
||
|
LF : TStLinEst;
|
||
|
begin
|
||
|
LinEst16(KnownY, KnownX, NData, LF, false);
|
||
|
Result := LF.B0;
|
||
|
end;
|
||
|
|
||
|
function RSquared(const KnownY: array of Double;
|
||
|
const KnownX: array of Double) : Double;
|
||
|
begin
|
||
|
if (High(KnownY) <> High(KnownX)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Result := RSquared16(KnownY, KnownX, High(KnownY)+1);
|
||
|
end;
|
||
|
|
||
|
function RSquared16(const KnownY; const KnownX; NData : Integer) : Double;
|
||
|
var
|
||
|
LF : TStLinEst;
|
||
|
begin
|
||
|
LinEst16(KnownY, KnownX, NData, LF, true);
|
||
|
Result := LF.R2;
|
||
|
end;
|
||
|
|
||
|
function Slope(const KnownY: array of Double;
|
||
|
const KnownX: array of Double) : Double;
|
||
|
begin
|
||
|
if (High(KnownY) <> High(KnownX)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Result := Slope16(KnownY, KnownX, High(KnownY)+1);
|
||
|
end;
|
||
|
|
||
|
function Slope16(const KnownY; const KnownX; NData : Integer) : Double;
|
||
|
var
|
||
|
LF : TStLinEst;
|
||
|
begin
|
||
|
LinEst16(KnownY, KnownX, NData, LF, false);
|
||
|
Result := LF.B1;
|
||
|
end;
|
||
|
|
||
|
function StandardErrorY(const KnownY: array of Double;
|
||
|
const KnownX: array of Double) : Double;
|
||
|
begin
|
||
|
if (High(KnownY) <> High(KnownX)) then
|
||
|
RaiseStatError(stscStatBadCount);
|
||
|
Result := StandardErrorY16(KnownY, KnownX, High(KnownY)+1);
|
||
|
end;
|
||
|
|
||
|
function StandardErrorY16(const KnownY; const KnownX;
|
||
|
NData : Integer) : Double;
|
||
|
var
|
||
|
LF : TStLinEst;
|
||
|
begin
|
||
|
LinEst16(KnownY, KnownX, NData, LF, true);
|
||
|
Result := LF.sigma;
|
||
|
end;
|
||
|
|
||
|
{------------------------------------------------------------------------}
|
||
|
|
||
|
function BetaCf(a, b, x : Single) : Single;
|
||
|
{-Evaluates continued fraction for incomplete beta function}
|
||
|
const
|
||
|
MAXIT = 100;
|
||
|
EPS = 3.0E-7;
|
||
|
FPMIN = 1.0E-30;
|
||
|
var
|
||
|
m, m2 : Integer;
|
||
|
aa, c, d, del, h, qab, qam, qap : Double;
|
||
|
begin
|
||
|
qab := a+b;
|
||
|
qap := a+1.0;
|
||
|
qam := a-1.0;
|
||
|
c := 1.0;
|
||
|
d := 1.0-qab*x/qap;
|
||
|
if (abs(d) < FPMIN) then
|
||
|
d := FPMIN;
|
||
|
d := 1.0/d;
|
||
|
h := d;
|
||
|
for m := 1 to MAXIT do begin
|
||
|
m2 := 2*m;
|
||
|
aa := m*(b-m)*x/((qam+m2)*(a+m2));
|
||
|
d := 1.0+aa*d;
|
||
|
if (abs(d) < FPMIN) then
|
||
|
d := FPMIN;
|
||
|
c := 1.0+aa/c;
|
||
|
if (abs(c) < FPMIN) then
|
||
|
c := FPMIN;
|
||
|
d := 1.0/d;
|
||
|
h := h*d*c;
|
||
|
aa := -(a+m)*(qab+m)*x/((a+m2)*(qap+m2));
|
||
|
|
||
|
d := 1.0+aa*d;
|
||
|
if (abs(d) < FPMIN) then
|
||
|
d := FPMIN;
|
||
|
c := 1.0+aa/c;
|
||
|
if (abs(c) < FPMIN) then
|
||
|
c := FPMIN;
|
||
|
d := 1.0/d;
|
||
|
del := d*c;
|
||
|
h := h*del;
|
||
|
|
||
|
{check for convergence}
|
||
|
if (abs(del-1.0) < EPS) then
|
||
|
break;
|
||
|
if m = MAXIT then
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
end;
|
||
|
Result := h;
|
||
|
end;
|
||
|
|
||
|
function BetaDist(X, Alpha, Beta, A, B : Single) : Single;
|
||
|
var
|
||
|
bt : Double;
|
||
|
begin
|
||
|
if (X < A) or (X > B) or (A = B) or (Alpha <= 0.0) or (Beta <= 0.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
{normalize X}
|
||
|
X := (X-A)/(B-A);
|
||
|
|
||
|
{compute factors in front of continued fraction expansion}
|
||
|
if (X = 0.0) or (X = 1.0) then
|
||
|
bt := 0.0
|
||
|
else
|
||
|
bt := exp(GammaLn(Alpha+Beta)-GammaLn(Alpha)-GammaLn(Beta)+
|
||
|
Alpha*ln(X)+Beta*ln(1.0-X));
|
||
|
|
||
|
{use symmetry relationship to make continued fraction converge quickly}
|
||
|
if (X < (Alpha+1.0)/(Alpha+Beta+2.0)) then
|
||
|
Result := bt*BetaCf(Alpha, Beta, X)/Alpha
|
||
|
else
|
||
|
Result := 1.0-bt*BetaCf(Beta, Alpha, 1.0-X)/Beta;
|
||
|
end;
|
||
|
|
||
|
function Sign(a, b : Double) : Double;
|
||
|
{-Returns abs(a) if b >= 0.0, else -abs(a)}
|
||
|
begin
|
||
|
if (b >= 0.0) then
|
||
|
Result := abs(a)
|
||
|
else
|
||
|
Result := -abs(a);
|
||
|
end;
|
||
|
|
||
|
function BetaInv(Probability, Alpha, Beta, A, B : Single) : Single;
|
||
|
const
|
||
|
MAXIT = 100;
|
||
|
UNUSED = -1.11e30;
|
||
|
XACC = 3e-7;
|
||
|
var
|
||
|
j : Integer;
|
||
|
ans, fh, fl, fm, fnew, s, xh, xl, xm, xnew, dsign : Double;
|
||
|
begin
|
||
|
if (Probability < 0.0) or (Probability > 1.0) or
|
||
|
(A = B) or (Alpha <= 0.0) or (Beta <= 0.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
if (Probability = 0.0) then
|
||
|
Result := A
|
||
|
else if (Probability = 1.0) then
|
||
|
Result := B
|
||
|
else begin
|
||
|
{Ridder's method of finding the root of BetaDist = Probability}
|
||
|
fl := -Probability; {BetaDist(A, Alpha, Beta, A, B)-Probability}
|
||
|
fh := 1.0-Probability; {BetaDist(B, Alpha, Beta, A, B)-Probability}
|
||
|
xl := A;
|
||
|
xh := B;
|
||
|
ans := UNUSED;
|
||
|
|
||
|
for j := 1 to MAXIT do begin
|
||
|
xm := 0.5*(xl+xh);
|
||
|
fm := BetaDist(xm, Alpha, Beta, A, B)-Probability;
|
||
|
s := sqrt(fm*fm-fl*fh);
|
||
|
if (s = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
if (fl >= fh) then
|
||
|
dsign := 1.0
|
||
|
else
|
||
|
dsign := -1.0;
|
||
|
xnew := xm+(xm-xl)*(dsign*fm/s);
|
||
|
if (abs(xnew-ans) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
ans := xnew;
|
||
|
|
||
|
fnew := BetaDist(ans, Alpha, Beta, A, B)-Probability;
|
||
|
if (fnew = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
|
||
|
{keep root bracketed on next iteration}
|
||
|
if (Sign(fm, fnew) <> fm) then begin
|
||
|
xl := xm;
|
||
|
fl := fm;
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fl, fnew) <> fl) then begin
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fh, fnew) <> fh) then begin
|
||
|
xl := ans;
|
||
|
fl := fnew;
|
||
|
end else
|
||
|
{shouldn't get here}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
if (abs(xh-xl) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
BetaInv := A; {avoid compiler warning}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function BinomDistPmf(N, K : Integer; p : Extended) : Double;
|
||
|
{-Returns the Probability mass function of the binomial distribution}
|
||
|
begin
|
||
|
Result := Combinations(N, K)*IntPower(p, K)*IntPower(1.0-p, N-K);
|
||
|
end;
|
||
|
|
||
|
function BinomDist(NumberS, Trials : Integer; ProbabilityS : Single;
|
||
|
Cumulative : Boolean) : Single;
|
||
|
begin
|
||
|
if (Trials < 0) or (NumberS < 0) or (NumberS > Trials) or
|
||
|
(ProbabilityS < 0.0) or (ProbabilityS > 1.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
if (Cumulative) then
|
||
|
Result := 1.0+BinomDistPmf(Trials, NumberS, ProbabilityS)-
|
||
|
BetaDist(ProbabilityS, NumberS, Trials-NumberS+1, 0.0, 1.0)
|
||
|
else
|
||
|
Result := BinomDistPmf(Trials, NumberS, ProbabilityS);
|
||
|
end;
|
||
|
|
||
|
function CritBinom(Trials : Integer; ProbabilityS, Alpha : Single) : Integer;
|
||
|
var
|
||
|
s : Integer;
|
||
|
B : Double;
|
||
|
begin
|
||
|
if (Trials < 0) or (ProbabilityS < 0.0) or (ProbabilityS > 1.0) or
|
||
|
(Alpha < 0.0) or (Alpha > 1.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
B := 0.0;
|
||
|
for s := 0 to Trials do begin
|
||
|
B := B+BinomDistPmf(Trials, s, ProbabilityS);
|
||
|
if (B >= Alpha) then begin
|
||
|
Result := s;
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
{in case of roundoff problems}
|
||
|
Result := Trials;
|
||
|
end;
|
||
|
|
||
|
function GammSer(a, x : Single) : Single;
|
||
|
{-Returns the series computation for GammP}
|
||
|
const
|
||
|
MAXIT = 100;
|
||
|
EPS = 3.0E-7;
|
||
|
var
|
||
|
N : Integer;
|
||
|
sum, del, ap : Double;
|
||
|
begin
|
||
|
Result := 0.0;
|
||
|
if (x > 0.0) then begin
|
||
|
{x shouldn't be < 0.0, tested by caller}
|
||
|
ap := a;
|
||
|
sum := 1.0/a;
|
||
|
del := sum;
|
||
|
for N := 1 to MAXIT do begin
|
||
|
ap := ap+1;
|
||
|
del := del*x/ap;
|
||
|
sum := sum+del;
|
||
|
if (abs(del) < abs(sum)*EPS) then begin
|
||
|
Result := sum*exp(-X+a*ln(X)-GammaLn(a));
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function GammCf(a, x : Single) : Single;
|
||
|
{-Returns the continued fraction computation for GammP}
|
||
|
const
|
||
|
MAXIT = 100;
|
||
|
EPS = 3.0e-7;
|
||
|
FPMIN = 1.0e-30;
|
||
|
var
|
||
|
i : Integer;
|
||
|
an, b, c, d, del, h : Double;
|
||
|
begin
|
||
|
b := x+1.0-a;
|
||
|
c := 1.0/FPMIN;
|
||
|
d := 1.0/b;
|
||
|
h := d;
|
||
|
for i := 1 to MAXIT do begin
|
||
|
an := -i*(i-a);
|
||
|
b := b+2.0;
|
||
|
d := an*d+b;
|
||
|
if (abs(d) < FPMIN) then
|
||
|
d := FPMIN;
|
||
|
c := b+an/c;
|
||
|
if (abs(c) < FPMIN) then
|
||
|
c := FPMIN;
|
||
|
d := 1.0/d;
|
||
|
del := d*c;
|
||
|
h := h*del;
|
||
|
if (abs(del-1.0) < EPS) then
|
||
|
break;
|
||
|
if i = MAXIT then
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
end;
|
||
|
Result := h*exp(-x+a*ln(x)-GammaLn(a));
|
||
|
end;
|
||
|
|
||
|
function GammP(a, x : Single) : Single;
|
||
|
{-Returns the incomplete gamma function P(a, x)}
|
||
|
begin
|
||
|
if (x < 0.0) or (a <= 0.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
if (x < a+1.0) then
|
||
|
{use the series representation}
|
||
|
Result := GammSer(a, x)
|
||
|
else
|
||
|
{use the continued fraction representation}
|
||
|
Result := 1.0-GammCf(a, x);
|
||
|
end;
|
||
|
|
||
|
function ChiDist(X : Single; DegreesFreedom : Integer) : Single;
|
||
|
begin
|
||
|
if (DegreesFreedom < 1) or (X < 0.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
Result := 1.0-GammP(DegreesFreedom/2.0, X/2.0);
|
||
|
end;
|
||
|
|
||
|
function ChiInv(Probability : Single; DegreesFreedom : Integer) : Single;
|
||
|
const
|
||
|
MAXIT = 100;
|
||
|
UNUSED = -1.11e30;
|
||
|
XACC = 3e-7;
|
||
|
FACTOR = 1.6;
|
||
|
var
|
||
|
j : Integer;
|
||
|
ans, fh, fl, fm, fnew, s, xh, xl, xm, xnew, dsign : Double;
|
||
|
begin
|
||
|
if (Probability < 0.0) or (Probability > 1.0) or (DegreesFreedom < 1) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
if (Probability = 0.0) then
|
||
|
Result := 0.0
|
||
|
else begin
|
||
|
{bracket the interval}
|
||
|
xl := 0.0;
|
||
|
xh := 100.0;
|
||
|
fl := ChiDist(xl, DegreesFreedom)-Probability;
|
||
|
fh := ChiDist(xh, DegreesFreedom)-Probability;
|
||
|
for j := 1 to MAXIT do begin
|
||
|
if (fl*fh < 0.0) then
|
||
|
{bracketed the root}
|
||
|
break;
|
||
|
if (abs(fl) < abs(fh)) then begin
|
||
|
xl := xl+FACTOR*(xl-xh);
|
||
|
fl := ChiDist(xl, DegreesFreedom)-Probability;
|
||
|
end else begin
|
||
|
xh := xh+FACTOR*(xh-xl);
|
||
|
fh := ChiDist(xh, DegreesFreedom)-Probability;
|
||
|
end;
|
||
|
end;
|
||
|
if (fl*fh >= 0.0) then
|
||
|
{couldn't bracket it, means Probability too close to 1.0}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
{Ridder's method of finding the root of ChiDist = Probability}
|
||
|
ans := UNUSED;
|
||
|
|
||
|
for j := 1 to MAXIT do begin
|
||
|
xm := 0.5*(xl+xh);
|
||
|
fm := ChiDist(xm, DegreesFreedom)-Probability;
|
||
|
s := sqrt(fm*fm-fl*fh);
|
||
|
if (s = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
if (fl >= fh) then
|
||
|
dsign := 1.0
|
||
|
else
|
||
|
dsign := -1.0;
|
||
|
xnew := xm+(xm-xl)*(dsign*fm/s);
|
||
|
if (abs(xnew-ans) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
ans := xnew;
|
||
|
|
||
|
fnew := ChiDist(ans, DegreesFreedom)-Probability;
|
||
|
if (fnew = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
|
||
|
{keep root bracketed on next iteration}
|
||
|
if (Sign(fm, fnew) <> fm) then begin
|
||
|
xl := xm;
|
||
|
fl := fm;
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fl, fnew) <> fl) then begin
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fh, fnew) <> fh) then begin
|
||
|
xl := ans;
|
||
|
fl := fnew;
|
||
|
end else
|
||
|
{shouldn't get here}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
if (abs(xh-xl) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
Result := 0.0; {avoid compiler warning}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function ExponDist(X, Lambda : Single; Cumulative : Boolean) : Single;
|
||
|
begin
|
||
|
if (X < 0.0) or (Lambda <= 0.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
if (Cumulative) then
|
||
|
Result := 1.0-exp(-Lambda*X)
|
||
|
else
|
||
|
Result := Lambda*exp(-Lambda*X);
|
||
|
end;
|
||
|
|
||
|
function FDist(X : Single;
|
||
|
DegreesFreedom1, DegreesFreedom2 : Integer) : Single;
|
||
|
begin
|
||
|
if (X < 0) or (DegreesFreedom1 < 1) or (DegreesFreedom2 < 1) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
Result := BetaDist(DegreesFreedom2/(DegreesFreedom2+DegreesFreedom1*X),
|
||
|
DegreesFreedom2/2.0, DegreesFreedom1/2.0, 0.0, 1.0);
|
||
|
end;
|
||
|
|
||
|
function FInv(Probability : Single;
|
||
|
DegreesFreedom1, DegreesFreedom2 : Integer) : Single;
|
||
|
const
|
||
|
MAXIT = 100;
|
||
|
UNUSED = -1.11e30;
|
||
|
XACC = 3e-7;
|
||
|
FACTOR = 1.6;
|
||
|
var
|
||
|
j : Integer;
|
||
|
ans, fh, fl, fm, fnew, s, xh, xl, xm, xnew, dsign : Double;
|
||
|
begin
|
||
|
if (Probability < 0.0) or (Probability > 1.0) or
|
||
|
(DegreesFreedom1 < 1) or (DegreesFreedom2 < 1) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
if (Probability = 1.0) then
|
||
|
Result := 0.0
|
||
|
else begin
|
||
|
{bracket the interval}
|
||
|
xl := 0.0;
|
||
|
xh := 100.0;
|
||
|
fl := FDist(xl, DegreesFreedom1, DegreesFreedom2)-Probability;
|
||
|
fh := FDist(xh, DegreesFreedom1, DegreesFreedom2)-Probability;
|
||
|
for j := 1 to MAXIT do begin
|
||
|
if (fl*fh < 0.0) then
|
||
|
{bracketed the root}
|
||
|
break;
|
||
|
if (abs(fl) < abs(fh)) then begin
|
||
|
xl := xl+FACTOR*(xl-xh);
|
||
|
fl := FDist(xl, DegreesFreedom1, DegreesFreedom2)-Probability;
|
||
|
end else begin
|
||
|
xh := xh+FACTOR*(xh-xl);
|
||
|
fh := FDist(xh, DegreesFreedom1, DegreesFreedom2)-Probability;
|
||
|
end;
|
||
|
end;
|
||
|
if (fl*fh >= 0.0) then
|
||
|
{couldn't bracket it, means Probability too close to 0.0}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
{Ridder's method of finding the root of FDist = Probability}
|
||
|
ans := UNUSED;
|
||
|
|
||
|
for j := 1 to MAXIT do begin
|
||
|
xm := 0.5*(xl+xh);
|
||
|
fm := FDist(xm, DegreesFreedom1, DegreesFreedom2)-Probability;
|
||
|
s := sqrt(fm*fm-fl*fh);
|
||
|
if (s = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
if (fl >= fh) then
|
||
|
dsign := 1.0
|
||
|
else
|
||
|
dsign := -1.0;
|
||
|
xnew := xm+(xm-xl)*(dsign*fm/s);
|
||
|
if (abs(xnew-ans) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
ans := xnew;
|
||
|
|
||
|
fnew := FDist(ans, DegreesFreedom1, DegreesFreedom2)-Probability;
|
||
|
if (fnew = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
|
||
|
{keep root bracketed on next iteration}
|
||
|
if (Sign(fm, fnew) <> fm) then begin
|
||
|
xl := xm;
|
||
|
fl := fm;
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fl, fnew) <> fl) then begin
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fh, fnew) <> fh) then begin
|
||
|
xl := ans;
|
||
|
fl := fnew;
|
||
|
end else
|
||
|
{shouldn't get here}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
if (abs(xh-xl) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
Result := 0.0; {avoid compiler warning}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function LogNormDist(X, Mean, StandardDev : Single) : Single;
|
||
|
begin
|
||
|
if (X <= 0.0) or (StandardDev <= 0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
Result := NormSDist((ln(X)-Mean)/StandardDev);
|
||
|
end;
|
||
|
|
||
|
function LogInv(Probability, Mean, StandardDev : Single) : Single;
|
||
|
begin
|
||
|
if (Probability < 0.0) or (Probability > 1.0) or (StandardDev <= 0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
Result := exp(Mean+StandardDev*NormSInv(Probability));
|
||
|
end;
|
||
|
|
||
|
function NormDist(X, Mean, StandardDev : Single;
|
||
|
Cumulative : Boolean) : Single;
|
||
|
var
|
||
|
Z : Extended;
|
||
|
begin
|
||
|
if (StandardDev <= 0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
Z := (X-Mean)/StandardDev;
|
||
|
if (Cumulative) then
|
||
|
Result := NormSDist(Z)
|
||
|
else
|
||
|
Result := exp(-Z*Z/2.0)/(StandardDev*sqrt2pi);
|
||
|
end;
|
||
|
|
||
|
function NormInv(Probability, Mean, StandardDev : Single) : Single;
|
||
|
begin
|
||
|
if (Probability < 0.0) or (Probability > 1.0) or (StandardDev <= 0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
Result := Mean+StandardDev*NormSInv(Probability);
|
||
|
end;
|
||
|
|
||
|
function Erfc(X : Single) : Single;
|
||
|
var
|
||
|
t, z, ans : Double;
|
||
|
begin
|
||
|
z := abs(X);
|
||
|
t := 1.0/(1.0+0.5*z);
|
||
|
ans := t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+
|
||
|
t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+
|
||
|
t*(-0.82215223+t*0.17087277)))))))));
|
||
|
if (X >= 0.0) then
|
||
|
Result := ans
|
||
|
else
|
||
|
Result := 2.0-ans;
|
||
|
end;
|
||
|
|
||
|
function NormSDist(Z : Single) : Single;
|
||
|
const
|
||
|
sqrt2 = 1.41421356237310;
|
||
|
begin
|
||
|
Result := 1.0-0.5*Erfc(Z/sqrt2);
|
||
|
end;
|
||
|
|
||
|
function NormSInv(Probability : Single) : Single;
|
||
|
const
|
||
|
MAXIT = 100;
|
||
|
UNUSED = -1.11e30;
|
||
|
XACC = 3e-7;
|
||
|
FACTOR = 1.6;
|
||
|
var
|
||
|
j : Integer;
|
||
|
ans, fh, fl, fm, fnew, s, xh, xl, xm, xnew, dsign : Double;
|
||
|
begin
|
||
|
if (Probability < 0.0) or (Probability > 1.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
Result := 0.0;
|
||
|
|
||
|
{bracket the interval}
|
||
|
xl := -2.0;
|
||
|
xh := +2.0;
|
||
|
fl := NormSDist(xl)-Probability;
|
||
|
fh := NormSDist(xh)-Probability;
|
||
|
for j := 1 to MAXIT do begin
|
||
|
if (fl*fh < 0.0) then
|
||
|
{bracketed the root}
|
||
|
break;
|
||
|
if (abs(fl) < abs(fh)) then begin
|
||
|
xl := xl+FACTOR*(xl-xh);
|
||
|
fl := NormSDist(xl)-Probability;
|
||
|
end else begin
|
||
|
xh := xh+FACTOR*(xh-xl);
|
||
|
fh := NormSDist(xh)-Probability;
|
||
|
end;
|
||
|
end;
|
||
|
if (fl*fh >= 0.0) then
|
||
|
{couldn't bracket it, means Probability too close to 0.0 or 1.0}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
{Ridder's method of finding the root of NormSDist = Probability}
|
||
|
ans := UNUSED;
|
||
|
|
||
|
for j := 1 to MAXIT do begin
|
||
|
xm := 0.5*(xl+xh);
|
||
|
fm := NormSDist(xm)-Probability;
|
||
|
s := sqrt(fm*fm-fl*fh);
|
||
|
if (s = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
if (fl >= fh) then
|
||
|
dsign := 1.0
|
||
|
else
|
||
|
dsign := -1.0;
|
||
|
xnew := xm+(xm-xl)*(dsign*fm/s);
|
||
|
if (abs(xnew-ans) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
ans := xnew;
|
||
|
|
||
|
fnew := NormSDist(ans)-Probability;
|
||
|
if (fnew = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
|
||
|
{keep root bracketed on next iteration}
|
||
|
if (Sign(fm, fnew) <> fm) then begin
|
||
|
xl := xm;
|
||
|
fl := fm;
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fl, fnew) <> fl) then begin
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fh, fnew) <> fh) then begin
|
||
|
xl := ans;
|
||
|
fl := fnew;
|
||
|
end else
|
||
|
{shouldn't get here}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
if (abs(xh-xl) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
end;
|
||
|
|
||
|
function Poisson(X : Integer; Mean : Single; Cumulative : Boolean) : Single;
|
||
|
begin
|
||
|
if (X < 0) or (Mean <= 0.0) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
if (Cumulative) then
|
||
|
Result := 1.0-GammP(X+1.0, Mean)
|
||
|
else
|
||
|
Result := IntPower(Mean, X)*exp(-Mean)/Factorial(X);
|
||
|
end;
|
||
|
|
||
|
function TDist(X : Single; DegreesFreedom : Integer;
|
||
|
TwoTails : Boolean) : Single;
|
||
|
var
|
||
|
a : Double;
|
||
|
begin
|
||
|
if (DegreesFreedom < 1) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
a := BetaDist(DegreesFreedom/(DegreesFreedom+X*X), DegreesFreedom/2.0,
|
||
|
0.5, 0.0, 1.0);
|
||
|
if TwoTails then
|
||
|
Result := a
|
||
|
else
|
||
|
Result := 0.5*a;
|
||
|
end;
|
||
|
|
||
|
function TInv(Probability : Single; DegreesFreedom : Integer) : Single;
|
||
|
const
|
||
|
MAXIT = 100;
|
||
|
UNUSED = -1.11e30;
|
||
|
XACC = 3e-7;
|
||
|
FACTOR = 1.6;
|
||
|
var
|
||
|
j : Integer;
|
||
|
ans, fh, fl, fm, fnew, s, xh, xl, xm, xnew, dsign : Double;
|
||
|
begin
|
||
|
if (Probability < 0.0) or (Probability > 1.0) or (DegreesFreedom < 1) then
|
||
|
RaiseStatError(stscStatBadParam);
|
||
|
|
||
|
Result := 0.0;
|
||
|
if (Probability = 1.0) then
|
||
|
exit;
|
||
|
|
||
|
{bracket the interval}
|
||
|
xl := 0.0;
|
||
|
xh := +2.0;
|
||
|
fl := TDist(xl, DegreesFreedom, true)-Probability;
|
||
|
fh := TDist(xh, DegreesFreedom, true)-Probability;
|
||
|
for j := 1 to MAXIT do begin
|
||
|
if (fl*fh < 0.0) then
|
||
|
{bracketed the root}
|
||
|
break;
|
||
|
if (abs(fl) < abs(fh)) then begin
|
||
|
xl := xl+FACTOR*(xl-xh);
|
||
|
fl := TDist(xl, DegreesFreedom, true)-Probability;
|
||
|
end else begin
|
||
|
xh := xh+FACTOR*(xh-xl);
|
||
|
fh := TDist(xh, DegreesFreedom, true)-Probability;
|
||
|
end;
|
||
|
end;
|
||
|
if (fl*fh >= 0.0) then
|
||
|
{couldn't bracket it, means Probability too close to 1.0}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
{Ridder's method of finding the root of TDist = Probability}
|
||
|
ans := UNUSED;
|
||
|
|
||
|
for j := 1 to MAXIT do begin
|
||
|
xm := 0.5*(xl+xh);
|
||
|
fm := TDist(xm, DegreesFreedom, true)-Probability;
|
||
|
s := sqrt(fm*fm-fl*fh);
|
||
|
if (s = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
if (fl >= fh) then
|
||
|
dsign := 1.0
|
||
|
else
|
||
|
dsign := -1.0;
|
||
|
xnew := xm+(xm-xl)*(dsign*fm/s);
|
||
|
if (abs(xnew-ans) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
ans := xnew;
|
||
|
|
||
|
fnew := TDist(ans, DegreesFreedom, true)-Probability;
|
||
|
if (fnew = 0.0) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
|
||
|
{keep root bracketed on next iteration}
|
||
|
if (Sign(fm, fnew) <> fm) then begin
|
||
|
xl := xm;
|
||
|
fl := fm;
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fl, fnew) <> fl) then begin
|
||
|
xh := ans;
|
||
|
fh := fnew;
|
||
|
end else if (Sign(fh, fnew) <> fh) then begin
|
||
|
xl := ans;
|
||
|
fl := fnew;
|
||
|
end else
|
||
|
{shouldn't get here}
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
|
||
|
if (abs(xh-xl) <= XACC) then begin
|
||
|
Result := ans;
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
RaiseStatError(stscStatNoConverge);
|
||
|
end;
|
||
|
|
||
|
procedure Initialize;
|
||
|
{-Fully initializes factorial lookup tables}
|
||
|
var
|
||
|
i : Integer;
|
||
|
begin
|
||
|
FactA[2] := 2.0;
|
||
|
for i := 3 to MFactA do
|
||
|
FactA[i] := i*FactA[i-1];
|
||
|
for i := 2 to MFactLna do
|
||
|
FactLnA[i] := GammaLn(i+1.0);
|
||
|
end;
|
||
|
|
||
|
initialization
|
||
|
Initialize;
|
||
|
end.
|