diff --git a/Upsilon/StandardLibraries/MathLibrary.cs b/Upsilon/StandardLibraries/MathLibrary.cs index 0a1fb47..d72124f 100644 --- a/Upsilon/StandardLibraries/MathLibrary.cs +++ b/Upsilon/StandardLibraries/MathLibrary.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using Upsilon.BaseTypes; using Upsilon.BaseTypes.Number; namespace Upsilon.StandardLibraries @@ -14,5 +16,227 @@ namespace Upsilon.StandardLibraries } return new ScriptNumberLong(Math.Abs(((ScriptNumberLong) a).Value)); } + + [ScriptFunction("acos", "Returns the arc cosine of x (in radians).", directScriptManipulation: true)] + public ScriptNumber ArcCosine(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Acos(((ScriptNumberDouble) a).Value)); + } + return new ScriptNumberDouble(Math.Acos(((ScriptNumberLong) a).Value)); + } + + [ScriptFunction("asin", "Returns the arc sine of x (in radians).", directScriptManipulation: true)] + public ScriptNumber ArcSine(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Asin(((ScriptNumberDouble) a).Value)); + } + return new ScriptNumberDouble(Math.Asin(((ScriptNumberLong) a).Value)); + } + + [ScriptFunction("atan", "Returns the arc tangent of y (in radians).", directScriptManipulation: true)] + public ScriptNumber ArcTangent(ScriptNumber a, ScriptNumber b = null) + { + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Atan(((ScriptNumberDouble) a).Value)); + } + return new ScriptNumberDouble(Math.Atan(((ScriptNumberLong) a).Value)); + } + + [ScriptFunction("atan", "Returns the arc tangent of y/x (in radians).", directScriptManipulation: true)] + public ScriptNumber ArcTangent2(ScriptNumber a, ScriptNumber b) + { + if (a.IsFloat && b.IsFloat) + { + return new ScriptNumberDouble( + Math.Atan2(((ScriptNumberDouble) a).Value, ((ScriptNumberDouble) b).Value)); + } + if (a.IsFloat) + { + return new ScriptNumberDouble( + Math.Atan2(((ScriptNumberDouble) a).Value, ((ScriptNumberLong) b).Value)); + } + if (b.IsFloat) + { + return new ScriptNumberDouble( + Math.Atan2(((ScriptNumberLong) a).Value, ((ScriptNumberDouble) b).Value)); + } + return new ScriptNumberDouble( + Math.Atan2(((ScriptNumberLong) a).Value, ((ScriptNumberLong) b).Value)); + } + + [ScriptFunction("ceil", "Returns the smallest integral value larger than or equal to x.", directScriptManipulation: true)] + public ScriptNumber Ceiling(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberLong((long) Math.Ceiling(((ScriptNumberDouble) a).Value)); + } + return a; + } + + [ScriptFunction("cos", "Returns the cosine of x (assumed to be in radians).", directScriptManipulation: true)] + public ScriptNumber Cosine(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Cos(((ScriptNumberDouble) a).Value)); + } + return new ScriptNumberDouble(Math.Cos(((ScriptNumberLong) a).Value)); + } + + [ScriptFunction("deg", "Converts the angle x from radians to degrees.", directScriptManipulation: true)] + public ScriptNumber Degrees(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble((180 / Math.PI) * ((ScriptNumberDouble)a).Value); + } + return new ScriptNumberDouble((180 / Math.PI) * ((ScriptNumberLong)a).Value); + } + + [ScriptFunction("exp", "Returns the value e^x (where e is the base of natural logarithms).", directScriptManipulation: true)] + public ScriptNumber Exponent(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Exp(((ScriptNumberDouble) a).Value)); + } + return new ScriptNumberDouble(Math.Exp(((ScriptNumberLong) a).Value)); + } + + [ScriptFunction("floor", "Returns the largest integral value smaller than or equal to x.", directScriptManipulation: true)] + public ScriptNumber Floor(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberLong((long) Math.Floor(((ScriptNumberDouble) a).Value)); + } + return a; + } + + [ScriptFunction("fmod", "Returns the remainder of the division of x by y that rounds the quotient towards zero. (integer/float)", + directScriptManipulation: true)] + public ScriptNumber FModulo(ScriptNumber a, ScriptNumber b) + { + return a % b; + } + + public ScriptNumberDouble Huge { get; } = new ScriptNumberDouble(double.MaxValue); + + [ScriptFunction("log", "Returns the logarithm of x in the given base. The default for base is e (so that the function returns the natural logarithm of x).", directScriptManipulation: true)] + public ScriptNumber Logarithm(ScriptNumber a, ScriptNumber b = null) + { + var @base = Math.E; + if (b != null) + { + @base = (double) b.ToCSharpObject(); + } + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Log(((ScriptNumberDouble) a).Value, @base)); + } + return new ScriptNumberDouble(Math.Log(((ScriptNumberLong) a).Value, @base)); + } + + public ScriptNumberLong MaxInteger { get; } = new ScriptNumberLong(long.MaxValue); + public ScriptNumberLong MinInteger { get; } = new ScriptNumberLong(long.MinValue); + + [ScriptFunction("modf", "Returns the integral part of x and the fractional part of x. Its second result is always a float.", + directScriptManipulation: true)] + public SimpleScriptTable ModuloIntegral(ScriptNumber a) + { + if (a.IsFloat) + { + var integral = new ScriptNumberLong((long) ((ScriptNumberDouble)a).Value); + var remainder = new ScriptNumberDouble(((ScriptNumberDouble) a).Value % 1); + return new SimpleScriptTable(new List(){integral, remainder}); + } + + return new SimpleScriptTable(new List() + {new ScriptNumberLong((long) a.ToCSharpObject()), new ScriptNumberDouble(0)}); + } + + public ScriptNumberDouble Pi { get; } = new ScriptNumberDouble(Math.PI); + + [ScriptFunction("rad", "Converts the angle x from degrees to radians.", directScriptManipulation: true)] + public ScriptNumber Radians(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble((Math.PI / 180) * ((ScriptNumberDouble) a).Value); + } + return new ScriptNumberDouble((Math.PI / 180) * ((ScriptNumberLong)a).Value); + } + + private static Random _rand = new Random(); + [ScriptFunction("random", "When called without arguments, returns a pseudo-random float with uniform distribution in the range [0,1). When called with two integers m and n, math.random returns a pseudo-random integer with uniform distribution in the range [m, n]. (The value n-m cannot be negative and must fit in a Lua integer.) The call math.random(n) is equivalent to math.random(1,n).", directScriptManipulation: true)] + public ScriptNumber Random(ScriptNumber a = null,ScriptNumber b = null) + { + if (a == null) + { + return new ScriptNumberDouble(_rand.NextDouble()); + } + + if (b == null) + { + var max = Convert.ToInt32(a.ToCSharpObject()); + return new ScriptNumberLong(_rand.Next(max)); + } + else + { + var min = Convert.ToInt32(a.ToCSharpObject()); + var max = Convert.ToInt32(b.ToCSharpObject()); + return new ScriptNumberLong(_rand.Next(min, max)); + + } + } + + [ScriptFunction("randomseed", "Sets x as the \"seed\" for the pseudo-random generator: equal seeds produce equal sequences of numbers.", directScriptManipulation: true)] + public void RandomSeed(ScriptNumber a) + { + var v = a.ToCSharpObject().GetHashCode(); + _rand = new Random(v); + } + + [ScriptFunction("sin", "Returns the sine of x (assumed to be in radians).", directScriptManipulation: true)] + public ScriptNumber Sine(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Sin(((ScriptNumberDouble) a).Value)); + } + return new ScriptNumberDouble(Math.Sin(((ScriptNumberLong) a).Value)); + } + + [ScriptFunction("sqrt", "Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)", directScriptManipulation: true)] + public ScriptNumber SquareRoot(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Sqrt(((ScriptNumberDouble) a).Value)); + } + return new ScriptNumberDouble(Math.Sqrt(((ScriptNumberLong) a).Value)); + } + + [ScriptFunction("tan", "Returns the tangent of x (assumed to be in radians).", directScriptManipulation: true)] + public ScriptNumber Tangens(ScriptNumber a) + { + if (a.IsFloat) + { + return new ScriptNumberDouble(Math.Tan(((ScriptNumberDouble) a).Value)); + } + return new ScriptNumberDouble(Math.Tan(((ScriptNumberLong) a).Value)); + } + + [ScriptFunction("type", "Returns \"integer\" if x is an integer, \"float\" if it is a float.", directScriptManipulation: true)] + public ScriptString Type(ScriptNumber a) + { + return a.IsFloat ? new ScriptString("float") : new ScriptString("integer"); + } } } \ No newline at end of file