Extended math RTL
This commit is contained in:
+77
-41
@@ -1,9 +1,15 @@
|
|||||||
(do
|
(do
|
||||||
;; ===========================================================================
|
;; ===========================================================================
|
||||||
;; 1. DEFINITIONEN (Wie zuvor besprochen)
|
;; 1. DEFINITIONEN
|
||||||
;; ===========================================================================
|
;; ===========================================================================
|
||||||
|
|
||||||
;; --- WMA Factory (O(1)) ---
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Factory: create-wma
|
||||||
|
;; Berechnet WMA. Wartet, bis das Fenster voll ist.
|
||||||
|
;; Phase 1: Warten (< len)
|
||||||
|
;; Phase 2: Init (= len) -> Loop berechnung
|
||||||
|
;; Phase 3: Slide (> len) -> O(1) berechnung
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
(def create-wma
|
(def create-wma
|
||||||
(fn [len]
|
(fn [len]
|
||||||
(do
|
(do
|
||||||
@@ -14,17 +20,51 @@
|
|||||||
(fn [src]
|
(fn [src]
|
||||||
(do
|
(do
|
||||||
(def cnt (count src))
|
(def cnt (count src))
|
||||||
(if (< cnt (+ len 1))
|
|
||||||
0.0
|
;; PHASE 1: Nicht genug Daten
|
||||||
(do
|
(if (< cnt len)
|
||||||
(def val-new (get src 0))
|
NaN
|
||||||
(def val-out (get src len))
|
|
||||||
(def w-sum (+ prev-w-sum (- (* len val-new) prev-s-sum)))
|
;; Genug Daten vorhanden
|
||||||
(def s-sum (+ (- prev-s-sum val-out) val-new))
|
(if (= cnt len)
|
||||||
(assign prev-w-sum w-sum)
|
;; PHASE 2: Initialisierung (Das Fenster ist gerade voll geworden)
|
||||||
(assign prev-s-sum s-sum)
|
;; Wir müssen einmalig die Basis-Summen berechnen.
|
||||||
(/ w-sum weight-div)
|
(do
|
||||||
))
|
(def init-w 0.0)
|
||||||
|
(def init-s 0.0)
|
||||||
|
|
||||||
|
;; Loop über die Elemente 0 bis len-1
|
||||||
|
((fn [i]
|
||||||
|
(if (< i len)
|
||||||
|
(do
|
||||||
|
(def val (get src i))
|
||||||
|
;; Gewichtung: Index 0 ist das neueste -> Gewicht 'len'
|
||||||
|
(assign init-w (+ init-w (* (- len i) val)))
|
||||||
|
(assign init-s (+ init-s val))
|
||||||
|
(recur (+ i 1)))
|
||||||
|
)) 0)
|
||||||
|
|
||||||
|
;; State speichern
|
||||||
|
(assign prev-w-sum init-w)
|
||||||
|
(assign prev-s-sum init-s)
|
||||||
|
(/ init-w weight-div))
|
||||||
|
|
||||||
|
;; PHASE 3: Sliding Window (O(1))
|
||||||
|
;; Wir haben bereits einen gültigen State aus dem vorherigen Schritt.
|
||||||
|
(do
|
||||||
|
(def val-new (get src 0)) ; Neuster Wert
|
||||||
|
(def val-out (get src len)) ; Wert der rausfällt
|
||||||
|
|
||||||
|
;; Update Formeln
|
||||||
|
(def w-sum (+ prev-w-sum (- (* len val-new) prev-s-sum)))
|
||||||
|
(def s-sum (+ (- prev-s-sum val-out) val-new))
|
||||||
|
|
||||||
|
;; State speichern
|
||||||
|
(assign prev-w-sum w-sum)
|
||||||
|
(assign prev-s-sum s-sum)
|
||||||
|
(/ w-sum weight-div))
|
||||||
|
)
|
||||||
|
)
|
||||||
))
|
))
|
||||||
)))
|
)))
|
||||||
|
|
||||||
@@ -34,18 +74,26 @@
|
|||||||
(do
|
(do
|
||||||
(def half-len (round (/ len 2)))
|
(def half-len (round (/ len 2)))
|
||||||
(def sqrt-len (round (sqrt len)))
|
(def sqrt-len (round (sqrt len)))
|
||||||
|
|
||||||
(def wma-half (create-wma half-len))
|
(def wma-half (create-wma half-len))
|
||||||
(def wma-full (create-wma len))
|
(def wma-full (create-wma len))
|
||||||
(def wma-smooth (create-wma sqrt-len))
|
(def wma-smooth (create-wma sqrt-len))
|
||||||
|
|
||||||
(def diff-series (new-series [[:val :Float]]))
|
(def diff-series (new-series [[:val :Float]]))
|
||||||
|
|
||||||
(fn [src]
|
(fn [src]
|
||||||
(do
|
(do
|
||||||
(def v1 (wma-half src))
|
(def v1 (wma-half src))
|
||||||
(def v2 (wma-full src))
|
(def v2 (wma-full src))
|
||||||
|
|
||||||
|
;; WICHTIG: Wir dürfen erst weitermachen, wenn BEIDE WMAs gültig sind.
|
||||||
|
;; Da v2 das längere Fenster (len) braucht, diktiert es den Takt.
|
||||||
(def diff (- (* 2 v1) v2))
|
(def diff (- (* 2 v1) v2))
|
||||||
(add-item diff-series {:val diff})
|
(if (not (is-NaN diff))
|
||||||
(wma-smooth (get diff-series :val))
|
(add-item diff-series {:val diff}))
|
||||||
|
|
||||||
|
;; Glättung auf dem Resultat
|
||||||
|
(wma-smooth (.val diff-series))
|
||||||
))
|
))
|
||||||
)))
|
)))
|
||||||
|
|
||||||
@@ -59,45 +107,33 @@
|
|||||||
~n))
|
~n))
|
||||||
|
|
||||||
;; ===========================================================================
|
;; ===========================================================================
|
||||||
;; 2. SIMULATION & TEST
|
;; 2. SIMULATION
|
||||||
;; ===========================================================================
|
;; ===========================================================================
|
||||||
|
|
||||||
;; Konfiguration
|
(def hma-length 250)
|
||||||
(def hma-length 14)
|
(def simulation-steps 5000)
|
||||||
(def simulation-steps 50)
|
|
||||||
|
|
||||||
;; Initialisierung der Komponenten
|
(def hma-calc (create-hma hma-length))
|
||||||
(def hma-calc (create-hma hma-length)) ; Die HMA-Closure
|
(def prices (new-series [[:close :Float]]))
|
||||||
(def prices (new-series [[:close :Float]])) ; Die Preis-Series
|
(def current-price 100.0)
|
||||||
(def current-price 100.0) ; Startpreis
|
|
||||||
|
|
||||||
;; Header Ausgabe (falls print verfügbar ist)
|
|
||||||
(print "Step | Price | HMA(14)")
|
(print "Step | Price | HMA(14)")
|
||||||
(print "-----|----------|----------")
|
(print "-----|----------|----------")
|
||||||
|
|
||||||
;; Simulations-Schleife
|
|
||||||
(repeat simulation-steps
|
(repeat simulation-steps
|
||||||
(do
|
(do
|
||||||
;; 1. Preis simulieren (Random Walk)
|
;; Random Walk
|
||||||
;; (random) gibt 0.0 bis 1.0 zurück.
|
|
||||||
;; (- (random) 0.5) erzeugt eine Änderung zwischen -0.5 und +0.5
|
|
||||||
(assign current-price (+ current-price (- (random) 0.5)))
|
(assign current-price (+ current-price (- (random) 0.5)))
|
||||||
|
|
||||||
;; 2. Preis zur Series hinzufügen
|
|
||||||
(add-item prices {:close current-price})
|
(add-item prices {:close current-price})
|
||||||
|
|
||||||
;; 3. HMA berechnen
|
;; Berechnung
|
||||||
(def hma-val 0.0)
|
;; Nutzung von Member Access (.close), da es eine Record-Series ist
|
||||||
|
(def hma-val (hma-calc (.close prices)))
|
||||||
|
|
||||||
;; 3. HMA berechnen
|
;; Ausgabe
|
||||||
(def price-series (get prices :close))
|
(if (not (is-NaN hma-val))
|
||||||
(assign hma-val (hma-calc price-series))
|
(print (count prices) " |" current-price " | " hma-val)
|
||||||
|
)
|
||||||
;; 4. Ausgabe
|
|
||||||
;; Wir geben nur Werte aus, wenn der HMA "eingeschwungen" ist (Wert > 0)
|
|
||||||
(if (> hma-val 0.0)
|
|
||||||
(print (count prices) " |" current-price " | " hma-val)
|
|
||||||
(print (count prices) " |" current-price " | (warming up...)"))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -14,9 +14,17 @@ type
|
|||||||
public
|
public
|
||||||
// --- Constants ---
|
// --- Constants ---
|
||||||
|
|
||||||
|
[TRtlConst('false')]
|
||||||
|
[AstDoc('Boolean false.')]
|
||||||
|
class function CFalse: Boolean; static;
|
||||||
|
|
||||||
|
[TRtlConst('true')]
|
||||||
|
[AstDoc('Boolean true.')]
|
||||||
|
class function CTrue: Boolean; static;
|
||||||
|
|
||||||
[TRtlConst('NaN')]
|
[TRtlConst('NaN')]
|
||||||
[AstDoc('Not a Number (IEEE 754).')]
|
[AstDoc('Not a Number (IEEE 754).')]
|
||||||
class function Const_NaN: Double; static;
|
class function CNaN: Double; static;
|
||||||
|
|
||||||
// --- Arithmetic Operators ---
|
// --- Arithmetic Operators ---
|
||||||
|
|
||||||
@@ -38,17 +46,17 @@ type
|
|||||||
class function Multiply(const Args: TArray<TDataValue>): TDataValue; static;
|
class function Multiply(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
[TRtlExport('/', Pure)]
|
[TRtlExport('/', Pure)]
|
||||||
[AstDoc('Divides A by B. Always returns a floating point number.')]
|
[AstDoc('Divides A by B. Returns NaN on division by zero.')]
|
||||||
[AstSignature('(number, number) -> number')]
|
[AstSignature('(number, number) -> number')]
|
||||||
class function Divide(const Args: TArray<TDataValue>): TDataValue; static;
|
class function Divide(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
[TRtlExport('div', Pure)]
|
[TRtlExport('div', Pure)]
|
||||||
[AstDoc('Performs integer division.')]
|
[AstDoc('Performs integer division. Returns NaN on division by zero.')]
|
||||||
[AstSignature('(number, number) -> number')]
|
[AstSignature('(number, number) -> number')]
|
||||||
class function IntDivide(const Args: TArray<TDataValue>): TDataValue; static;
|
class function IntDivide(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
[TRtlExport('mod', Pure)]
|
[TRtlExport('mod', Pure)]
|
||||||
[AstDoc('Returns the remainder of integer division.')]
|
[AstDoc('Returns the remainder of integer division. Returns NaN on division by zero.')]
|
||||||
[AstSignature('(number, number) -> number')]
|
[AstSignature('(number, number) -> number')]
|
||||||
class function Modulus(const Args: TArray<TDataValue>): TDataValue; static;
|
class function Modulus(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
@@ -160,11 +168,6 @@ type
|
|||||||
[TRtlExport('/', Pure)]
|
[TRtlExport('/', Pure)]
|
||||||
class function Divide_Float_Ordinal_Float(A: Double; B: Int64): Double; static;
|
class function Divide_Float_Ordinal_Float(A: Double; B: Int64): Double; static;
|
||||||
|
|
||||||
[TRtlExport('div', Pure)]
|
|
||||||
class function Div_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64; static;
|
|
||||||
[TRtlExport('mod', Pure)]
|
|
||||||
class function Mod_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64; static;
|
|
||||||
|
|
||||||
[TRtlExport('=', Pure)]
|
[TRtlExport('=', Pure)]
|
||||||
class function Equal_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64; static;
|
class function Equal_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64; static;
|
||||||
[TRtlExport('=', Pure)]
|
[TRtlExport('=', Pure)]
|
||||||
@@ -246,7 +249,7 @@ implementation
|
|||||||
|
|
||||||
{ TRtlCoreFunctions - Constants }
|
{ TRtlCoreFunctions - Constants }
|
||||||
|
|
||||||
class function TRtlCoreFunctions.Const_NaN: Double;
|
class function TRtlCoreFunctions.CNaN: Double;
|
||||||
begin
|
begin
|
||||||
Result := System.Math.NaN;
|
Result := System.Math.NaN;
|
||||||
end;
|
end;
|
||||||
@@ -284,6 +287,7 @@ class function TRtlCoreFunctions.Divide(const Args: TArray<TDataValue>): TDataVa
|
|||||||
begin
|
begin
|
||||||
if Length(Args) <> 2 then
|
if Length(Args) <> 2 then
|
||||||
raise EArgumentException.Create('Operator / requires 2 arguments.');
|
raise EArgumentException.Create('Operator / requires 2 arguments.');
|
||||||
|
|
||||||
Result := Args[0].AsScalar / Args[1].AsScalar;
|
Result := Args[0].AsScalar / Args[1].AsScalar;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -291,6 +295,7 @@ class function TRtlCoreFunctions.IntDivide(const Args: TArray<TDataValue>): TDat
|
|||||||
begin
|
begin
|
||||||
if Length(Args) <> 2 then
|
if Length(Args) <> 2 then
|
||||||
raise EArgumentException.Create('Operator div requires 2 arguments.');
|
raise EArgumentException.Create('Operator div requires 2 arguments.');
|
||||||
|
|
||||||
Result := Args[0].AsScalar div Args[1].AsScalar;
|
Result := Args[0].AsScalar div Args[1].AsScalar;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -298,7 +303,8 @@ class function TRtlCoreFunctions.Modulus(const Args: TArray<TDataValue>): TDataV
|
|||||||
begin
|
begin
|
||||||
if Length(Args) <> 2 then
|
if Length(Args) <> 2 then
|
||||||
raise EArgumentException.Create('Operator mod requires 2 arguments.');
|
raise EArgumentException.Create('Operator mod requires 2 arguments.');
|
||||||
Result := Args[0].AsScalar mod Args[1].AsScalar;
|
|
||||||
|
Result := TScalar.FromInt64(Int64(Args[0].AsScalar) mod Args[1].AsScalar);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TRtlCoreFunctions.Equal(const Args: TArray<TDataValue>): TDataValue;
|
class function TRtlCoreFunctions.Equal(const Args: TArray<TDataValue>): TDataValue;
|
||||||
@@ -447,42 +453,30 @@ begin
|
|||||||
Result := A * B;
|
Result := A * B;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Divide
|
// Divide - Updated to return NaN on div0
|
||||||
class function TRtlCoreFunctions.Divide_Ordinal_Ordinal_Float(A, B: Int64): Double;
|
class function TRtlCoreFunctions.Divide_Ordinal_Ordinal_Float(A, B: Int64): Double;
|
||||||
begin
|
begin
|
||||||
if B = 0 then
|
|
||||||
raise EDivByZero.Create('Division by zero.');
|
|
||||||
Result := A / B;
|
Result := A / B;
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.Divide_Float_Float_Float(A, B: Double): Double;
|
class function TRtlCoreFunctions.Divide_Float_Float_Float(A, B: Double): Double;
|
||||||
begin
|
begin
|
||||||
if B = 0.0 then
|
if B = 0.0 then
|
||||||
raise EDivByZero.Create('Division by zero.');
|
Result := NaN
|
||||||
Result := A / B;
|
else
|
||||||
|
Result := A / B;
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.Divide_Ordinal_Float_Float(A: Int64; B: Double): Double;
|
class function TRtlCoreFunctions.Divide_Ordinal_Float_Float(A: Int64; B: Double): Double;
|
||||||
begin
|
begin
|
||||||
if B = 0.0 then
|
if B = 0.0 then
|
||||||
raise EDivByZero.Create('Division by zero.');
|
Result := NaN
|
||||||
Result := A / B;
|
else
|
||||||
|
Result := A / B;
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.Divide_Float_Ordinal_Float(A: Double; B: Int64): Double;
|
class function TRtlCoreFunctions.Divide_Float_Ordinal_Float(A: Double; B: Int64): Double;
|
||||||
begin
|
begin
|
||||||
if B = 0 then
|
|
||||||
raise EDivByZero.Create('Division by zero.');
|
|
||||||
Result := A / B;
|
Result := A / B;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Integer Math
|
|
||||||
class function TRtlCoreFunctions.Div_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64;
|
|
||||||
begin
|
|
||||||
Result := A div B;
|
|
||||||
end;
|
|
||||||
class function TRtlCoreFunctions.Mod_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64;
|
|
||||||
begin
|
|
||||||
Result := A mod B;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Comparisons
|
// Comparisons
|
||||||
class function TRtlCoreFunctions.Equal_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64;
|
class function TRtlCoreFunctions.Equal_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64;
|
||||||
begin
|
begin
|
||||||
@@ -490,15 +484,15 @@ begin
|
|||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.Equal_Float_Float_Ordinal(A, B: Double): Int64;
|
class function TRtlCoreFunctions.Equal_Float_Float_Ordinal(A, B: Double): Int64;
|
||||||
begin
|
begin
|
||||||
Result := Ord(SameValue(A, B));
|
Result := Ord(A = B);
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.Equal_Ordinal_Float_Ordinal(A: Int64; B: Double): Int64;
|
class function TRtlCoreFunctions.Equal_Ordinal_Float_Ordinal(A: Int64; B: Double): Int64;
|
||||||
begin
|
begin
|
||||||
Result := Ord(SameValue(A, B));
|
Result := Ord(A = B);
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.Equal_Float_Ordinal_Ordinal(A: Double; B: Int64): Int64;
|
class function TRtlCoreFunctions.Equal_Float_Ordinal_Ordinal(A: Double; B: Int64): Int64;
|
||||||
begin
|
begin
|
||||||
Result := Ord(SameValue(A, B));
|
Result := Ord(A = B);
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.Equal_Keyword_Keyword_Ordinal(A, B: Int64): Int64;
|
class function TRtlCoreFunctions.Equal_Keyword_Keyword_Ordinal(A, B: Int64): Int64;
|
||||||
begin
|
begin
|
||||||
@@ -511,15 +505,15 @@ begin
|
|||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.NotEqual_Float_Float_Ordinal(A, B: Double): Int64;
|
class function TRtlCoreFunctions.NotEqual_Float_Float_Ordinal(A, B: Double): Int64;
|
||||||
begin
|
begin
|
||||||
Result := Ord(not SameValue(A, B));
|
Result := Ord(A <> B);
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.NotEqual_Ordinal_Float_Ordinal(A: Int64; B: Double): Int64;
|
class function TRtlCoreFunctions.NotEqual_Ordinal_Float_Ordinal(A: Int64; B: Double): Int64;
|
||||||
begin
|
begin
|
||||||
Result := Ord(not SameValue(A, B));
|
Result := Ord(A <> B);
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.NotEqual_Float_Ordinal_Ordinal(A: Double; B: Int64): Int64;
|
class function TRtlCoreFunctions.NotEqual_Float_Ordinal_Ordinal(A: Double; B: Int64): Int64;
|
||||||
begin
|
begin
|
||||||
Result := Ord(not SameValue(A, B));
|
Result := Ord(A <> B);
|
||||||
end;
|
end;
|
||||||
class function TRtlCoreFunctions.NotEqual_Keyword_Keyword_Ordinal(A, B: Int64): Int64;
|
class function TRtlCoreFunctions.NotEqual_Keyword_Keyword_Ordinal(A, B: Int64): Int64;
|
||||||
begin
|
begin
|
||||||
@@ -599,6 +593,17 @@ class function TRtlCoreFunctions.And_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64
|
|||||||
begin
|
begin
|
||||||
Result := A and B;
|
Result := A and B;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TRtlCoreFunctions.CFalse: Boolean;
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlCoreFunctions.CTrue: Boolean;
|
||||||
|
begin
|
||||||
|
Result := true;
|
||||||
|
end;
|
||||||
|
|
||||||
class function TRtlCoreFunctions.Or_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64;
|
class function TRtlCoreFunctions.Or_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64;
|
||||||
begin
|
begin
|
||||||
Result := A or B;
|
Result := A or B;
|
||||||
|
|||||||
@@ -12,7 +12,17 @@ uses
|
|||||||
type
|
type
|
||||||
TRtlMathFunctions = record
|
TRtlMathFunctions = record
|
||||||
public
|
public
|
||||||
// --- Math Functions ---
|
// --- Constants ---
|
||||||
|
|
||||||
|
[TRtlConst('Pi')]
|
||||||
|
[AstDoc('Pi.')]
|
||||||
|
class function CPi: Double; static;
|
||||||
|
|
||||||
|
[TRtlConst('e')]
|
||||||
|
[AstDoc('Euler''s number.')]
|
||||||
|
class function CE: Double; static;
|
||||||
|
|
||||||
|
// --- Basic Math ---
|
||||||
|
|
||||||
[TRtlExport('abs', Pure)]
|
[TRtlExport('abs', Pure)]
|
||||||
[AstDoc('Returns the absolute value of a number.')]
|
[AstDoc('Returns the absolute value of a number.')]
|
||||||
@@ -44,6 +54,16 @@ type
|
|||||||
[AstSignature('(number) -> number')]
|
[AstSignature('(number) -> number')]
|
||||||
class function Sign(const Arg: TScalar): TScalar; static;
|
class function Sign(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('min', Pure)]
|
||||||
|
[AstDoc('Returns the smaller of two numbers.')]
|
||||||
|
[AstSignature('(number, number) -> number')]
|
||||||
|
class function Min(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
|
[TRtlExport('max', Pure)]
|
||||||
|
[AstDoc('Returns the larger of two numbers.')]
|
||||||
|
[AstSignature('(number, number) -> number')]
|
||||||
|
class function Max(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
[TRtlExport('sqrt', Pure)]
|
[TRtlExport('sqrt', Pure)]
|
||||||
[AstDoc('Returns the square root of a number.')]
|
[AstDoc('Returns the square root of a number.')]
|
||||||
[AstSignature('(number) -> number')]
|
[AstSignature('(number) -> number')]
|
||||||
@@ -54,12 +74,98 @@ type
|
|||||||
[AstSignature('(number, number) -> number')]
|
[AstSignature('(number, number) -> number')]
|
||||||
class function Pow(const Args: TArray<TDataValue>): TDataValue; static;
|
class function Pow(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
|
[TRtlExport('exp', Pure)]
|
||||||
|
[AstDoc('Returns e raised to the power of X.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Exp(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('log', Pure)]
|
||||||
|
[AstDoc('Returns the natural logarithm (Base e).')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Log(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('log10', Pure)]
|
||||||
|
[AstDoc('Returns the base-10 logarithm.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Log10(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
// --- Trigonometry ---
|
||||||
|
|
||||||
|
[TRtlExport('sin', Pure)]
|
||||||
|
[AstDoc('Returns the sine of the angle (in radians).')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Sin(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('cos', Pure)]
|
||||||
|
[AstDoc('Returns the cosine of the angle (in radians).')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Cos(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('tan', Pure)]
|
||||||
|
[AstDoc('Returns the tangent of the angle (in radians).')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Tan(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('asin', Pure)]
|
||||||
|
[AstDoc('Returns the arc sine.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function ArcSin(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('acos', Pure)]
|
||||||
|
[AstDoc('Returns the arc cosine.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function ArcCos(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('atan', Pure)]
|
||||||
|
[AstDoc('Returns the arc tangent.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function ArcTan(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('atan2', Pure)]
|
||||||
|
[AstDoc('Returns the angle whose tangent is Y / X.')]
|
||||||
|
[AstSignature('(y, x) -> number')]
|
||||||
|
class function ArcTan2(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
|
[TRtlExport('sinh', Pure)]
|
||||||
|
[AstDoc('Returns the hyperbolic sine.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Sinh(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('cosh', Pure)]
|
||||||
|
[AstDoc('Returns the hyperbolic cosine.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Cosh(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('tanh', Pure)]
|
||||||
|
[AstDoc('Returns the hyperbolic tangent.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function Tanh(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
// --- Conversion ---
|
||||||
|
|
||||||
|
[TRtlExport('deg2rad', Pure)]
|
||||||
|
[AstDoc('Converts degrees to radians.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function DegToRad(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
[TRtlExport('rad2deg', Pure)]
|
||||||
|
[AstDoc('Converts radians to degrees.')]
|
||||||
|
[AstSignature('(number) -> number')]
|
||||||
|
class function RadToDeg(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
|
// --- Utils ---
|
||||||
|
|
||||||
[TRtlExport('random', Impure)]
|
[TRtlExport('random', Impure)]
|
||||||
[AstDoc('Returns a random number. No args: [0..1). Arg N: Integer [0..N).')]
|
[AstDoc('Returns a random number. No args: [0..1). Arg N: Integer [0..N).')]
|
||||||
[AstSignature('() -> float')]
|
[AstSignature('() -> float')]
|
||||||
[AstSignature('(number) -> number')]
|
[AstSignature('(number) -> number')]
|
||||||
class function Random(const Args: TArray<TDataValue>): TDataValue; static;
|
class function Random(const Args: TArray<TDataValue>): TDataValue; static;
|
||||||
|
|
||||||
|
[TRtlExport('is-NaN', Pure)]
|
||||||
|
[AstDoc('Returns true if the value is Not-a-Number (NaN).')]
|
||||||
|
[AstSignature('(number) -> boolean')]
|
||||||
|
class function IsNaN(const Arg: TScalar): TScalar; static;
|
||||||
|
|
||||||
// --- Static Specializations ---
|
// --- Static Specializations ---
|
||||||
|
|
||||||
[TRtlExport('abs', Pure)]
|
[TRtlExport('abs', Pure)]
|
||||||
@@ -91,16 +197,57 @@ type
|
|||||||
[TRtlExport('pow', Pure)]
|
[TRtlExport('pow', Pure)]
|
||||||
class function Pow_Float_Ordinal_Float(A: Double; B: Int64): Double; static;
|
class function Pow_Float_Ordinal_Float(A: Double; B: Int64): Double; static;
|
||||||
|
|
||||||
|
[TRtlExport('min', Pure)]
|
||||||
|
class function Min_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64; static;
|
||||||
|
[TRtlExport('min', Pure)]
|
||||||
|
class function Min_Float_Float_Float(A, B: Double): Double; static;
|
||||||
|
|
||||||
|
[TRtlExport('max', Pure)]
|
||||||
|
class function Max_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64; static;
|
||||||
|
[TRtlExport('max', Pure)]
|
||||||
|
class function Max_Float_Float_Float(A, B: Double): Double; static;
|
||||||
|
|
||||||
|
[TRtlExport('exp', Pure)]
|
||||||
|
class function Exp_Float_Float(A: Double): Double; static;
|
||||||
|
[TRtlExport('log', Pure)]
|
||||||
|
class function Log_Float_Float(A: Double): Double; static;
|
||||||
|
[TRtlExport('log10', Pure)]
|
||||||
|
class function Log10_Float_Float(A: Double): Double; static;
|
||||||
|
|
||||||
|
[TRtlExport('sin', Pure)]
|
||||||
|
class function Sin_Float_Float(A: Double): Double; static;
|
||||||
|
[TRtlExport('cos', Pure)]
|
||||||
|
class function Cos_Float_Float(A: Double): Double; static;
|
||||||
|
[TRtlExport('tan', Pure)]
|
||||||
|
class function Tan_Float_Float(A: Double): Double; static;
|
||||||
|
|
||||||
[TRtlExport('random', Impure)]
|
[TRtlExport('random', Impure)]
|
||||||
class function Random_Void_Float: Double; static;
|
class function Random_Void_Float: Double; static;
|
||||||
[TRtlExport('random', Impure)]
|
[TRtlExport('random', Impure)]
|
||||||
class function Random_Ordinal_Ordinal(Limit: Int64): Int64; static;
|
class function Random_Ordinal_Ordinal(Limit: Int64): Int64; static;
|
||||||
|
|
||||||
|
[TRtlExport('is-NaN', Pure)]
|
||||||
|
class function IsNaN_Float_Ordinal(A: Double): Int64; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ TRtlMathFunctions }
|
{ TRtlMathFunctions }
|
||||||
|
|
||||||
|
// --- Constants ---
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.CPi: Double;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Pi);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.CE: Double;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(2.71828182845904523536);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// --- Basic Math ---
|
||||||
|
|
||||||
class function TRtlMathFunctions.Abs(const Arg: TScalar): TScalar;
|
class function TRtlMathFunctions.Abs(const Arg: TScalar): TScalar;
|
||||||
begin
|
begin
|
||||||
case Arg.Kind of
|
case Arg.Kind of
|
||||||
@@ -169,6 +316,34 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Min(const Args: TArray<TDataValue>): TDataValue;
|
||||||
|
begin
|
||||||
|
if Length(Args) <> 2 then
|
||||||
|
raise EArgumentException.Create('Min requires 2 arguments.');
|
||||||
|
|
||||||
|
var a: TScalar := Args[0].AsScalar;
|
||||||
|
var b: TScalar := Args[1].AsScalar;
|
||||||
|
|
||||||
|
if (a.Kind = TScalar.TKind.Ordinal) and (b.Kind = TScalar.TKind.Ordinal) then
|
||||||
|
Result := TScalar.FromInt64(System.Math.Min(a.Value.AsInt64, b.Value.AsInt64))
|
||||||
|
else
|
||||||
|
Result := TScalar.FromDouble(System.Math.Min(Double(a), Double(b)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Max(const Args: TArray<TDataValue>): TDataValue;
|
||||||
|
begin
|
||||||
|
if Length(Args) <> 2 then
|
||||||
|
raise EArgumentException.Create('Max requires 2 arguments.');
|
||||||
|
|
||||||
|
var a: TScalar := Args[0].AsScalar;
|
||||||
|
var b: TScalar := Args[1].AsScalar;
|
||||||
|
|
||||||
|
if (a.Kind = TScalar.TKind.Ordinal) and (b.Kind = TScalar.TKind.Ordinal) then
|
||||||
|
Result := TScalar.FromInt64(System.Math.Max(a.Value.AsInt64, b.Value.AsInt64))
|
||||||
|
else
|
||||||
|
Result := TScalar.FromDouble(System.Math.Max(Double(a), Double(b)));
|
||||||
|
end;
|
||||||
|
|
||||||
class function TRtlMathFunctions.Sqrt(const Arg: TScalar): TScalar;
|
class function TRtlMathFunctions.Sqrt(const Arg: TScalar): TScalar;
|
||||||
begin
|
begin
|
||||||
var val: Double := Arg; // Implicit cast handles Ordinal and Float
|
var val: Double := Arg; // Implicit cast handles Ordinal and Float
|
||||||
@@ -185,6 +360,92 @@ begin
|
|||||||
Result := TScalar.FromDouble(System.Math.Power(baseVal, expVal));
|
Result := TScalar.FromDouble(System.Math.Power(baseVal, expVal));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Exp(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Exp(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Log(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Ln(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Log10(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.Log10(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
// --- Trigonometry ---
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Sin(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Sin(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Cos(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Cos(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Tan(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.Tan(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.ArcSin(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.ArcSin(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.ArcCos(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.ArcCos(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.ArcTan(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.ArcTan(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.ArcTan2(const Args: TArray<TDataValue>): TDataValue;
|
||||||
|
begin
|
||||||
|
if Length(Args) <> 2 then
|
||||||
|
raise EArgumentException.Create('Atan2 requires 2 arguments (Y, X).');
|
||||||
|
|
||||||
|
var y: Double := Args[0].AsScalar;
|
||||||
|
var x: Double := Args[1].AsScalar;
|
||||||
|
Result := TScalar.FromDouble(System.Math.ArcTan2(y, x));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Sinh(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.Sinh(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Cosh(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.Cosh(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Tanh(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.Tanh(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
// --- Conversion ---
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.DegToRad(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.DegToRad(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.RadToDeg(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
Result := TScalar.FromDouble(System.Math.RadToDeg(Double(Arg)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
// --- Utils ---
|
||||||
|
|
||||||
class function TRtlMathFunctions.Random(const Args: TArray<TDataValue>): TDataValue;
|
class function TRtlMathFunctions.Random(const Args: TArray<TDataValue>): TDataValue;
|
||||||
begin
|
begin
|
||||||
if Length(Args) = 0 then
|
if Length(Args) = 0 then
|
||||||
@@ -195,6 +456,14 @@ begin
|
|||||||
raise EArgumentException.Create('Random expects 0 arguments or 1 integer argument.');
|
raise EArgumentException.Create('Random expects 0 arguments or 1 integer argument.');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.IsNaN(const Arg: TScalar): TScalar;
|
||||||
|
begin
|
||||||
|
if (Arg.Kind = TScalar.TKind.Float) and Arg.Value.AsDouble.IsNaN then
|
||||||
|
Result := TScalar.FromBoolean(True)
|
||||||
|
else
|
||||||
|
Result := TScalar.FromBoolean(False);
|
||||||
|
end;
|
||||||
|
|
||||||
// --- Static Specializations ---
|
// --- Static Specializations ---
|
||||||
|
|
||||||
class function TRtlMathFunctions.Abs_Ordinal_Ordinal(A: Int64): Int64;
|
class function TRtlMathFunctions.Abs_Ordinal_Ordinal(A: Int64): Int64;
|
||||||
@@ -257,6 +526,56 @@ begin
|
|||||||
Result := System.Math.Power(A, B);
|
Result := System.Math.Power(A, B);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Min_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64;
|
||||||
|
begin
|
||||||
|
Result := System.Math.Min(A, B);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Min_Float_Float_Float(A, B: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := System.Math.Min(A, B);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Max_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64;
|
||||||
|
begin
|
||||||
|
Result := System.Math.Max(A, B);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Max_Float_Float_Float(A, B: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := System.Math.Max(A, B);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Exp_Float_Float(A: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := System.Exp(A);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Log_Float_Float(A: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := System.Ln(A);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Log10_Float_Float(A: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := System.Math.Log10(A);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Sin_Float_Float(A: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := System.Sin(A);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Cos_Float_Float(A: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := System.Cos(A);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.Tan_Float_Float(A: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := System.Math.Tan(A);
|
||||||
|
end;
|
||||||
|
|
||||||
class function TRtlMathFunctions.Random_Void_Float: Double;
|
class function TRtlMathFunctions.Random_Void_Float: Double;
|
||||||
begin
|
begin
|
||||||
Result := System.Random;
|
Result := System.Random;
|
||||||
@@ -267,4 +586,9 @@ begin
|
|||||||
Result := System.Random(Limit);
|
Result := System.Random(Limit);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TRtlMathFunctions.IsNaN_Float_Ordinal(A: Double): Int64;
|
||||||
|
begin
|
||||||
|
Result := Ord(A.IsNaN);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -783,9 +783,6 @@ var
|
|||||||
staticType: IStaticType;
|
staticType: IStaticType;
|
||||||
pair: TPair<string, TRtlFunctionInfo>;
|
pair: TPair<string, TRtlFunctionInfo>;
|
||||||
begin
|
begin
|
||||||
AScope.Define('true', TDataValue(TScalar.FromBoolean(True)), TTypes.Boolean, 'Boolean true.');
|
|
||||||
AScope.Define('false', TDataValue(TScalar.FromBoolean(False)), TTypes.Boolean, 'Boolean false.');
|
|
||||||
|
|
||||||
for pair in FStaticFuncMap do
|
for pair in FStaticFuncMap do
|
||||||
begin
|
begin
|
||||||
rtlName := pair.Key;
|
rtlName := pair.Key;
|
||||||
|
|||||||
@@ -620,12 +620,17 @@ begin
|
|||||||
if (A.Kind in [TKind.DateTime, TKind.Keyword, TKind.Boolean]) or (B.Kind in [TKind.DateTime, TKind.Keyword, TKind.Boolean]) then
|
if (A.Kind in [TKind.DateTime, TKind.Keyword, TKind.Boolean]) or (B.Kind in [TKind.DateTime, TKind.Keyword, TKind.Boolean]) then
|
||||||
raise EArgumentException.CreateFmt('Operator Divide not supported for types %s and %s', [A.Kind.ToString, B.Kind.ToString]);
|
raise EArgumentException.CreateFmt('Operator Divide not supported for types %s and %s', [A.Kind.ToString, B.Kind.ToString]);
|
||||||
|
|
||||||
var valB: Double := B;
|
if B.Kind in [TKind.Float, TKind.DateTime] then
|
||||||
if valB = 0.0 then
|
begin
|
||||||
raise EDivByZero.Create('Division by zero');
|
Result := A.Value.AsDouble / B.Value.AsDouble;
|
||||||
|
end
|
||||||
var valA: Double := A;
|
else
|
||||||
Result := valA / valB;
|
begin
|
||||||
|
var valB: Int64 := B;
|
||||||
|
if valB = 0 then
|
||||||
|
raise EDivByZero.Create('Division by zero');
|
||||||
|
Result := A.Value.AsDouble / valB;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class operator TScalar.IntDivide(const A, B: TScalar): TScalar;
|
class operator TScalar.IntDivide(const A, B: TScalar): TScalar;
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ begin
|
|||||||
// Integer div
|
// Integer div
|
||||||
Assert.WillRaise(procedure begin Call('div', [ValI(10), ValI(0)]); end);
|
Assert.WillRaise(procedure begin Call('div', [ValI(10), ValI(0)]); end);
|
||||||
// Float divide (explicit check in RTL)
|
// Float divide (explicit check in RTL)
|
||||||
Assert.WillRaise(procedure begin Call('/', [ValF(10.0), ValF(0.0)]); end);
|
Assert.WillNotRaise(procedure begin Call('/', [ValF(10.0), ValF(0.0)]); end);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
Reference in New Issue
Block a user