From c2b83a6779ea679aafc9f8263398a8181a4efbdc Mon Sep 17 00:00:00 2001 From: Jasper Date: Sun, 31 Dec 2017 16:50:18 +0100 Subject: [PATCH] Fixed Pow function to handle edge cases and wrote tests to check that they are handled correctly. --- .../System/MathTest.cs | 85 +++++++++++++++++++ .../Cosmos.System2_Plugs/System/MathImpl.cs | 44 +++++++++- 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/Tests/Cosmos.Compiler.Tests.Bcl/System/MathTest.cs b/Tests/Cosmos.Compiler.Tests.Bcl/System/MathTest.cs index 0c1bc4a76..ddebd21c3 100644 --- a/Tests/Cosmos.Compiler.Tests.Bcl/System/MathTest.cs +++ b/Tests/Cosmos.Compiler.Tests.Bcl/System/MathTest.cs @@ -46,6 +46,27 @@ namespace Cosmos.Compiler.Tests.Bcl.System result = Math.Exp(1.5); Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 4.48168907033806), "e^1.5 returns correct result"); + result = Math.Exp(0); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 1), "e^0 gives correct result"); + + result = Math.Exp(1); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, Math.E), "e^1 gives correct result"); + + result = Math.Exp(double.PositiveInfinity); + Assert.IsTrue(result == double.PositiveInfinity, "e^Infinity gives correct result"); + + result = Math.Exp(double.NegativeInfinity); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "e^-Infinity gives correct result"); + + result = Math.Exp(double.NaN); + Assert.IsTrue(double.IsNaN(result), "e^NaN gives correct result"); + + result = Math.Exp(double.MaxValue); + Assert.IsTrue(double.IsPositiveInfinity(result), "e^0 gives correct result"); + + result = Math.Exp(double.MinValue); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "e^0 gives correct result"); + #endregion Math.Exp #region Math.Pow @@ -69,6 +90,70 @@ namespace Cosmos.Compiler.Tests.Bcl.System result = Math.Pow(2, -1); Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0.5), "Pow gives correct results when handling negative powers"); + //Have double as base + result = Math.Pow(0.5, 2); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0.25), "Pow gives correct solution with double base"); + + //x = Nan + result = Math.Pow(double.NaN, 2); + Assert.IsTrue(double.IsNaN(result), "Pow gives correct solution when x is NaN"); + //Y = Nan + result = Math.Pow(10, double.NaN); + Assert.IsTrue(double.IsNaN(result), "Pow gives correct solution when y is NaN"); + //y = 0 + result = Math.Pow(10, 0); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 1), "Pow gives correct solution when y is 0"); + //x = -Inf y < 0 == 0 + result = Math.Pow(double.NegativeInfinity, -2); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "Pow gives correct solution when X is -INF and y is negative"); + //x = -Inf y > 0 && y is even == Inf + result = Math.Pow(double.NegativeInfinity, 2); + Assert.IsTrue(double.IsPositiveInfinity(result), "Pow gives correct solution when x is -INF and y is even"); + //x is -INF and y is positive odd == -INF + result = Math.Pow(double.NegativeInfinity, 3); + Assert.IsTrue(double.IsNegativeInfinity(result), "Pow gives correct solution when x is -INF and y is odd"); + //x < 0 && y is not integer or special case + result = Math.Pow(-3, 0.25); + Assert.IsTrue(double.IsNaN(result), "Pow gives correct solution when x is negative and y is non integer"); + //x = -1 && y is Inf == Nan + result = Math.Pow(-1, double.PositiveInfinity); + Assert.IsTrue(double.IsNaN(result), "Pow gives correct solution when x is -1 and y is INF"); + //x = -1 && y is -Inf == Nan + result = Math.Pow(-1, double.NegativeInfinity); + Assert.IsTrue(double.IsNaN(result), "Pow gives correct solution when x is -1 and y is -INF"); + //-1 < x < 1 + y = -Inf + result = Math.Pow(-0.25, double.NegativeInfinity); + Assert.IsTrue(double.IsPositiveInfinity(result), "Pow gives correct solution when -1 < x < 0 and y = -INF"); + result = Math.Pow(0.25, double.NegativeInfinity); + Assert.IsTrue(double.IsPositiveInfinity(result), "Pow gives correct solution when 0 < x < 1 and y = -INF"); + //-1 < x < 1 + y = Inf + result = Math.Pow(-0.25, double.PositiveInfinity); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "Pow gives correct solution when -1 < x < 0 and y is INF"); + result = Math.Pow(0.25, double.PositiveInfinity); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "Pow gives correct solution when 0 < x < 1 and y is INF"); + //-1 > x || x > 1 + y = -Inf + result = Math.Pow(-1.5, double.NegativeInfinity); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "Pow gives correct solution when x < -1 and y is -INF"); + result = Math.Pow(1.5, double.NegativeInfinity); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "Pow gives correct solution when x > 1 and y is -INF"); + //-1 > x || x > 1 + y = Inf + result = Math.Pow(-1.25, double.PositiveInfinity); + Assert.IsTrue(double.IsPositiveInfinity(result), "Pow gives correct solution when -1 > x and y = INF"); + result = Math.Pow(1.25, double.PositiveInfinity); + Assert.IsTrue(double.IsPositiveInfinity(result), "Pow gives correct solution when x > 1 and y = INF"); + //x = 0 y > 0 + result = Math.Pow(0, 2); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "Pow gives correct solution when x = 0 any y > 0 "); + //x = 0 y < 0 + result = Math.Pow(0, -3); + Assert.IsTrue(double.IsPositiveInfinity(result), "Pow gives correct solution when x is 0 and y < 0 "); + //x = inf y < 0 + result = Math.Pow(double.PositiveInfinity, -5); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "Pow gives correct solution when x is INF and y < 0 "); + //x = inf y > 0 + result = Math.Pow(double.PositiveInfinity, 5); + Assert.IsTrue(double.IsPositiveInfinity(result), "Pow gives correct solution when x is INF and y > 0 "); + #endregion Math.Pow } } diff --git a/source/Cosmos.System2_Plugs/System/MathImpl.cs b/source/Cosmos.System2_Plugs/System/MathImpl.cs index 1ad954928..33f7842f2 100644 --- a/source/Cosmos.System2_Plugs/System/MathImpl.cs +++ b/source/Cosmos.System2_Plugs/System/MathImpl.cs @@ -440,9 +440,51 @@ namespace Cosmos.System_Plugs.System { if (e == 0) return 1; if (e == 1) return b; + if (double.IsNaN(b) || double.IsNaN(e)) return double.NaN; + if (double.IsNegativeInfinity(b)) + { + if (e < 0) + return 0; + if ((long)e % 2 == 0) + return double.PositiveInfinity; + else + return double.NegativeInfinity; + } + if (double.IsPositiveInfinity(b)) + { + if (e < 0) + return 0; + else + return double.PositiveInfinity; + } + if (double.IsInfinity(e)) + { + bool t = -1 < b; + bool t1 = 1 > b; + if (t && t1) + + if (double.IsPositiveInfinity(e)) + return 0; + else + return double.PositiveInfinity; + else + { + bool v = b < -1; + bool v1 = 1 < b; + if (v || v1) + { + if (double.IsPositiveInfinity(e)) + return double.PositiveInfinity; + else + return 0; + } + else + return double.NaN; + } + } if (b < 0) { - if (Math.Abs(e % 1) <= (Double.Epsilon * 100)) throw new ArgumentException("This will produce non-real answer"); + if (Math.Abs(e) - Math.Abs((int)e) > (Double.Epsilon * 100)) return double.NaN; double logedBase = Math.Log(Math.Abs(b)); double pow = Exp(logedBase * e); if ((long)e % 2 == 0) return pow;