diff --git a/ASTPlayground/Script.txt b/ASTPlayground/Script.txt index c255c9a..e0def51 100644 --- a/ASTPlayground/Script.txt +++ b/ASTPlayground/Script.txt @@ -1,9 +1,15 @@ (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 (fn [len] (do @@ -14,17 +20,51 @@ (fn [src] (do (def cnt (count src)) - (if (< cnt (+ len 1)) - 0.0 - (do - (def val-new (get src 0)) - (def val-out (get src len)) - (def w-sum (+ prev-w-sum (- (* len val-new) prev-s-sum))) - (def s-sum (+ (- prev-s-sum val-out) val-new)) - (assign prev-w-sum w-sum) - (assign prev-s-sum s-sum) - (/ w-sum weight-div) - )) + + ;; PHASE 1: Nicht genug Daten + (if (< cnt len) + NaN + + ;; Genug Daten vorhanden + (if (= cnt len) + ;; PHASE 2: Initialisierung (Das Fenster ist gerade voll geworden) + ;; Wir müssen einmalig die Basis-Summen berechnen. + (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,23 +74,31 @@ (do (def half-len (round (/ len 2))) (def sqrt-len (round (sqrt len))) + (def wma-half (create-wma half-len)) (def wma-full (create-wma len)) (def wma-smooth (create-wma sqrt-len)) + (def diff-series (new-series [[:val :Float]])) (fn [src] (do (def v1 (wma-half 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)) - (add-item diff-series {:val diff}) - (wma-smooth (get diff-series :val)) + (if (not (is-NaN diff)) + (add-item diff-series {:val diff})) + + ;; Glättung auf dem Resultat + (wma-smooth (.val diff-series)) )) ))) ;; --- Repeat Macro --- - (defmacro repeat [n body] + (defmacro repeat [n body] `((fn [cnt] (if (> cnt 0) (do @@ -59,45 +107,33 @@ ~n)) ;; =========================================================================== - ;; 2. SIMULATION & TEST + ;; 2. SIMULATION ;; =========================================================================== - - ;; Konfiguration - (def hma-length 14) - (def simulation-steps 50) + + (def hma-length 250) + (def simulation-steps 5000) - ;; Initialisierung der Komponenten - (def hma-calc (create-hma hma-length)) ; Die HMA-Closure - (def prices (new-series [[:close :Float]])) ; Die Preis-Series - (def current-price 100.0) ; Startpreis + (def hma-calc (create-hma hma-length)) + (def prices (new-series [[:close :Float]])) + (def current-price 100.0) - ;; Header Ausgabe (falls print verfügbar ist) (print "Step | Price | HMA(14)") (print "-----|----------|----------") - ;; Simulations-Schleife (repeat simulation-steps (do - ;; 1. Preis simulieren (Random Walk) - ;; (random) gibt 0.0 bis 1.0 zurück. - ;; (- (random) 0.5) erzeugt eine Änderung zwischen -0.5 und +0.5 + ;; Random Walk (assign current-price (+ current-price (- (random) 0.5))) - - ;; 2. Preis zur Series hinzufügen (add-item prices {:close current-price}) - ;; 3. HMA berechnen - (def hma-val 0.0) + ;; Berechnung + ;; Nutzung von Member Access (.close), da es eine Record-Series ist + (def hma-val (hma-calc (.close prices))) - ;; 3. HMA berechnen - (def price-series (get prices :close)) - (assign hma-val (hma-calc price-series)) - - ;; 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...)")) + ;; Ausgabe + (if (not (is-NaN hma-val)) + (print (count prices) " |" current-price " | " hma-val) + ) ) ) ) \ No newline at end of file diff --git a/Src/AST/Myc.Ast.RTL.Core.pas b/Src/AST/Myc.Ast.RTL.Core.pas index 4e7d0af..d251523 100644 --- a/Src/AST/Myc.Ast.RTL.Core.pas +++ b/Src/AST/Myc.Ast.RTL.Core.pas @@ -14,9 +14,17 @@ type public // --- Constants --- + [TRtlConst('false')] + [AstDoc('Boolean false.')] + class function CFalse: Boolean; static; + + [TRtlConst('true')] + [AstDoc('Boolean true.')] + class function CTrue: Boolean; static; + [TRtlConst('NaN')] [AstDoc('Not a Number (IEEE 754).')] - class function Const_NaN: Double; static; + class function CNaN: Double; static; // --- Arithmetic Operators --- @@ -38,17 +46,17 @@ type class function Multiply(const Args: TArray): TDataValue; static; [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')] class function Divide(const Args: TArray): TDataValue; static; [TRtlExport('div', Pure)] - [AstDoc('Performs integer division.')] + [AstDoc('Performs integer division. Returns NaN on division by zero.')] [AstSignature('(number, number) -> number')] class function IntDivide(const Args: TArray): TDataValue; static; [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')] class function Modulus(const Args: TArray): TDataValue; static; @@ -160,11 +168,6 @@ type [TRtlExport('/', Pure)] 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)] class function Equal_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64; static; [TRtlExport('=', Pure)] @@ -246,7 +249,7 @@ implementation { TRtlCoreFunctions - Constants } -class function TRtlCoreFunctions.Const_NaN: Double; +class function TRtlCoreFunctions.CNaN: Double; begin Result := System.Math.NaN; end; @@ -284,6 +287,7 @@ class function TRtlCoreFunctions.Divide(const Args: TArray): TDataVa begin if Length(Args) <> 2 then raise EArgumentException.Create('Operator / requires 2 arguments.'); + Result := Args[0].AsScalar / Args[1].AsScalar; end; @@ -291,6 +295,7 @@ class function TRtlCoreFunctions.IntDivide(const Args: TArray): TDat begin if Length(Args) <> 2 then raise EArgumentException.Create('Operator div requires 2 arguments.'); + Result := Args[0].AsScalar div Args[1].AsScalar; end; @@ -298,7 +303,8 @@ class function TRtlCoreFunctions.Modulus(const Args: TArray): TDataV begin if Length(Args) <> 2 then 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; class function TRtlCoreFunctions.Equal(const Args: TArray): TDataValue; @@ -447,42 +453,30 @@ begin Result := A * B; end; -// Divide +// Divide - Updated to return NaN on div0 class function TRtlCoreFunctions.Divide_Ordinal_Ordinal_Float(A, B: Int64): Double; begin - if B = 0 then - raise EDivByZero.Create('Division by zero.'); Result := A / B; end; class function TRtlCoreFunctions.Divide_Float_Float_Float(A, B: Double): Double; begin if B = 0.0 then - raise EDivByZero.Create('Division by zero.'); - Result := A / B; + Result := NaN + else + Result := A / B; end; class function TRtlCoreFunctions.Divide_Ordinal_Float_Float(A: Int64; B: Double): Double; begin if B = 0.0 then - raise EDivByZero.Create('Division by zero.'); - Result := A / B; + Result := NaN + else + Result := A / B; end; class function TRtlCoreFunctions.Divide_Float_Ordinal_Float(A: Double; B: Int64): Double; begin - if B = 0 then - raise EDivByZero.Create('Division by zero.'); Result := A / B; 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 class function TRtlCoreFunctions.Equal_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64; begin @@ -490,15 +484,15 @@ begin end; class function TRtlCoreFunctions.Equal_Float_Float_Ordinal(A, B: Double): Int64; begin - Result := Ord(SameValue(A, B)); + Result := Ord(A = B); end; class function TRtlCoreFunctions.Equal_Ordinal_Float_Ordinal(A: Int64; B: Double): Int64; begin - Result := Ord(SameValue(A, B)); + Result := Ord(A = B); end; class function TRtlCoreFunctions.Equal_Float_Ordinal_Ordinal(A: Double; B: Int64): Int64; begin - Result := Ord(SameValue(A, B)); + Result := Ord(A = B); end; class function TRtlCoreFunctions.Equal_Keyword_Keyword_Ordinal(A, B: Int64): Int64; begin @@ -511,15 +505,15 @@ begin end; class function TRtlCoreFunctions.NotEqual_Float_Float_Ordinal(A, B: Double): Int64; begin - Result := Ord(not SameValue(A, B)); + Result := Ord(A <> B); end; class function TRtlCoreFunctions.NotEqual_Ordinal_Float_Ordinal(A: Int64; B: Double): Int64; begin - Result := Ord(not SameValue(A, B)); + Result := Ord(A <> B); end; class function TRtlCoreFunctions.NotEqual_Float_Ordinal_Ordinal(A: Double; B: Int64): Int64; begin - Result := Ord(not SameValue(A, B)); + Result := Ord(A <> B); end; class function TRtlCoreFunctions.NotEqual_Keyword_Keyword_Ordinal(A, B: Int64): Int64; begin @@ -599,6 +593,17 @@ class function TRtlCoreFunctions.And_Ordinal_Ordinal_Ordinal(A, B: Int64): Int64 begin Result := A and B; 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; begin Result := A or B; diff --git a/Src/AST/Myc.Ast.RTL.Math.pas b/Src/AST/Myc.Ast.RTL.Math.pas index 9adeb6a..02db20a 100644 --- a/Src/AST/Myc.Ast.RTL.Math.pas +++ b/Src/AST/Myc.Ast.RTL.Math.pas @@ -12,7 +12,17 @@ uses type TRtlMathFunctions = record 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)] [AstDoc('Returns the absolute value of a number.')] @@ -44,6 +54,16 @@ type [AstSignature('(number) -> number')] 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; static; + + [TRtlExport('max', Pure)] + [AstDoc('Returns the larger of two numbers.')] + [AstSignature('(number, number) -> number')] + class function Max(const Args: TArray): TDataValue; static; + [TRtlExport('sqrt', Pure)] [AstDoc('Returns the square root of a number.')] [AstSignature('(number) -> number')] @@ -54,12 +74,98 @@ type [AstSignature('(number, number) -> number')] class function Pow(const Args: TArray): 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; 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)] [AstDoc('Returns a random number. No args: [0..1). Arg N: Integer [0..N).')] [AstSignature('() -> float')] [AstSignature('(number) -> number')] class function Random(const Args: TArray): 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 --- [TRtlExport('abs', Pure)] @@ -91,16 +197,57 @@ type [TRtlExport('pow', Pure)] 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)] class function Random_Void_Float: Double; static; [TRtlExport('random', Impure)] class function Random_Ordinal_Ordinal(Limit: Int64): Int64; static; + + [TRtlExport('is-NaN', Pure)] + class function IsNaN_Float_Ordinal(A: Double): Int64; static; end; implementation { 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; begin case Arg.Kind of @@ -169,6 +316,34 @@ begin end; end; +class function TRtlMathFunctions.Min(const Args: TArray): 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; +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; begin var val: Double := Arg; // Implicit cast handles Ordinal and Float @@ -185,6 +360,92 @@ begin Result := TScalar.FromDouble(System.Math.Power(baseVal, expVal)); 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; +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; begin if Length(Args) = 0 then @@ -195,6 +456,14 @@ begin raise EArgumentException.Create('Random expects 0 arguments or 1 integer argument.'); 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 --- class function TRtlMathFunctions.Abs_Ordinal_Ordinal(A: Int64): Int64; @@ -257,6 +526,56 @@ begin Result := System.Math.Power(A, B); 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; begin Result := System.Random; @@ -267,4 +586,9 @@ begin Result := System.Random(Limit); end; +class function TRtlMathFunctions.IsNaN_Float_Ordinal(A: Double): Int64; +begin + Result := Ord(A.IsNaN); +end; + end. diff --git a/Src/AST/Myc.Ast.RTL.pas b/Src/AST/Myc.Ast.RTL.pas index d23e73d..9a29e3d 100644 --- a/Src/AST/Myc.Ast.RTL.pas +++ b/Src/AST/Myc.Ast.RTL.pas @@ -783,9 +783,6 @@ var staticType: IStaticType; pair: TPair; 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 begin rtlName := pair.Key; diff --git a/Src/Data/Myc.Data.Scalar.pas b/Src/Data/Myc.Data.Scalar.pas index 11dd965..6bdea89 100644 --- a/Src/Data/Myc.Data.Scalar.pas +++ b/Src/Data/Myc.Data.Scalar.pas @@ -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 raise EArgumentException.CreateFmt('Operator Divide not supported for types %s and %s', [A.Kind.ToString, B.Kind.ToString]); - var valB: Double := B; - if valB = 0.0 then - raise EDivByZero.Create('Division by zero'); - - var valA: Double := A; - Result := valA / valB; + if B.Kind in [TKind.Float, TKind.DateTime] then + begin + Result := A.Value.AsDouble / B.Value.AsDouble; + end + else + begin + var valB: Int64 := B; + if valB = 0 then + raise EDivByZero.Create('Division by zero'); + Result := A.Value.AsDouble / valB; + end; end; class operator TScalar.IntDivide(const A, B: TScalar): TScalar; diff --git a/Test/AST/Test.Myc.Ast.RTL.pas b/Test/AST/Test.Myc.Ast.RTL.pas index 89622fd..ddb59d0 100644 --- a/Test/AST/Test.Myc.Ast.RTL.pas +++ b/Test/AST/Test.Myc.Ast.RTL.pas @@ -213,7 +213,7 @@ begin // Integer div Assert.WillRaise(procedure begin Call('div', [ValI(10), ValI(0)]); end); // 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.