diff --git a/src/Numerics.Tests/PrecisionTest.cs b/src/Numerics.Tests/PrecisionTest.cs index 1b869947..e5f18611 100644 --- a/src/Numerics.Tests/PrecisionTest.cs +++ b/src/Numerics.Tests/PrecisionTest.cs @@ -28,6 +28,7 @@ // using System; +using System.Numerics; using NUnit.Framework; namespace MathNet.Numerics.UnitTests @@ -1156,5 +1157,100 @@ namespace MathNet.Numerics.UnitTests Assert.AreEqual(-1, double.NegativeInfinity.CompareTo(1.0, Precision.DoubleDecimalPlaces)); Assert.AreEqual(1, 1.0.CompareTo(double.NegativeInfinity, Precision.DoubleDecimalPlaces)); } + + [Test] + [TestCase(100.3123, 3, 0)] + [TestCase(1100.6123, 3, 1000)] + [TestCase(1500.8123, 3, 2000)] + [TestCase(110003245.3123, 3, 110003000)] + [TestCase(110003245.3123, 1, 110003250)] + [TestCase(110003245.3123, -2, 110003245.31)] + [TestCase(110003245.3123, 0, 110003245)] + public void RoundAboveDecimal(decimal number, int digit, decimal expectedResult) + { + Assert.AreEqual(expectedResult, number.RoundAboveZero(digit)); + } + + [Test] + [TestCase(100.3123, 3, 0)] + [TestCase(1100.6123, 3, 1000)] + [TestCase(1500.8123, 3, 2000)] + [TestCase(110003245.3123, 3, 110003000)] + [TestCase(110003245.3123, 1, 110003250)] + [TestCase(110003245.3123, -2, 110003245.31)] + [TestCase(110003245.3123, 0, 110003245)] + public void RoundAboveDouble(double number, int digit, double expectedResult) + { + Assert.AreEqual(expectedResult,number.RoundAboveZero(digit)); + } + + [Test] + [TestCase(100.3123f, 3, 0f)] + [TestCase(1100.6123f, 3, 1000f)] + [TestCase(1500.8123f, 3, 2000f)] + [TestCase(11245.3123f, 3, 11000f)] + [TestCase(13245.3123f, 1, 13250f)] + [TestCase(13245.3123f, -2, 13245.31f)] + [TestCase(13245.3123f, 0, 13245f)] + public void RoundAboveFloat(float number, int digit, float expectedResult) + { + Assert.AreEqual(expectedResult,number.RoundAboveZero(digit)); + } + + [Test] + [TestCase(100, 3, 0)] + [TestCase(1100, 3, 1000)] + [TestCase(1500, 3, 2000)] + [TestCase(110003245, 3, 110003000)] + [TestCase(110003245, 1, 110003250)] + [TestCase(110003245, -2, 110003245)] + public void RoundAboveInt(int number, int digit, int expectedResult) + { + Assert.AreEqual(expectedResult,number.RoundAboveZero(digit)); + } + + [Test] + public void RoundAboveUint() + { + Assert.AreEqual(110003250,((uint)110003245).RoundAboveZero(1)); + } + + + [Test] + public void RoundAboveUlong() + { + Assert.AreEqual(3250, ((ulong)3245).RoundAboveZero(1)); + } + + [Test] + [TestCase(110003245, 1, 110003250)] + public void RoundAboveLong(long number, int digit, int expectedResult) + { + Assert.AreEqual(expectedResult, number.RoundAboveZero(digit)); + } + + [Test] + public void RoundAboveShort() + { + Assert.AreEqual(3250, ((short)3245).RoundAboveZero(1)); + } + + [Test] + public void RoundAboveUshort() + { + Assert.AreEqual(3250,((ushort)3245).RoundAboveZero(1)); + } + + [Test] + public void RoundAboveBigInteger() + { + Assert.AreEqual(BigInteger.Zero,new BigInteger(100).RoundAboveZero(3)); + Assert.AreEqual(new BigInteger(1000),new BigInteger(1100).RoundAboveZero(3)); + Assert.AreEqual(new BigInteger(2000),new BigInteger(1500).RoundAboveZero(3)); + Assert.AreEqual(new BigInteger(110003000), new BigInteger(110003245).RoundAboveZero(3)); + Assert.AreEqual(new BigInteger(110003250), new BigInteger(110003245).RoundAboveZero(1)); + Assert.AreEqual(new BigInteger(110003245), new BigInteger(110003245).RoundAboveZero(-2)); + Assert.AreEqual(new BigInteger(110003245), new BigInteger(110003245).RoundAboveZero(0)); + } } } diff --git a/src/Numerics/Precision.cs b/src/Numerics/Precision.cs index 544295a6..60106c31 100644 --- a/src/Numerics/Precision.cs +++ b/src/Numerics/Precision.cs @@ -28,6 +28,7 @@ // using System; +using System.Numerics; using System.Runtime; using System.Runtime.InteropServices; @@ -744,6 +745,151 @@ namespace MathNet.Numerics return eps; } + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static decimal RoundAboveZero(this decimal number, int powerDigits = 3) + { + if (powerDigits <= 0) + return Math.Round(number, powerDigits*-1,MidpointRounding.AwayFromZero); + return Math.Round(number / (decimal) Math.Pow(10, powerDigits),MidpointRounding.AwayFromZero) * (decimal) Math.Pow(10, powerDigits); + } + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static double RoundAboveZero(this double number, int powerDigits = 3) + { + if (powerDigits <= 0) + return Math.Round(number, powerDigits*-1,MidpointRounding.AwayFromZero); + return Math.Round(number / Math.Pow(10, powerDigits),MidpointRounding.AwayFromZero) * Math.Pow(10, powerDigits); + } + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static int RoundAboveZero(this int number, int powerDigits = 3) + { + if (powerDigits <= 0) + return number; + return (int) RoundAboveZero((decimal) number, powerDigits); + } + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static uint RoundAboveZero(this uint number, int powerDigits = 3) + { + if (powerDigits <= 0) + return number; + return (uint) RoundAboveZero((decimal) number, powerDigits); + } + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static ulong RoundAboveZero(this ulong number, int powerDigits = 3) + { + if (powerDigits <= 0) + return number; + return (ulong) RoundAboveZero((decimal) number, powerDigits); + } + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static long RoundAboveZero(this long number, int powerDigits = 3) + { + if (powerDigits <= 0) + return number; + return (long) RoundAboveZero((decimal) number, powerDigits); + } + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static short RoundAboveZero(this short number, int powerDigits = 3) + { + if (powerDigits <= 0) + return number; + return (short) RoundAboveZero((decimal) number, powerDigits); + } + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static ushort RoundAboveZero(this ushort number, int powerDigits = 3) + { + if (powerDigits <= 0) + return number; + return (ushort) RoundAboveZero((decimal) number, powerDigits); + } + + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static float RoundAboveZero(this float number, int powerDigits = 3) + { + return (float) RoundAboveZero((decimal) number, powerDigits); + } + + /// + /// Round to the number closest to 10^powerDigits. + /// + /// Number to be rounded + /// For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits. + /// To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 + /// Rounded number + public static BigInteger RoundAboveZero(this BigInteger number, int powerDigits = 3) + { + if (powerDigits <= 0) + return number; + + var onelarger = number / BigInteger.Pow(10, powerDigits-1); + var divided = onelarger / 10; + var lastDigit = onelarger - divided * 10; + if (lastDigit >= 5) + divided += 1; + return divided * BigInteger.Pow(10, powerDigits); + } + /// /// Calculates the actual positive double precision machine epsilon - the smallest number that can be added to 1, yielding a results different than 1. /// This is also known as unit roundoff error. According to the definition of Prof. Higham.