diff --git a/src/Numerics.Tests/PrecisionTest.cs b/src/Numerics.Tests/PrecisionTest.cs
index e151a4c7..d6b8905d 100644
--- a/src/Numerics.Tests/PrecisionTest.cs
+++ b/src/Numerics.Tests/PrecisionTest.cs
@@ -1172,13 +1172,13 @@ namespace MathNet.Numerics.UnitTests
}
[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)]
+ [TestCase(100.3123d, -3, 0d)]
+ [TestCase(1100.6123d, -3, 1000d)]
+ [TestCase(1500.8123d, -3, 2000d)]
+ [TestCase(110003245.3123d, -3, 110003000d)]
+ [TestCase(110003245.3123d, -1, 110003250d)]
+ [TestCase(110003245.3123d, 2, 110003245.31d)]
+ [TestCase(110003245.3123d, 0, 110003245d)]
public void RoundDouble(double number, int digit, double expectedResult)
{
Assert.AreEqual(expectedResult,number.Round(digit));
@@ -1212,19 +1212,18 @@ namespace MathNet.Numerics.UnitTests
[Test]
public void RoundUint32()
{
- Assert.AreEqual(110003250,((uint)110003245).Round(-1));
+ Assert.AreEqual(110003250U,110003245U.Round(-1));
}
-
[Test]
public void RoundUInt64()
{
- Assert.AreEqual(3250, ((ulong)3245).Round(-1));
+ Assert.AreEqual(3250UL, 3245UL.Round(-1));
}
[Test]
- [TestCase(110003245, -1, 110003250)]
- public void RoundInt64(long number, int digit, int expectedResult)
+ [TestCase(110003245L, -1, 110003250L)]
+ public void RoundInt64(long number, int digit, long expectedResult)
{
Assert.AreEqual(expectedResult, number.Round(digit));
}
@@ -1252,5 +1251,34 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(new BigInteger(110003245), new BigInteger(110003245).Round(2));
Assert.AreEqual(new BigInteger(110003245), new BigInteger(110003245).Round(0));
}
+
+ [Test]
+ [TestCase(0.0, 2.0, 0.0)]
+ [TestCase(0.1, 2.0, 0.125)]
+ [TestCase(0.7, 2.0, 0.5)]
+ [TestCase(0.8, 2.0, 1.0)]
+ [TestCase(1.1, 2.0, 1.0)]
+ [TestCase(1.6, 2.0, 2.0)]
+ [TestCase(3.2, 2.0, 4.0)]
+ [TestCase(14.0, 2.0, 16.0)]
+ [TestCase(-14.0, 2.0, -16.0)]
+ public void RoundToPowerDouble(double number, double basis, double expectedResult)
+ {
+ Assert.AreEqual(expectedResult, number.RoundToPower(basis), 0.0);
+ }
+
+ [Test]
+ [TestCase(0.0, 0.3, 0.0)]
+ [TestCase(0.1, 0.3, 0.0)]
+ [TestCase(0.2, 0.3, 0.3)]
+ [TestCase(0.8, 0.3, 0.9)]
+ [TestCase(1.1, 0.3, 1.2)]
+ [TestCase(1.6, 0.3, 1.5)]
+ [TestCase(3.2, 0.3, 3.3)]
+ [TestCase(-3.2, 0.3, -3.3)]
+ public void RoundToMultipleDouble(double number, double basis, double expectedResult)
+ {
+ Assert.AreEqual(expectedResult, number.RoundToMultiple(basis), Precision.DoublePrecision);
+ }
}
}
diff --git a/src/Numerics/Precision.cs b/src/Numerics/Precision.cs
index 122f817f..1c0dc7bb 100644
--- a/src/Numerics/Precision.cs
+++ b/src/Numerics/Precision.cs
@@ -746,7 +746,74 @@ namespace MathNet.Numerics
}
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// 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.
+ ///
+ /// Machine epsilon
+ static double MeasurePositiveMachineEpsilon()
+ {
+ double eps = 1.0d;
+
+ while ((1.0d + (eps / 2.0d)) > 1.0d)
+ eps /= 2.0d;
+
+ return eps;
+ }
+
+ ///
+ /// Round to a multiple of the provided positive basis.
+ ///
+ /// Number to be rounded.
+ /// The basis to whose multiples to round to. Must be positive.
+ public static double RoundToMultiple(this double number, double basis)
+ {
+ return Math.Round(number / basis, MidpointRounding.AwayFromZero) * basis;
+ }
+
+ ///
+ /// Round to a multiple of the provided positive basis.
+ ///
+ /// Number to be rounded.
+ /// The basis to whose multiples to round to. Must be positive.
+ public static float RoundToMultiple(this float number, float basis)
+ {
+ return (float) RoundToMultiple((double) number, basis);
+ }
+
+ ///
+ /// Round to a multiple of the provided positive basis.
+ ///
+ /// Number to be rounded.
+ /// The basis to whose multiples to round to. Must be positive.
+ public static decimal RoundToMultiple(this decimal number, decimal basis)
+ {
+ return Math.Round(number / basis, MidpointRounding.AwayFromZero) * basis;
+ }
+
+ ///
+ /// Round to a multiple of the provided positive basis.
+ ///
+ /// Number to be rounded.
+ /// The basis to whose powers to round to. Must be positive.
+ public static double RoundToPower(this double number, double basis)
+ {
+ return number < 0.0
+ ? -Math.Pow(basis, Math.Round(Math.Log(-number, basis), MidpointRounding.AwayFromZero))
+ : Math.Pow(basis, Math.Round(Math.Log(number, basis), MidpointRounding.AwayFromZero));
+ }
+
+ ///
+ /// Round to a multiple of the provided positive basis.
+ ///
+ /// Number to be rounded.
+ /// The basis to whose powers to round to. Must be positive.
+ public static float RoundToPower(this float number, float basis)
+ {
+ return (float) RoundToPower((double) number, basis);
+ }
+
+ ///
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
@@ -754,16 +821,13 @@ namespace MathNet.Numerics
/// Rounded number
public static double Round(this double number, int decimals)
{
- if (decimals >= 0)
- {
- return Math.Round(number, decimals, MidpointRounding.AwayFromZero);
- }
-
- return Math.Round(number / Math.Pow(10, -decimals), MidpointRounding.AwayFromZero) * Math.Pow(10, -decimals);
+ return decimals >= 0
+ ? Math.Round(number, decimals, MidpointRounding.AwayFromZero)
+ : RoundToMultiple(number, Math.Pow(10.0, -decimals));
}
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
@@ -771,46 +835,39 @@ namespace MathNet.Numerics
/// Rounded number
public static float Round(this float number, int decimals)
{
- return (float) Round((decimal) number, decimals);
+ return (float) Round((double) number, decimals);
}
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
/// To round 123456789 to hundreds Round(123456789, -2) = 123456800
/// Rounded number
public static decimal Round(this decimal number, int decimals)
- {
- if (decimals >= 0)
- {
- return Math.Round(number, decimals, MidpointRounding.AwayFromZero);
- }
-
- decimal roundTo = (decimal) Math.Pow(10, -decimals);
- return Math.Round(number / roundTo, MidpointRounding.AwayFromZero) * roundTo;
+ {
+ return decimals >= 0
+ ? Math.Round(number, decimals, MidpointRounding.AwayFromZero)
+ : RoundToMultiple(number, (decimal) Math.Pow(10.0, -decimals));
}
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
/// To round 123456789 to hundreds Round(123456789, -2) = 123456800
/// Rounded number
public static int Round(this int number, int decimals)
- {
- if (decimals >= 0)
- {
- return number;
- }
-
- return (int) Round((decimal) number, decimals);
- }
+ {
+ return decimals >= 0
+ ? number
+ : (int) Round((decimal) number, decimals);
+ }
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
@@ -819,16 +876,13 @@ namespace MathNet.Numerics
[CLSCompliant(false)]
public static uint Round(this uint number, int decimals)
{
- if (decimals >= 0)
- {
- return number;
- }
-
- return (uint) Round((decimal) number, decimals);
+ return decimals >= 0
+ ? number
+ : (uint) Round((decimal) number, decimals);
}
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
@@ -836,16 +890,13 @@ namespace MathNet.Numerics
/// Rounded number
public static long Round(this long number, int decimals)
{
- if (decimals >= 0)
- {
- return number;
- }
-
- return (long) Round((decimal) number, decimals);
+ return decimals >= 0
+ ? number
+ : (long) Round((decimal) number, decimals);
}
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
@@ -854,15 +905,13 @@ namespace MathNet.Numerics
[CLSCompliant(false)]
public static ulong Round(this ulong number, int decimals)
{
- if (decimals >= 0)
- {
- return number;
- }
-
- return (ulong) Round((decimal) number, decimals);
+ return decimals >= 0
+ ? number
+ : (ulong) Round((decimal) number, decimals);
}
+
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
@@ -870,16 +919,13 @@ namespace MathNet.Numerics
/// Rounded number
public static short Round(this short number, int decimals)
{
- if (decimals >= 0)
- {
- return number;
- }
-
- return (short) Round((decimal) number, decimals);
+ return decimals >= 0
+ ? number
+ : (short) Round((decimal) number, decimals);
}
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
@@ -888,16 +934,13 @@ namespace MathNet.Numerics
[CLSCompliant(false)]
public static ushort Round(this ushort number, int decimals)
{
- if (decimals >= 0)
- {
- return number;
- }
-
- return (ushort) Round((decimal) number, decimals);
+ return decimals >= 0
+ ? number
+ : (ushort) Round((decimal) number, decimals);
}
///
- /// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
+ /// Round to the number closest to 10^(-decimals). Negative decimals to round within the integer part.
///
/// Number to be rounded
/// Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.
@@ -921,21 +964,6 @@ namespace MathNet.Numerics
return divided * BigInteger.Pow(10, -decimals);
}
- ///
- /// 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.
- ///
- /// Machine epsilon
- static double MeasurePositiveMachineEpsilon()
- {
- double eps = 1.0d;
-
- while ((1.0d + (eps / 2.0d)) > 1.0d)
- eps /= 2.0d;
-
- return eps;
- }
-
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
static double Truncate(double value)
{