unit Myc.Ast.RTL.Math; interface uses System.SysUtils, System.Math, Myc.Data.Scalar, Myc.Data.Value, Myc.Ast.Attributes; type TRtlMathFunctions = record public // --- 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.')] [AstSignature('(number) -> number')] class function Abs(const Arg: TScalar): TScalar; static; [TRtlExport('round', Pure)] [AstDoc('Rounds a float to the nearest integer.')] [AstSignature('(number) -> number')] class function Round(const Arg: TScalar): TScalar; static; [TRtlExport('trunc', Pure)] [AstDoc('Returns the integer part of a float.')] [AstSignature('(number) -> number')] class function Trunc(const Arg: TScalar): TScalar; static; [TRtlExport('ceil', Pure)] [AstDoc('Returns the smallest integer >= the argument.')] [AstSignature('(number) -> number')] class function Ceil(const Arg: TScalar): TScalar; static; [TRtlExport('floor', Pure)] [AstDoc('Returns the largest integer <= the argument.')] [AstSignature('(number) -> number')] class function Floor(const Arg: TScalar): TScalar; static; [TRtlExport('sign', Pure)] [AstDoc('Returns -1 for negative, 1 for positive, 0 for zero.')] [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')] class function Sqrt(const Arg: TScalar): TScalar; static; [TRtlExport('pow', Pure)] [AstDoc('Returns Base raised to the power of Exponent.')] [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)] class function Abs_Ordinal_Ordinal(A: Int64): Int64; static; [TRtlExport('abs', Pure)] class function Abs_Float_Float(A: Double): Double; static; [TRtlExport('round', Pure)] class function Round_Ordinal_Ordinal(A: Int64): Int64; static; [TRtlExport('round', Pure)] class function Round_Float_Ordinal(A: Double): Int64; static; [TRtlExport('trunc', Pure)] class function Trunc_Ordinal_Ordinal(A: Int64): Int64; static; [TRtlExport('trunc', Pure)] class function Trunc_Float_Ordinal(A: Double): Int64; static; [TRtlExport('sqrt', Pure)] class function Sqrt_Ordinal_Float(A: Int64): Double; static; [TRtlExport('sqrt', Pure)] class function Sqrt_Float_Float(A: Double): Double; static; [TRtlExport('pow', Pure)] class function Pow_Ordinal_Ordinal_Float(A, B: Int64): Double; static; [TRtlExport('pow', Pure)] class function Pow_Float_Float_Float(A, B: Double): Double; static; [TRtlExport('pow', Pure)] class function Pow_Ordinal_Float_Float(A: Int64; B: Double): Double; static; [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 TScalar.TKind.Ordinal: Result := TScalar.FromInt64(System.Abs(Arg.Value.AsInt64)); TScalar.TKind.Float, TScalar.TKind.DateTime: Result := TScalar.FromDouble(System.Abs(Arg.Value.AsDouble)); else raise EArgumentException.Create('Abs requires a numeric argument.'); end; end; class function TRtlMathFunctions.Round(const Arg: TScalar): TScalar; begin case Arg.Kind of TScalar.TKind.Ordinal: Result := Arg; TScalar.TKind.Float, TScalar.TKind.DateTime: begin var val: Double := Arg.Value.AsDouble; Result := TScalar.FromInt64(System.Round(val)); end; else raise EArgumentException.Create('Round requires a numeric argument.'); end; end; class function TRtlMathFunctions.Trunc(const Arg: TScalar): TScalar; begin case Arg.Kind of TScalar.TKind.Ordinal: Result := Arg; TScalar.TKind.Float, TScalar.TKind.DateTime: begin var val: Double := Arg.Value.AsDouble; Result := TScalar.FromInt64(System.Trunc(val)); end; else raise EArgumentException.Create('Trunc requires a numeric argument.'); end; end; class function TRtlMathFunctions.Ceil(const Arg: TScalar): TScalar; begin case Arg.Kind of TScalar.TKind.Ordinal: Result := Arg; TScalar.TKind.Float, TScalar.TKind.DateTime: Result := TScalar.FromInt64(System.Math.Ceil(Arg.Value.AsDouble)); else raise EArgumentException.Create('Ceil requires a numeric argument.'); end; end; class function TRtlMathFunctions.Floor(const Arg: TScalar): TScalar; begin case Arg.Kind of TScalar.TKind.Ordinal: Result := Arg; TScalar.TKind.Float, TScalar.TKind.DateTime: Result := TScalar.FromInt64(System.Math.Floor(Arg.Value.AsDouble)); else raise EArgumentException.Create('Floor requires a numeric argument.'); end; end; class function TRtlMathFunctions.Sign(const Arg: TScalar): TScalar; begin case Arg.Kind of TScalar.TKind.Ordinal: Result := TScalar.FromInt64(System.Math.Sign(Arg.Value.AsInt64)); TScalar.TKind.Float, TScalar.TKind.DateTime: Result := TScalar.FromInt64(System.Math.Sign(Arg.Value.AsDouble)); else raise EArgumentException.Create('Sign requires a numeric argument.'); 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 Result := TScalar.FromDouble(System.Sqrt(val)); end; class function TRtlMathFunctions.Pow(const Args: TArray): TDataValue; begin if Length(Args) <> 2 then raise EArgumentException.Create('Pow requires 2 arguments (Base, Exponent).'); var baseVal: Double := Args[0].AsScalar; var expVal: Double := Args[1].AsScalar; 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 Result := TScalar.FromDouble(System.Random) else if (Length(Args) = 1) and (Args[0].AsScalar.Kind = TScalar.TKind.Ordinal) then Result := TScalar.FromInt64(System.Random(Integer(Args[0].AsScalar.Value.AsInt64))) else 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; begin Result := System.Abs(A); end; class function TRtlMathFunctions.Abs_Float_Float(A: Double): Double; begin Result := System.Abs(A); end; class function TRtlMathFunctions.Round_Ordinal_Ordinal(A: Int64): Int64; begin Result := A; end; class function TRtlMathFunctions.Round_Float_Ordinal(A: Double): Int64; begin Result := System.Round(A); end; class function TRtlMathFunctions.Trunc_Ordinal_Ordinal(A: Int64): Int64; begin Result := A; end; class function TRtlMathFunctions.Trunc_Float_Ordinal(A: Double): Int64; begin Result := System.Trunc(A); end; class function TRtlMathFunctions.Sqrt_Ordinal_Float(A: Int64): Double; begin Result := System.Sqrt(A); end; class function TRtlMathFunctions.Sqrt_Float_Float(A: Double): Double; begin Result := System.Sqrt(A); end; class function TRtlMathFunctions.Pow_Ordinal_Ordinal_Float(A, B: Int64): Double; begin Result := System.Math.Power(A, B); end; class function TRtlMathFunctions.Pow_Float_Float_Float(A, B: Double): Double; begin Result := System.Math.Power(A, B); end; class function TRtlMathFunctions.Pow_Ordinal_Float_Float(A: Int64; B: Double): Double; begin Result := System.Math.Power(A, B); end; class function TRtlMathFunctions.Pow_Float_Ordinal_Float(A: Double; B: Int64): Double; 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; end; class function TRtlMathFunctions.Random_Ordinal_Ordinal(Limit: Int64): Int64; begin Result := System.Random(Limit); end; class function TRtlMathFunctions.IsNaN_Float_Ordinal(A: Double): Int64; begin Result := Ord(A.IsNaN); end; end.