diff --git a/Math expression eval/UnitTest/TestAll.cs b/Math expression eval/UnitTest/TestAll.cs index 48fef10..af90adf 100644 --- a/Math expression eval/UnitTest/TestAll.cs +++ b/Math expression eval/UnitTest/TestAll.cs @@ -1188,5 +1188,77 @@ public void Or_Operator_Test() .Bind("b", 1); Assert.AreEqual(true, expr4.Eval()); } + + [TestMethod] + public void Rand_0Parameters_Test() + { + var expr1 = new Expression("Rand()"); + // Shouldn't error + var _ = expr1.Eval(); + } + + [DataTestMethod] + [DataRow("xxx")] + [DataRow(1d)] + [DataRow(true)] + [DataRow(false)] + public void Rand_1Parameter_Test(object seed) + { + string seedString = seed is string ? $"\"{seed.ToString()}\"" : seed.ToString(); + var expr = new Expression($"Rand({seedString})"); + var random = new Random(seed.GetHashCode()); + var expected = Math.Round(random.NextDouble(), 6); + + // Seed should always return same value + Assert.AreEqual(expected, expr.Eval()); + } + + [TestMethod] + public void Rand_2Parameters_Test() + { + var expr = new Expression("Rand(10,12)"); + bool got10 = false; + bool got11 = false; + for (int count = 0; count < 1000; count++) + { + // Either 10 or 11 + var actual = expr.Eval(); + if (actual == 10) + { + got10 = true; + } + else if (actual == 11) + { + got11 = true; + } + else + { + Assert.Fail("Expected 10 or 11"); + } + if (got10 && got11) // Stop if you found a 10 and 11 + break; + } + + if (!got10 || !got11) + { + Assert.Fail("Expected 10 or 11"); + } + } + + [DataTestMethod] + [DataRow("seed")] + [DataRow(1d)] + [DataRow(true)] + [DataRow(false)] + public void Rand_3Parameters_Test(object seed) + { + string seedString = seed is string ? $"\"{seed.ToString()}\"" : seed.ToString(); + var expr = new Expression($"Rand({seedString},1000,2000)"); + var random = new Random(seed.GetHashCode()); + var expected = random.Next(1000, 2000); + + // Seed should always return same value + Assert.AreEqual(expected, expr.Eval()); + } } } diff --git a/Math expression eval/org.matheval/Functions/Impl/randFunction.cs b/Math expression eval/org.matheval/Functions/Impl/randFunction.cs index 6f224fa..0640aad 100644 --- a/Math expression eval/org.matheval/Functions/Impl/randFunction.cs +++ b/Math expression eval/org.matheval/Functions/Impl/randFunction.cs @@ -39,7 +39,15 @@ public class randFunction : IFunction public List GetInfo() { return new List{ - new FunctionDef(Afe_Common.Const_Random, null, typeof(decimal), 0)}; + // None + new FunctionDef(Afe_Common.Const_Random, null, typeof(decimal), 0), + // Seed + new FunctionDef(Afe_Common.Const_Random, new[]{ typeof(object) }, typeof(decimal), 1), + // Min, Max + new FunctionDef(Afe_Common.Const_Random, new[]{ typeof(decimal), typeof(decimal) }, typeof(decimal), 2), + // Seed, Min, Max + new FunctionDef(Afe_Common.Const_Random, new[]{ typeof(object), typeof(decimal), typeof(decimal) }, typeof(decimal), 3) + }; } /// @@ -50,9 +58,49 @@ public List GetInfo() /// Value public Object Execute(Dictionary args, ExpressionContext dc) { - // Random r = new Random(); - //return Afe_Common.Round(r.Next(), dc); - return Convert.ToDecimal(new Random().NextDouble(), dc.WorkingCulture); + Random r = args.Count == 1 || args.Count == 3 + ? new Random(args[Afe_Common.Const_Key_One].GetHashCode()) + : new Random(); + + switch (args.Count) + { + case 2: + return Convert.ToDecimal + ( + r.Next + ( + Convert.ToInt32 + ( + Afe_Common.ToDecimal(args[Afe_Common.Const_Key_One], dc.WorkingCulture) + , dc.WorkingCulture + ), + Convert.ToInt32 + ( + Afe_Common.ToDecimal(args[Afe_Common.Const_Key_Two], dc.WorkingCulture) + , dc.WorkingCulture + ) + ) + ); + case 3: + return Convert.ToDecimal + ( + r.Next + ( + Convert.ToInt32 + ( + Afe_Common.ToDecimal(args[Afe_Common.Const_Key_Two], dc.WorkingCulture) + , dc.WorkingCulture + ), + Convert.ToInt32 + ( + Afe_Common.ToDecimal(args[Afe_Common.Const_Key_Three], dc.WorkingCulture) + , dc.WorkingCulture + ) + ) + ); + default: + return Convert.ToDecimal(r.NextDouble(), dc.WorkingCulture); + } } } }