diff --git a/src/Core/FunctionValue.cs b/src/Core/FunctionValue.cs index 9d74307..e40a5dc 100644 --- a/src/Core/FunctionValue.cs +++ b/src/Core/FunctionValue.cs @@ -17,6 +17,7 @@ namespace CSMic public static readonly FunctionValue NONE = new FunctionValue(FunctionValueType.None, null); public static readonly FunctionValue NUMBER = new FunctionValue(FunctionValueType.Numeric, 0m); public static readonly FunctionValue STRING = new FunctionValue(FunctionValueType.String, string.Empty); + public static readonly FunctionValue ZERO = new FunctionValue(FunctionValueType.Numeric, 0m); public FunctionValue() { diff --git a/src/StandardLibrary/Constants.cs b/src/StandardLibrary/Constants.cs deleted file mode 100644 index dacfc9f..0000000 --- a/src/StandardLibrary/Constants.cs +++ /dev/null @@ -1,23 +0,0 @@ -using CSMic; - -namespace CSMic.StandardLibrary -{ - public static class Constants - { - public static void Initialize(InputInterpreter inputInterpreter) - { - if(inputInterpreter == null) - { - throw new ArgumentNullException("inputInterpreter", "Cannot initialize a null InputInterpreter."); - } - - inputInterpreter.Interpret("pi :: 3.1415926535897931"); - inputInterpreter.Interpret("e :: 2.7182818284590451"); - inputInterpreter.Interpret("tau :: 6.2831853071795862"); - inputInterpreter.Interpret("phi :: 1.6180339887498948"); - inputInterpreter.Interpret("goldenratio :: 1.6180339887498948"); - inputInterpreter.Interpret("eurler :: 0.5772156649015329"); - inputInterpreter.Interpret("omega :: 0.5671432904097839"); - } - } -} diff --git a/src/StandardLibrary/Functions.cs b/src/StandardLibrary/Functions.cs deleted file mode 100644 index 10c88fe..0000000 --- a/src/StandardLibrary/Functions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using CSMic; -using CSMic.StandardLibrary.Functions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CSMic.StandardLibrary -{ - public static class Functions - { - public static void Initialize(InputInterpreter inputInterpreter) - { - if (inputInterpreter == null) - { - throw new ArgumentNullException("inputInterpreter", "Cannot initialize a null InputInterpreter."); - } - - inputInterpreter.RegisterFunction(new AbsoluteValue()); - inputInterpreter.RegisterFunction(new Sign()); - inputInterpreter.RegisterFunction(new Min()); - inputInterpreter.RegisterFunction(new Max()); - } - } -} diff --git a/src/StandardLibrary/Functions/Angle/Degrees.cs b/src/StandardLibrary/Functions/Angle/Degrees.cs new file mode 100644 index 0000000..ac2e53f --- /dev/null +++ b/src/StandardLibrary/Functions/Angle/Degrees.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Angle +{ + public class Degrees : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "degrees"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, double.DegreesToRadians((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Angle/Radians.cs b/src/StandardLibrary/Functions/Angle/Radians.cs new file mode 100644 index 0000000..07c69f6 --- /dev/null +++ b/src/StandardLibrary/Functions/Angle/Radians.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Angle +{ + public class Radians : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "radians"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, double.RadiansToDegrees((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Angle/WrapAngle.cs b/src/StandardLibrary/Functions/Angle/WrapAngle.cs new file mode 100644 index 0000000..987166e --- /dev/null +++ b/src/StandardLibrary/Functions/Angle/WrapAngle.cs @@ -0,0 +1,43 @@ +namespace CSMic.StandardLibrary.Functions.Angle +{ + public class WrapAngle : FunctionBase, ICodedFunction + { + public string Name + { + get + { + return "wrapangle"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + yield return new FunctionArgument("periodStart", FunctionValue.NUMBER); + yield return new FunctionArgument("periodEnd", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var inputValue = _args[0].Value; + decimal value = Convert.ToDecimal(inputValue.Value); + var inputPeriodStart = _args[1].Value; + decimal periodStart = Convert.ToDecimal(inputPeriodStart.Value); + var inputPeriodEnd = _args[2].Value; + decimal periodEnd = Convert.ToDecimal(inputPeriodEnd.Value); + + // Perform modulo. + decimal width = periodEnd - periodStart; + decimal modulus = value % width; + modulus = modulus < 0 ? modulus + width : modulus; + + return new FunctionValue(FunctionValueType.Numeric, modulus); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/NumberTheory/BinomialCoefficient.cs b/src/StandardLibrary/Functions/NumberTheory/BinomialCoefficient.cs new file mode 100644 index 0000000..d4f1f57 --- /dev/null +++ b/src/StandardLibrary/Functions/NumberTheory/BinomialCoefficient.cs @@ -0,0 +1,68 @@ +using CSMic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CSMic.StandardLibrary.Functions.NumberTheory +{ + public class BinomialCoefficient : FunctionBase, ICodedFunction + { + public string Name + { + get + { + return "ncr"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("first", FunctionValue.NUMBER); + yield return new FunctionArgument("second", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var inputFirst = _args[0].Value; + var inputSecond = _args[1].Value; + decimal first = Convert.ToDecimal(inputFirst.Value); + decimal second = Convert.ToDecimal(inputSecond.Value); + + if (first < 0 || first > 20 || second < 0 || second > 20 || first - second < 0) + { + return FunctionValue.ZERO; + } + + if(Math.Floor(first) != first || Math.Floor(second) != second) + { + return FunctionValue.ZERO; + } + + int n = Convert.ToInt32(first); + int r = Convert.ToInt32(second); + decimal nFac = Factorial.INTEGER_FACTORIAL_LOOKUP[n]; + decimal rFac = Factorial.INTEGER_FACTORIAL_LOOKUP[r]; + decimal nmrFac = Factorial.INTEGER_FACTORIAL_LOOKUP[n - r]; + + try + { + decimal combinations = (nFac) / (rFac * nmrFac); + + return new FunctionValue(FunctionValueType.Numeric, combinations); + } + catch + { + // Last chance emergency fail if the decimal value is exceeded. + return FunctionValue.ZERO; + } + }); + } + } +} diff --git a/src/StandardLibrary/Functions/NumberTheory/Factorial.cs b/src/StandardLibrary/Functions/NumberTheory/Factorial.cs new file mode 100644 index 0000000..fb9c2cf --- /dev/null +++ b/src/StandardLibrary/Functions/NumberTheory/Factorial.cs @@ -0,0 +1,110 @@ +using CSMic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CSMic.StandardLibrary.Functions.NumberTheory +{ + public class Factorial : FunctionBase, ICodedFunction + { + private static readonly double[] LANCZOS_APPROXIMATION = + { + 0.99999999999980993, + 676.5203681218851, + -1259.1392167224028, + 771.32342877765313, + -176.61502916214059, + 12.507343278686905, + -0.13857109526572012, + 9.9843695780195716e-6, + 1.5056327351493116e-7 + }; + + public static readonly decimal[] INTEGER_FACTORIAL_LOOKUP = + { + /* 0 */ 1, + /* 1 */ 1, + /* 2 */ 2, + /* 3 */ 6, + /* 4 */ 24, + /* 5 */ 120, + /* 6 */ 720, + /* 7 */ 5040, + /* 8 */ 40320, + /* 9 */ 362880, + /* 10 */ 3628800, + /* 11 */ 39916800, + /* 12 */ 479001600, + /* 13 */ 62207020800, + /* 14 */ 87178291200, + /* 15 */ 1307674368000, + /* 16 */ 20922789888000, + /* 17 */ 355687428096000, + /* 18 */ 6402373705728000, + /* 19 */ 121645100408832000, + /* 20 */ 2432902008176640000 + }; + + public string Name + { + get + { + return "fac"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var inputValue = _args[0].Value; + decimal value = Convert.ToDecimal(inputValue.Value); + + if (value < 0) + { + return FunctionValue.ZERO; + } + if (value > 20) + { + return FunctionValue.ZERO; + } + + if (Math.Floor(value) == value) + { + // Input is an integer. We'll just use the lookup table. + var index = Convert.ToInt32(value); + return new FunctionValue(FunctionValueType.Numeric, INTEGER_FACTORIAL_LOOKUP[index]); + } + + double gammaFactorial = Gamma(Convert.ToDouble(value) + 1); + + return new FunctionValue(FunctionValueType.Numeric, Convert.ToDecimal(gammaFactorial)); + }); + } + + private static double Gamma(double shiftedGama) + { + if (shiftedGama < 0.5) + return Math.PI / (Math.Sin(Math.PI * shiftedGama) * Gamma(1 - shiftedGama)); + + shiftedGama -= 1; + double accumulator = LANCZOS_APPROXIMATION[0]; + for (int i = 1; i < LANCZOS_APPROXIMATION.Length; i++) + accumulator += LANCZOS_APPROXIMATION[i] / (shiftedGama + i); + + double shiftedVariable = shiftedGama + 7.5; + return Math.Sqrt(2 * Math.PI) * Math.Pow(shiftedVariable, shiftedGama + 0.5) * Math.Exp(-shiftedVariable) * accumulator; + } + + } +} diff --git a/src/StandardLibrary/Functions/NumberTheory/GreatedCommonDenomitator.cs b/src/StandardLibrary/Functions/NumberTheory/GreatedCommonDenomitator.cs new file mode 100644 index 0000000..0d1cfe3 --- /dev/null +++ b/src/StandardLibrary/Functions/NumberTheory/GreatedCommonDenomitator.cs @@ -0,0 +1,65 @@ +using CSMic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CSMic.StandardLibrary.Functions.NumberTheory +{ + public class GreatestCommonDevisor : FunctionBase, ICodedFunction + { + public string Name + { + get + { + return "gcd"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("first", FunctionValue.NUMBER); + yield return new FunctionArgument("second", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var inputFirst = _args[0].Value; + var inputSecond = _args[1].Value; + decimal first = Convert.ToDecimal(inputFirst.Value); + decimal second = Convert.ToDecimal(inputSecond.Value); + + if (first <= 0 || second <= 0) + { + return FunctionValue.ZERO; + } + + if (Math.Floor(first) != first || Math.Floor(second) != second) + { + return FunctionValue.ZERO; + } + + decimal gcd = EuclideanAlgorithm(first, second); + decimal lcd = (first * second) / gcd; + + return new FunctionValue(FunctionValueType.Numeric, lcd); + }); + } + + public decimal EuclideanAlgorithm(decimal first, decimal second) + { + if(second == 0) + { + return first; + } + + return EuclideanAlgorithm(second, first % second); + } + } +} diff --git a/src/StandardLibrary/Functions/NumberTheory/LeastCommonMultiple.cs b/src/StandardLibrary/Functions/NumberTheory/LeastCommonMultiple.cs new file mode 100644 index 0000000..54ae01f --- /dev/null +++ b/src/StandardLibrary/Functions/NumberTheory/LeastCommonMultiple.cs @@ -0,0 +1,62 @@ +using CSMic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CSMic.StandardLibrary.Functions.NumberTheory +{ + public class LeastCommonMultiple : FunctionBase, ICodedFunction + { + public string Name + { + get + { + return "gcd"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("first", FunctionValue.NUMBER); + yield return new FunctionArgument("second", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var inputFirst = _args[0].Value; + var inputSecond = _args[1].Value; + decimal first = Convert.ToDecimal(inputFirst.Value); + decimal second = Convert.ToDecimal(inputSecond.Value); + + if (first <= 0 || second <= 0) + { + return FunctionValue.ZERO; + } + + if (Math.Floor(first) != first || Math.Floor(second) != second) + { + return FunctionValue.ZERO; + } + + return new FunctionValue(FunctionValueType.Numeric, EuclideanAlgorithm(first, second)); + }); + } + + public decimal EuclideanAlgorithm(decimal first, decimal second) + { + if(second == 0) + { + return first; + } + + return EuclideanAlgorithm(second, first % second); + } + } +} diff --git a/src/StandardLibrary/Functions/NumberTheory/Permutations.cs b/src/StandardLibrary/Functions/NumberTheory/Permutations.cs new file mode 100644 index 0000000..20a4144 --- /dev/null +++ b/src/StandardLibrary/Functions/NumberTheory/Permutations.cs @@ -0,0 +1,67 @@ +using CSMic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CSMic.StandardLibrary.Functions.NumberTheory +{ + public class Permutations : FunctionBase, ICodedFunction + { + public string Name + { + get + { + return "npr"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("first", FunctionValue.NUMBER); + yield return new FunctionArgument("second", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var inputFirst = _args[0].Value; + var inputSecond = _args[1].Value; + decimal first = Convert.ToDecimal(inputFirst.Value); + decimal second = Convert.ToDecimal(inputSecond.Value); + + if (first < 0 || first > 20 || second < 0 || second > 20 || first - second < 0) + { + return FunctionValue.ZERO; + } + + if(Math.Floor(first) != first || Math.Floor(second) != second) + { + return FunctionValue.ZERO; + } + + int n = Convert.ToInt32(first); + int r = Convert.ToInt32(second); + decimal nFac = Factorial.INTEGER_FACTORIAL_LOOKUP[n]; + decimal nmrFac = Factorial.INTEGER_FACTORIAL_LOOKUP[n - r]; + + try + { + decimal combinations = (nFac) / (nmrFac); + + return new FunctionValue(FunctionValueType.Numeric, combinations); + } + catch + { + // Last chance emergency fail if the decimal value is exceeded. + return FunctionValue.ZERO; + } + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Random/Bernoulli.cs b/src/StandardLibrary/Functions/Random/Bernoulli.cs new file mode 100644 index 0000000..dd7261e --- /dev/null +++ b/src/StandardLibrary/Functions/Random/Bernoulli.cs @@ -0,0 +1,45 @@ +using CSMic; +using CSMic.StandardLibrary.Functions.Random; + +namespace CSMic.StandardLibrary.Functions.Random +{ + public class Bernoulli : RandomBase, ICodedFunction + { + public string Name + { + get + { + return "bern"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("p", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var input = _args[0].Value; + decimal pValue = Convert.ToDecimal(input.Value); + + if(pValue < 0m || pValue > 1m) + { + throw new ArgumentOutOfRangeException(nameof(pValue), "The p value must be between 0 and 1."); + } + + if(NextDecimal() < pValue) + { + return FunctionValue.TRUE; + } + + return FunctionValue.FALSE; + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Random/FairFlip.cs b/src/StandardLibrary/Functions/Random/FairFlip.cs new file mode 100644 index 0000000..32e6382 --- /dev/null +++ b/src/StandardLibrary/Functions/Random/FairFlip.cs @@ -0,0 +1,37 @@ +using CSMic; +using CSMic.StandardLibrary.Functions.Random; + +namespace CSMic.StandardLibrary.Functions.Random +{ + public class FairFlip : RandomBase, ICodedFunction + { + public string Name + { + get + { + return "flip"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield break; + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + if(NextDecimal() < 0.5m) + { + return FunctionValue.TRUE; + } + + return FunctionValue.FALSE; + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Random/RandomBase.cs b/src/StandardLibrary/Functions/Random/RandomBase.cs new file mode 100644 index 0000000..8578e43 --- /dev/null +++ b/src/StandardLibrary/Functions/Random/RandomBase.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CSMic.StandardLibrary.Functions.Random +{ + public abstract class RandomBase : FunctionBase + { + protected static System.Random RandomNumberGenerator + { + get + { + return System.Random.Shared; + } + } + + protected static decimal NextDecimal() + { + return Convert.ToDecimal(RandomNumberGenerator.NextDouble()); + } + + protected static decimal NextDecimalNormal() + { + double u1 = 1.0 - RandomNumberGenerator.NextDouble(); + double u2 = 1.0 - RandomNumberGenerator.NextDouble(); + double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * + Math.Sin(2.0 * Math.PI * u2); + return Convert.ToDecimal(randStdNormal); + } + } +} diff --git a/src/StandardLibrary/Functions/Random/RandomNormal.cs b/src/StandardLibrary/Functions/Random/RandomNormal.cs new file mode 100644 index 0000000..fa8f6a1 --- /dev/null +++ b/src/StandardLibrary/Functions/Random/RandomNormal.cs @@ -0,0 +1,32 @@ +using CSMic; +using CSMic.StandardLibrary.Functions.Random; + +namespace CSMic.StandardLibrary.Functions.Random +{ + public class RandomNormal : RandomBase, ICodedFunction + { + public string Name + { + get + { + return "randn"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield break; + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + return new FunctionValue(FunctionValueType.Numeric, NextDecimalNormal()); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Random/RandomNormalSpread.cs b/src/StandardLibrary/Functions/Random/RandomNormalSpread.cs new file mode 100644 index 0000000..85897ae --- /dev/null +++ b/src/StandardLibrary/Functions/Random/RandomNormalSpread.cs @@ -0,0 +1,43 @@ +using CSMic; +using CSMic.StandardLibrary.Functions.Random; + +namespace CSMic.StandardLibrary.Functions.Random +{ + public class RandomNormalSpread : RandomBase, ICodedFunction + { + public string Name + { + get + { + return "randns"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("lower", FunctionValue.NUMBER); + yield return new FunctionArgument("upper", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var inputLower = _args[0].Value; + var inputUpper = _args[1].Value; + decimal lower = Convert.ToDecimal(inputLower.Value); + decimal upper = Convert.ToDecimal(inputUpper.Value); + + if(upper <= lower) + { + return FunctionValue.ZERO; + } + + return new FunctionValue(FunctionValueType.Numeric, NextDecimalNormal() * (upper - lower)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Random/RandomUniform.cs b/src/StandardLibrary/Functions/Random/RandomUniform.cs new file mode 100644 index 0000000..cb388bb --- /dev/null +++ b/src/StandardLibrary/Functions/Random/RandomUniform.cs @@ -0,0 +1,32 @@ +using CSMic; +using CSMic.StandardLibrary.Functions.Random; + +namespace CSMic.StandardLibrary.Functions.Random +{ + public class RandomUniform : RandomBase, ICodedFunction + { + public string Name + { + get + { + return "rand"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield break; + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + return new FunctionValue(FunctionValueType.Numeric, NextDecimal()); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Random/RandomUniformSpread.cs b/src/StandardLibrary/Functions/Random/RandomUniformSpread.cs new file mode 100644 index 0000000..97e7293 --- /dev/null +++ b/src/StandardLibrary/Functions/Random/RandomUniformSpread.cs @@ -0,0 +1,43 @@ +using CSMic; +using CSMic.StandardLibrary.Functions.Random; + +namespace CSMic.StandardLibrary.Functions.Random +{ + public class RandomUniformSpread : RandomBase, ICodedFunction + { + public string Name + { + get + { + return "rands"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("lower", FunctionValue.NUMBER); + yield return new FunctionArgument("upper", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var inputLower = _args[0].Value; + var inputUpper = _args[1].Value; + decimal lower = Convert.ToDecimal(inputLower.Value); + decimal upper = Convert.ToDecimal(inputUpper.Value); + + if(upper <= lower) + { + return FunctionValue.ZERO; + } + + return new FunctionValue(FunctionValueType.Numeric, NextDecimal() * (upper - lower)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Rounding/Ceiling.cs b/src/StandardLibrary/Functions/Rounding/Ceiling.cs new file mode 100644 index 0000000..9881679 --- /dev/null +++ b/src/StandardLibrary/Functions/Rounding/Ceiling.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Rounding +{ + public class Ceiling : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "ceiling"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Ceiling(value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Rounding/Clamp.cs b/src/StandardLibrary/Functions/Rounding/Clamp.cs new file mode 100644 index 0000000..71ba157 --- /dev/null +++ b/src/StandardLibrary/Functions/Rounding/Clamp.cs @@ -0,0 +1,39 @@ +namespace CSMic.StandardLibrary.Functions.Rounding +{ + public class Clamp : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "clamp"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + yield return new FunctionArgument("low", FunctionValue.NUMBER); + yield return new FunctionArgument("high", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var inputValue = _args[0].Value; + decimal value = Convert.ToDecimal(inputValue.Value); + var inputLow = _args[1].Value; + decimal low = Convert.ToDecimal(inputLow.Value); + var inputHigh = _args[2].Value; + decimal high = Convert.ToDecimal(inputHigh.Value); + + return new FunctionValue(FunctionValueType.Numeric, value < low ? low : value > high ? high : value); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Rounding/Floor.cs b/src/StandardLibrary/Functions/Rounding/Floor.cs new file mode 100644 index 0000000..bc4a028 --- /dev/null +++ b/src/StandardLibrary/Functions/Rounding/Floor.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Rounding +{ + public class Floor : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "floor"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Floor(value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Rounding/Fractional.cs b/src/StandardLibrary/Functions/Rounding/Fractional.cs new file mode 100644 index 0000000..c1442ab --- /dev/null +++ b/src/StandardLibrary/Functions/Rounding/Fractional.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Rounding +{ + public class Fractional : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "frac"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, value - Math.Truncate(value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Rounding/Round.cs b/src/StandardLibrary/Functions/Rounding/Round.cs new file mode 100644 index 0000000..18305a9 --- /dev/null +++ b/src/StandardLibrary/Functions/Rounding/Round.cs @@ -0,0 +1,37 @@ +namespace CSMic.StandardLibrary.Functions.Rounding +{ + public class Round : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "round"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var inputValue = _args[0].Value; + decimal value = Convert.ToDecimal(inputValue.Value); + var inputPrecision = _args[1].Value; + decimal precision = Convert.ToDecimal(inputValue.Value); + precision = Math.Round(precision); + int precisionInt = Convert.ToInt32(precision); + + return new FunctionValue(FunctionValueType.Numeric, Math.Round(value, precisionInt)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Rounding/Truncate.cs b/src/StandardLibrary/Functions/Rounding/Truncate.cs new file mode 100644 index 0000000..ac1c483 --- /dev/null +++ b/src/StandardLibrary/Functions/Rounding/Truncate.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Rounding +{ + public class Trancate : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "truncate"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Truncate(value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Acos.cs b/src/StandardLibrary/Functions/Trigonometry/Acos.cs new file mode 100644 index 0000000..37e2e6f --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Acos.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry +{ + public class Acos : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "acos"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Acos((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Asin.cs b/src/StandardLibrary/Functions/Trigonometry/Asin.cs new file mode 100644 index 0000000..c5de34b --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Asin.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry +{ + public class Asin : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "asin"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Asin((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Atan.cs b/src/StandardLibrary/Functions/Trigonometry/Atan.cs new file mode 100644 index 0000000..2c61574 --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Atan.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry +{ + public class Atan : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "atan"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Atan((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Atan2.cs b/src/StandardLibrary/Functions/Trigonometry/Atan2.cs new file mode 100644 index 0000000..0e1e389 --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Atan2.cs @@ -0,0 +1,36 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry +{ + public class Atan2 : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "atan2"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var inputFirst = _args[0].Value; + decimal valueFirst = Convert.ToDecimal(inputFirst.Value); + var inputSecond = _args[1].Value; + decimal valueSecond = Convert.ToDecimal(inputSecond.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Atan2((double)valueFirst, (double)valueSecond)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Cos.cs b/src/StandardLibrary/Functions/Trigonometry/Cos.cs new file mode 100644 index 0000000..efec96a --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Cos.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry +{ + public class Cos : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "cos"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Cos((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Acosh.cs b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Acosh.cs new file mode 100644 index 0000000..96712db --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Acosh.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry.Hyperbolic +{ + public class Acosh : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "acosh"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Acosh((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Asinh.cs b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Asinh.cs new file mode 100644 index 0000000..e84c2d7 --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Asinh.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry.Hyperbolic +{ + public class Asinh : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "asinh"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Asinh((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Atanh.cs b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Atanh.cs new file mode 100644 index 0000000..a768e51 --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Atanh.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry.Hyperbolic +{ + public class Atanh : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "atanh"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Atanh((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Cosh.cs b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Cosh.cs new file mode 100644 index 0000000..8ed7376 --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Cosh.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry.Hyperbolic +{ + public class Cosh : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "cosh"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Cosh((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Sinh.cs b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Sinh.cs new file mode 100644 index 0000000..cd30688 --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Sinh.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry.Hyperbolic +{ + public class Sinh : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "sinh"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Sinh((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Tanh.cs b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Tanh.cs new file mode 100644 index 0000000..3ea2ae8 --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Hyperbolic/Tanh.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry.Hyperbolic +{ + public class Tanh : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "tanh"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Tanh((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Sin.cs b/src/StandardLibrary/Functions/Trigonometry/Sin.cs new file mode 100644 index 0000000..df0a48f --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Sin.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry +{ + public class Sin : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "sin"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Sin((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Functions/Trigonometry/Tan.cs b/src/StandardLibrary/Functions/Trigonometry/Tan.cs new file mode 100644 index 0000000..68e0fe5 --- /dev/null +++ b/src/StandardLibrary/Functions/Trigonometry/Tan.cs @@ -0,0 +1,33 @@ +namespace CSMic.StandardLibrary.Functions.Trigonometry +{ + public class Tan : FunctionBase, ICodedFunction + { + + public string Name + { + get + { + return "tan"; + } + } + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return Execute(args, (_args) => + { + var input = _args[0].Value; + decimal value = Convert.ToDecimal(input.Value); + + return new FunctionValue(FunctionValueType.Numeric, Math.Tan((double)value)); + }); + } + } +} diff --git a/src/StandardLibrary/Initializer.cs b/src/StandardLibrary/Initializer.cs new file mode 100644 index 0000000..e3eb5de --- /dev/null +++ b/src/StandardLibrary/Initializer.cs @@ -0,0 +1,76 @@ +using CSMic.StandardLibrary.Functions; +using CSMic.StandardLibrary.Functions.Angle; + +namespace CSMic.StandardLibrary +{ + public static class Initializer + { + public static void InitializeAll(InputInterpreter interpreter) + { + InitializeAllFunctions(interpreter); + InitializeConstants(interpreter); + } + + public static void InitializeAllFunctions(InputInterpreter inputInterpreter) + { + if (inputInterpreter == null) + { + throw new ArgumentNullException("inputInterpreter", "Cannot initialize a null InputInterpreter."); + } + + InitializeBaseFunctions(inputInterpreter); + } + + public static void InitializeBaseFunctions(InputInterpreter inputInterpreter) + { + if (inputInterpreter == null) + { + throw new ArgumentNullException("inputInterpreter", "Cannot initialize a null InputInterpreter."); + } + + inputInterpreter.RegisterFunction(new AbsoluteValue()); + inputInterpreter.RegisterFunction(new Sign()); + inputInterpreter.RegisterFunction(new Min()); + inputInterpreter.RegisterFunction(new Max()); + } + + public static void InitializeAngleFunctions(InputInterpreter inputInterpreter) + { + if (inputInterpreter == null) + { + throw new ArgumentNullException("inputInterpreter", "Cannot initialize a null InputInterpreter."); + } + + inputInterpreter.RegisterFunction(new Degrees()); + inputInterpreter.RegisterFunction(new Radians()); + inputInterpreter.RegisterFunction(new WrapAngle()); + } + + public static void InitializeNumberTheoryFunctions(InputInterpreter inputInterpreter) + { + if (inputInterpreter == null) + { + throw new ArgumentNullException("inputInterpreter", "Cannot initialize a null InputInterpreter."); + } + + // Register functions... + } + + public static void InitializeConstants(InputInterpreter inputInterpreter) + { + if (inputInterpreter == null) + { + throw new ArgumentNullException("inputInterpreter", "Cannot initialize a null InputInterpreter."); + } + + inputInterpreter.Interpret("pi :: 3.1415926535897931"); + inputInterpreter.Interpret("e :: 2.7182818284590451"); + inputInterpreter.Interpret("tau :: 6.2831853071795862"); + inputInterpreter.Interpret("phi :: 1.6180339887498948"); + inputInterpreter.Interpret("goldenratio :: 1.6180339887498948"); + inputInterpreter.Interpret("eurler :: 0.5772156649015329"); + inputInterpreter.Interpret("omega :: 0.5671432904097839"); + } + } +} + diff --git a/src/StandardLibrary/functions/Sign.cs b/src/StandardLibrary/functions/Sign.cs index 8d9c48a..f75dace 100644 --- a/src/StandardLibrary/functions/Sign.cs +++ b/src/StandardLibrary/functions/Sign.cs @@ -5,8 +5,8 @@ namespace CSMic.StandardLibrary.Functions { public class Sign : FunctionBase, ICodedFunction { - public const decimal POSITIVE = 1; - public const decimal NEGATIVE = -1; + private const decimal POSITIVE = 1; + private const decimal NEGATIVE = -1; public string Name {