From 4cb8d65752bb555457a91c6484b9550729b9f520 Mon Sep 17 00:00:00 2001 From: Quajak Date: Sun, 25 Feb 2018 21:10:10 +0100 Subject: [PATCH] Added Math.Floor function with tests (Tests are simply copied from ceiling and changed results) --- .../System/MathTest.cs | 43 ++++++++++ .../Cosmos.System2_Plugs/System/MathImpl.cs | 81 +++++++++++++++++-- 2 files changed, 118 insertions(+), 6 deletions(-) diff --git a/Tests/Cosmos.Compiler.Tests.Bcl/System/MathTest.cs b/Tests/Cosmos.Compiler.Tests.Bcl/System/MathTest.cs index d61b85870..a57086554 100644 --- a/Tests/Cosmos.Compiler.Tests.Bcl/System/MathTest.cs +++ b/Tests/Cosmos.Compiler.Tests.Bcl/System/MathTest.cs @@ -91,6 +91,49 @@ namespace Cosmos.Compiler.Tests.Bcl.System #endregion Ceiling + #region Floor + + result = Math.Floor(0d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 0), "Floor gives correct value for 0"); + + result = Math.Floor(1d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 1), "Floor gives correct value for 1"); + + result = Math.Floor(-1d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, -1), "Floor gives correct value for -1"); + + result = Math.Floor(2.5d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 2), "Floor gives correct value for 2.5"); + + result = Math.Floor(-2.5d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, -3), "Floor gives correct value for -2.5"); + + result = Math.Floor(11.2d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 11), "Floor gives correct value for 11.2"); + + result = Math.Floor(-11.2d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, -12), "Floor gives correct value for -11.2"); + + result = Math.Floor(32.8d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, 32), "Floor gives correct value for 32.8"); + + result = Math.Floor(-32.8d); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, -33), "Floor gives correct value for -32.8"); + + result = Math.Floor(double.NaN); + Assert.IsTrue(double.IsNaN(result), "Floor gives correct value for NaN"); + + result = Math.Floor(double.PositiveInfinity); + Assert.IsTrue(double.IsPositiveInfinity(result), "Floor gives correct value for INF"); + + result = Math.Floor(double.NegativeInfinity); + Assert.IsTrue(double.IsNegativeInfinity(result), "Floor gives correct value for -INF"); + + result = Math.Floor((double)int.MaxValue + 2.5); + Assert.IsTrue(EqualityHelper.DoublesAreEqual(result, (double)int.MaxValue + 2), "Floor works for values larger than an int can hold. " + result + " expected " + (double)int.MaxValue + 2); + + #endregion Floor + #region Math.Cos result = Math.Cos(4); diff --git a/source/Cosmos.System2_Plugs/System/MathImpl.cs b/source/Cosmos.System2_Plugs/System/MathImpl.cs index a17276df3..7138a1574 100644 --- a/source/Cosmos.System2_Plugs/System/MathImpl.cs +++ b/source/Cosmos.System2_Plugs/System/MathImpl.cs @@ -654,13 +654,82 @@ namespace Cosmos.System_Plugs.System #region Floor - public static double Floor(double a) + public static double Floor(double x) { - // should be using assembler for bigger values than int or long max - if (a == Double.NaN || a == Double.NegativeInfinity || a == Double.PositiveInfinity) - return a; - int i = (a - (int)a < 0) ? (int)(a - 1) : (int)a; - return i; + if (double.IsInfinity(x) || double.IsNaN(x)) return x; + + int i0, i1, j0; + uint i, j; + i0 = HighWord(x); + i1 = LowWord(x); + j0 = ((i0 >> 20) & 0x7ff) - 0x3ff; + if (j0 < 20) + { + if (j0 < 0) + { /* raise inexact if x != 0 */ + if (1.0e+300 + x > 0.0) + {/* return 0*sign(x) if |x|<1 */ + if (i0 >= 0) + { + i0 = i1 = 0; + } + else if (((i0 & 0x7fffffff) | i1) != 0) + { + i0 = Int32.MaxValue; + i1 = 0; + } + } + } + else + { + i = (uint)0x000fffff >> j0; + if ((((uint)i0 & i) | (uint)i1) == 0) + return x; /* x is integral */ + if (1.0e+300 + x > 0.0) + { /* raise inexact flag */ + if (i0 < 0) + i0 += (0x00100000) >> j0; + i0 &= (int)~i; + i1 = 0; + } + } + } + else if (j0 > 51) + { + if (j0 == 0x400) return x + x; /* inf or NaN */ + else return x; /* x is integral */ + } + else + { + i = ((uint)(0xffffffff)) >> (j0 - 20); + if ((i1 & i) == 0) return x; /* x is integral */ + if (1.0e+300 + x > 0.0) + { /* raise inexact flag */ + if (i0 < 0) + { + if (j0 == 20) i0 += 1; + else + { + j = (uint)i1 + (uint)(1 << (52 - j0)); + if (j < i1) i0 += 1; /* got a carry */ + i1 = (int)j; + } + } + i1 &= (int)~i; + } + } + Byte[] returnBytes = BitConverter.GetBytes(0d); + Byte[] highWord = BitConverter.GetBytes(i0); + Byte[] lowWord = BitConverter.GetBytes(i1); + for (int c = 0; c < 4; c++) + { + returnBytes[c + (BitConverter.IsLittleEndian ? 4 : 0)] = highWord[c]; + } + for (int c = 0; c < 4; c++) + { + returnBytes[c + (BitConverter.IsLittleEndian ? 0 : 4)] = lowWord[c]; + } + return BitConverter.ToDouble(returnBytes, 0); } #endregion Floor