Browse Source

Precision: make RoundAboveZero more consistent with BCL Round (to avoid confusion)

v4
Christoph Ruegg 6 years ago
parent
commit
644cc1635a
  1. 104
      src/Numerics.Tests/PrecisionTest.cs
  2. 125
      src/Numerics/Precision.cs

104
src/Numerics.Tests/PrecisionTest.cs

@ -1159,98 +1159,98 @@ 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(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)
public void RoundDecimal(decimal number, int digit, decimal expectedResult)
{
Assert.AreEqual(expectedResult, number.RoundAboveZero(digit));
Assert.AreEqual(expectedResult, number.Round(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(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)
public void RoundDouble(double number, int digit, double expectedResult)
{
Assert.AreEqual(expectedResult,number.RoundAboveZero(digit));
Assert.AreEqual(expectedResult,number.Round(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(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)
public void RoundSingle(float number, int digit, float expectedResult)
{
Assert.AreEqual(expectedResult,number.RoundAboveZero(digit));
Assert.AreEqual(expectedResult,number.Round(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)
[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 RoundInt32(int number, int digit, int expectedResult)
{
Assert.AreEqual(expectedResult,number.RoundAboveZero(digit));
Assert.AreEqual(expectedResult,number.Round(digit));
}
[Test]
public void RoundAboveUint()
public void RoundUint32()
{
Assert.AreEqual(110003250,((uint)110003245).RoundAboveZero(1));
Assert.AreEqual(110003250,((uint)110003245).Round(-1));
}
[Test]
public void RoundAboveUlong()
public void RoundUInt64()
{
Assert.AreEqual(3250, ((ulong)3245).RoundAboveZero(1));
Assert.AreEqual(3250, ((ulong)3245).Round(-1));
}
[Test]
[TestCase(110003245, 1, 110003250)]
public void RoundAboveLong(long number, int digit, int expectedResult)
[TestCase(110003245, -1, 110003250)]
public void RoundInt64(long number, int digit, int expectedResult)
{
Assert.AreEqual(expectedResult, number.RoundAboveZero(digit));
Assert.AreEqual(expectedResult, number.Round(digit));
}
[Test]
public void RoundAboveShort()
public void RoundInt16()
{
Assert.AreEqual(3250, ((short)3245).RoundAboveZero(1));
Assert.AreEqual(3250, ((short)3245).Round(-1));
}
[Test]
public void RoundAboveUshort()
public void RoundUInt16()
{
Assert.AreEqual(3250,((ushort)3245).RoundAboveZero(1));
Assert.AreEqual(3250,((ushort)3245).Round(-1));
}
[Test]
public void RoundAboveBigInteger()
public void RoundBigInteger()
{
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));
Assert.AreEqual(BigInteger.Zero,new BigInteger(100).Round(-3));
Assert.AreEqual(new BigInteger(1000),new BigInteger(1100).Round(-3));
Assert.AreEqual(new BigInteger(2000),new BigInteger(1500).Round(-3));
Assert.AreEqual(new BigInteger(110003000), new BigInteger(110003245).Round(-3));
Assert.AreEqual(new BigInteger(110003250), new BigInteger(110003245).Round(-1));
Assert.AreEqual(new BigInteger(110003245), new BigInteger(110003245).Round(2));
Assert.AreEqual(new BigInteger(110003245), new BigInteger(110003245).Round(0));
}
}
}

125
src/Numerics/Precision.cs

@ -746,170 +746,171 @@ namespace MathNet.Numerics
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
public static double RoundAboveZero(this double number, int powerDigits)
public static double Round(this double number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return Math.Round(number, -powerDigits, MidpointRounding.AwayFromZero);
return Math.Round(number, decimals, MidpointRounding.AwayFromZero);
}
return Math.Round(number / Math.Pow(10, powerDigits), MidpointRounding.AwayFromZero) * Math.Pow(10, powerDigits);
return Math.Round(number / Math.Pow(10, -decimals), MidpointRounding.AwayFromZero) * Math.Pow(10, -decimals);
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
public static float RoundAboveZero(this float number, int powerDigits)
public static float Round(this float number, int decimals)
{
return (float) RoundAboveZero((decimal) number, powerDigits);
return (float) Round((decimal) number, decimals);
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
public static decimal RoundAboveZero(this decimal number, int powerDigits)
public static decimal Round(this decimal number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return Math.Round(number, -powerDigits, MidpointRounding.AwayFromZero);
return Math.Round(number, decimals, MidpointRounding.AwayFromZero);
}
return Math.Round(number / (decimal) Math.Pow(10, powerDigits), MidpointRounding.AwayFromZero) * (decimal) Math.Pow(10, powerDigits);
decimal roundTo = (decimal) Math.Pow(10, -decimals);
return Math.Round(number / roundTo, MidpointRounding.AwayFromZero) * roundTo;
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
public static int RoundAboveZero(this int number, int powerDigits)
public static int Round(this int number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return number;
}
return (int) RoundAboveZero((decimal) number, powerDigits);
return (int) Round((decimal) number, decimals);
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
[CLSCompliant(false)]
public static uint RoundAboveZero(this uint number, int powerDigits)
public static uint Round(this uint number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return number;
}
return (uint) RoundAboveZero((decimal) number, powerDigits);
return (uint) Round((decimal) number, decimals);
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
public static long RoundAboveZero(this long number, int powerDigits)
public static long Round(this long number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return number;
}
return (long) RoundAboveZero((decimal) number, powerDigits);
return (long) Round((decimal) number, decimals);
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
[CLSCompliant(false)]
public static ulong RoundAboveZero(this ulong number, int powerDigits)
public static ulong Round(this ulong number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return number;
}
return (ulong) RoundAboveZero((decimal) number, powerDigits);
return (ulong) Round((decimal) number, decimals);
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
public static short RoundAboveZero(this short number, int powerDigits)
public static short Round(this short number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return number;
}
return (short) RoundAboveZero((decimal) number, powerDigits);
return (short) Round((decimal) number, decimals);
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
[CLSCompliant(false)]
public static ushort RoundAboveZero(this ushort number, int powerDigits)
public static ushort Round(this ushort number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return number;
}
return (ushort) RoundAboveZero((decimal) number, powerDigits);
return (ushort) Round((decimal) number, decimals);
}
/// <summary>
/// Round to the number closest to 10^powerDigits.
/// Round to the number closest to 10^(-decimals). Supports negative decimals to round within the integer part.
/// </summary>
/// <param name="number">Number to be rounded</param>
/// <param name="powerDigits">For closest 1000 enter 3, 10^powerDigits. If lower then zero you will get decimal digits.</param>
/// <example>To round 123456789 to hundreds RoundAboveZero(123456789, 2) = 123456800 </example>
/// <param name="decimals">Number of decimals to round to. Negative to round within the integer part, e.g. -3 will wound to the closes 1000.</param>
/// <example>To round 123456789 to hundreds Round(123456789, -2) = 123456800 </example>
/// <returns>Rounded number</returns>
public static BigInteger RoundAboveZero(this BigInteger number, int powerDigits)
public static BigInteger Round(this BigInteger number, int decimals)
{
if (powerDigits <= 0)
if (decimals >= 0)
{
return number;
}
var onelarger = number / BigInteger.Pow(10, powerDigits-1);
var onelarger = number / BigInteger.Pow(10, (-decimals)-1);
var divided = onelarger / 10;
var lastDigit = onelarger - divided * 10;
if (lastDigit >= 5)
@ -917,7 +918,7 @@ namespace MathNet.Numerics
divided += 1;
}
return divided * BigInteger.Pow(10, powerDigits);
return divided * BigInteger.Pow(10, -decimals);
}
/// <summary>

Loading…
Cancel
Save