📄 math.pas
字号:
function IsInfinite(const AValue: Double): Boolean;
begin
Result := ((PInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and
((PInt64(@AValue)^ and $000FFFFFFFFFFFFF) = $0000000000000000)
end;
{ Statistical functions }
function Mean(const Data: array of Double): Extended;
begin
Result := SUM(Data) / (High(Data) - Low(Data) + 1)
end;
function MinValue(const Data: array of Double): Double;
var
I: Integer;
begin
Result := Data[Low(Data)];
for I := Low(Data) + 1 to High(Data) do
if Result > Data[I] then
Result := Data[I];
end;
function MinIntValue(const Data: array of Integer): Integer;
var
I: Integer;
begin
Result := Data[Low(Data)];
for I := Low(Data) + 1 to High(Data) do
if Result > Data[I] then
Result := Data[I];
end;
function Min(const A, B: Integer): Integer;
begin
if A < B then
Result := A
else
Result := B;
end;
function Min(const A, B: Int64): Int64;
begin
if A < B then
Result := A
else
Result := B;
end;
function Min(const A, B: Single): Single;
begin
if A < B then
Result := A
else
Result := B;
end;
function Min(const A, B: Double): Double;
begin
if A < B then
Result := A
else
Result := B;
end;
function Min(const A, B: Extended): Extended;
begin
if A < B then
Result := A
else
Result := B;
end;
function MaxValue(const Data: array of Double): Double;
var
I: Integer;
begin
Result := Data[Low(Data)];
for I := Low(Data) + 1 to High(Data) do
if Result < Data[I] then
Result := Data[I];
end;
function MaxIntValue(const Data: array of Integer): Integer;
var
I: Integer;
begin
Result := Data[Low(Data)];
for I := Low(Data) + 1 to High(Data) do
if Result < Data[I] then
Result := Data[I];
end;
function Max(const A, B: Integer): Integer;
begin
if A > B then
Result := A
else
Result := B;
end;
function Max(const A, B: Int64): Int64;
begin
if A > B then
Result := A
else
Result := B;
end;
function Max(const A, B: Single): Single;
begin
if A > B then
Result := A
else
Result := B;
end;
function Max(const A, B: Double): Double;
begin
if A > B then
Result := A
else
Result := B;
end;
function Max(const A, B: Extended): Extended;
begin
if A > B then
Result := A
else
Result := B;
end;
function Sign(const AValue: Integer): TValueSign;
begin
Result := ZeroValue;
if AValue < 0 then
Result := NegativeValue
else if AValue > 0 then
Result := PositiveValue;
end;
function Sign(const AValue: Int64): TValueSign;
begin
Result := ZeroValue;
if AValue < 0 then
Result := NegativeValue
else if AValue > 0 then
Result := PositiveValue;
end;
function Sign(const AValue: Double): TValueSign;
begin
if ((PInt64(@AValue)^ and $7FFFFFFFFFFFFFFF) = $0000000000000000) then
Result := ZeroValue
else if ((PInt64(@AValue)^ and $8000000000000000) = $8000000000000000) then
Result := NegativeValue
else
Result := PositiveValue;
end;
const
FuzzFactor = 1000;
ExtendedResolution = 1E-19 * FuzzFactor;
DoubleResolution = 1E-15 * FuzzFactor;
SingleResolution = 1E-7 * FuzzFactor;
function CompareValue(const A, B: Extended; Epsilon: Extended): TValueRelationship;
begin
if SameValue(A, B, Epsilon) then
Result := EqualsValue
else if A < B then
Result := LessThanValue
else
Result := GreaterThanValue;
end;
function CompareValue(const A, B: Double; Epsilon: Double): TValueRelationship;
begin
if SameValue(A, B, Epsilon) then
Result := EqualsValue
else if A < B then
Result := LessThanValue
else
Result := GreaterThanValue;
end;
function CompareValue(const A, B: Single; Epsilon: Single): TValueRelationship;
begin
if SameValue(A, B, Epsilon) then
Result := EqualsValue
else if A < B then
Result := LessThanValue
else
Result := GreaterThanValue;
end;
function CompareValue(const A, B: Integer): TValueRelationship;
begin
if A = B then
Result := EqualsValue
else if A < B then
Result := LessThanValue
else
Result := GreaterThanValue;
end;
function CompareValue(const A, B: Int64): TValueRelationship;
begin
if A = B then
Result := EqualsValue
else if A < B then
Result := LessThanValue
else
Result := GreaterThanValue;
end;
function SameValue(const A, B: Extended; Epsilon: Extended): Boolean;
begin
if Epsilon = 0 then
Epsilon := Min(Abs(A), Abs(B)) * ExtendedResolution;
Result := Abs(A - B) < Epsilon;
end;
function SameValue(const A, B: Double; Epsilon: Double): Boolean;
begin
if Epsilon = 0 then
Epsilon := Min(Abs(A), Abs(B)) * DoubleResolution;
Result := Abs(A - B) < Epsilon;
end;
function SameValue(const A, B: Single; Epsilon: Single): Boolean;
begin
if Epsilon = 0 then
Epsilon := Min(Abs(A), Abs(B)) * SingleResolution;
Result := Abs(A - B) < Epsilon;
end;
function IsZero(const A: Extended; Epsilon: Extended): Boolean;
begin
if Epsilon = 0 then
Epsilon := ExtendedResolution;
Result := Abs(A) < Epsilon;
end;
function IsZero(const A: Double; Epsilon: Double): Boolean;
begin
if Epsilon = 0 then
Epsilon := DoubleResolution;
Result := Abs(A) < Epsilon;
end;
function IsZero(const A: Single; Epsilon: Single): Boolean;
begin
if Epsilon = 0 then
Epsilon := SingleResolution;
Result := Abs(A) < Epsilon;
end;
function IfThen(AValue: Boolean; const ATrue: Integer; const AFalse: Integer): Integer;
begin
if AValue then
Result := ATrue
else
Result := AFalse;
end;
function IfThen(AValue: Boolean; const ATrue: Int64; const AFalse: Int64): Int64;
begin
if AValue then
Result := ATrue
else
Result := AFalse;
end;
function IfThen(AValue: Boolean; const ATrue: Double; const AFalse: Double): Double;
begin
if AValue then
Result := ATrue
else
Result := AFalse;
end;
function RandomRange(const AFrom, ATo: Integer): Integer;
begin
if AFrom > ATo then
Result := Random(AFrom - ATo) + ATo
else
Result := Random(ATo - AFrom) + AFrom;
end;
function RandomFrom(const AValues: array of Integer): Integer;
begin
Result := AValues[Random(High(AValues) + 1)];
end;
function RandomFrom(const AValues: array of Int64): Int64;
begin
Result := AValues[Random(High(AValues) + 1)];
end;
function RandomFrom(const AValues: array of Double): Double;
begin
Result := AValues[Random(High(AValues) + 1)];
end;
{ Range testing functions }
function InRange(const AValue, AMin, AMax: Integer): Boolean;
begin
Result := (AValue >= AMin) and (AValue <= AMax);
end;
function InRange(const AValue, AMin, AMax: Int64): Boolean;
begin
Result := (AValue >= AMin) and (AValue <= AMax);
end;
function InRange(const AValue, AMin, AMax: Double): Boolean;
begin
Result := (AValue >= AMin) and (AValue <= AMax);
end;
{ Range truncation functions }
function EnsureRange(const AValue, AMin, AMax: Integer): Integer;
begin
Result := AValue;
assert(AMin <= AMax);
if Result < AMin then
Result := AMin;
if Result > AMax then
Result := AMax;
end;
function EnsureRange(const AValue, AMin, AMax: Int64): Int64;
begin
Result := AValue;
assert(AMin <= AMax);
if Result < AMin then
Result := AMin;
if Result > AMax then
Result := AMax;
end;
function EnsureRange(const AValue, AMin, AMax: Double): Double;
begin
Result := AValue;
assert(AMin <= AMax);
if Result < AMin then
Result := AMin;
if Result > AMax then
Result := AMax;
end;
procedure MeanAndStdDev(const Data: array of Double; var Mean, StdDev: Extended);
var
S: Extended;
N,I: Integer;
begin
N := High(Data)- Low(Data) + 1;
if N = 1 then
begin
Mean := Data[0];
StdDev := Data[0];
Exit;
end;
Mean := Sum(Data) / N;
S := 0; // sum differences from the mean, for greater accuracy
for I := Low(Data) to High(Data) do
S := S + Sqr(Mean - Data[I]);
StdDev := Sqrt(S / (N - 1));
end;
procedure MomentSkewKurtosis(const Data: array of Double;
var M1, M2, M3, M4, Skew, Kurtosis: Extended);
var
Sum, SumSquares, SumCubes, SumQuads, OverN, Accum, M1Sqr, S2N, S3N: Extended;
I: Integer;
begin
OverN := 1 / (High(Data) - Low(Data) + 1);
Sum := 0;
SumSquares := 0;
SumCubes := 0;
SumQuads := 0;
for I := Low(Data) to High(Data) do
begin
Sum := Sum + Data[I];
Accum := Sqr(Data[I]);
SumSquares := SumSquares + Accum;
Accum := Accum*Data[I];
SumCubes := SumCubes + Accum;
SumQuads := SumQuads + Accum*Data[I];
end;
M1 := Sum * OverN;
M1Sqr := Sqr(M1);
S2N := SumSquares * OverN;
S3N := SumCubes * OverN;
M2 := S2N - M1Sqr;
M3 := S3N - (M1 * 3 * S2N) + 2*M1Sqr*M1;
M4 := (SumQuads * OverN) - (M1 * 4 * S3N) + (M1Sqr*6*S2N - 3*Sqr(M1Sqr));
Skew := M3 * Power(M2, -3/2); // = M3 / Power(M2, 3/2)
Kurtosis := M4 / Sqr(M2);
end;
function Norm(const Data: array of Double): Extended;
begin
Result := Sqrt(SumOfSquares(Data));
end;
function PopnStdDev(const Data: array of Double): Extended;
begin
Result := Sqrt(PopnVariance(Data))
end;
function PopnVariance(const Data: array of Double): Extended;
begin
Result := TotalVariance(Data) / (High(Data) - Low(Data) + 1)
end;
function RandG(Mean, StdDev: Extended): Extended;
{ Marsaglia-Bray algorithm }
var
U1, S2: Extended;
begin
repeat
U1 := 2*Random - 1;
S2 := Sqr(U1) + Sqr(2*Random-1);
until S2 < 1;
Result := Sqrt(-2*Ln(S2)/S2) * U1 * StdDev + Mean;
end;
function StdDev(const Data: array of Double): Extended;
begin
Result := Sqrt(Variance(Data))
end;
procedure RaiseOverflowError; forward;
function SumInt(const Data: array of Integer): Integer;
asm // IN: EAX = ptr to Data, EDX = High(Data) = Count - 1
// loop unrolled 4 times, 5 clocks per loop, 1.2 clocks per datum
PUSH EBX
MOV ECX, EAX // ecx = ptr to data
MOV EBX, EDX
XOR EAX, EAX
AND EDX, not 3
AND EBX, 3
SHL EDX, 2
JMP @Vector.Pointer[EBX*4]
@Vector:
DD @@1
DD @@2
DD @@3
DD @@4
@@4:
ADD EAX, [ECX+12+EDX]
JO RaiseOverflowError
@@3:
ADD EAX, [ECX+8+EDX]
JO RaiseOverflowError
@@2:
ADD EAX, [ECX+4+EDX]
JO RaiseOverflowError
@@1:
ADD EAX, [ECX+EDX]
JO RaiseOverflowError
SUB EDX,16
JNS @@4
POP EBX
end;
procedure RaiseOverflowError;
begin
raise EIntOverflow.Create(SIntOverflow);
end;
function SUM(const Data: array of Double): Extended;
asm // IN: EAX = ptr to Data, EDX = High(Data) = Count - 1
// Uses 4 accumulators to minimize read-after-write delays and loop overhead
// 5 clocks per loop, 4 items per loop = 1.2 clocks per item
FLDZ
MOV ECX, EDX
FLD ST(0)
AND EDX, not 3
FLD ST(0)
AND ECX, 3
FLD ST(0)
SHL EDX, 3 // count * sizeof(Double) = count * 8
JMP @Vector.Pointer[ECX*4]
@Vector:
DD @@1
DD @@2
DD @@3
DD @@4
@@4: FADD qword ptr [EAX+EDX+24] // 1
FXCH ST(3) // 0
@@3: FADD qword ptr [EAX+EDX+16] // 1
FXCH ST(2) // 0
@@2: FADD qword ptr [EAX+EDX+8] // 1
FXCH ST(1) // 0
@@1: FADD qword ptr [EAX+EDX] // 1
FXCH ST(2) // 0
SUB EDX, 32
JNS @@4
FADDP ST(3),ST // ST(3) := ST + ST(3); Pop ST
FADD // ST(1) := ST + ST(1); Pop ST
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -