Browse Source

Precision: fix inconsistent behavior

pull/163/merge
Christoph Ruegg 13 years ago
parent
commit
8f38ca706a
  1. 190
      src/Numerics/Precision.cs
  2. 12
      src/UnitTests/AssertHelpers.cs
  3. 213
      src/UnitTests/PrecisionTest.cs

190
src/Numerics/Precision.cs

@ -165,12 +165,12 @@ namespace MathNet.Numerics
/// </summary>
static Precision()
{
_numberOfDecimalPlacesForFloats = (int)Math.Ceiling(Math.Abs(Math.Log10(_singleMachinePrecision)));
_numberOfDecimalPlacesForDoubles = (int)Math.Ceiling(Math.Abs(Math.Log10(_doubleMachinePrecision)));
_numberOfDecimalPlacesForFloats = (int)Math.Floor(Math.Abs(Math.Log10(_singleMachinePrecision)));
_numberOfDecimalPlacesForDoubles = (int)Math.Floor(Math.Abs(Math.Log10(_doubleMachinePrecision)));
}
/// <summary>
/// Gets the number of decimal places for floats.
/// Gets the number of fully significant decimal places for floats.
/// </summary>
/// <value>The number of decimal places for floats.</value>
public static int NumberOfDecimalPlacesForFloats
@ -182,7 +182,7 @@ namespace MathNet.Numerics
}
/// <summary>
/// Gets the number of decimal places for doubles.
/// Gets the number of fully significant decimal places for doubles.
/// </summary>
/// <value>The number of decimal places for doubles.</value>
public static int NumberOfDecimalPlacesForDoubles
@ -211,27 +211,18 @@ namespace MathNet.Numerics
double magnitude = Math.Log10(Math.Abs(value));
#if PORTABLE
// To get the right number we need to know if the value is negative or positive
// truncating a positive number will always give use the correct magnitude
// truncating a negative number will give us a magnitude that is off by 1
if (magnitude < 0)
{
var truncated = (int)Truncate(magnitude);
#else
return (int)Truncate(magnitude - 1);
}
var truncated = (int)Math.Truncate(magnitude);
#endif
return (int)Truncate(magnitude);
#else
// To get the right number we need to know if the value is negative or positive
// truncating a positive number will always give use the correct magnitude
// truncating a negative number will give us a magnitude that is off by 1
if (magnitude < 0)
{
return (int)Math.Truncate(magnitude - 1);
}
return (int)Math.Truncate(magnitude);
#endif
// truncating a negative number will give us a magnitude that is off by 1 (unless integer)
return magnitude < 0d && truncated != magnitude
? truncated - 1
: truncated;
}
@ -252,24 +243,21 @@ namespace MathNet.Numerics
// work for negative numbers (obviously).
var magnitude = Convert.ToSingle(Math.Log10(Math.Abs(value)));
// To get the right number we need to know if the value is negative or positive
// truncating a positive number will always give use the correct magnitude
// truncating a negative number will give us a magnitude that is off by 1
if (magnitude < 0)
{
#if PORTABLE
return (int)Truncate(magnitude - 1);
var truncated = (int)Truncate(magnitude);
#else
return (int)Math.Truncate(magnitude - 1);
#endif
}
#if PORTABLE
return (int)Truncate(magnitude);
#else
return (int)Math.Truncate(magnitude);
var truncated = (int)Math.Truncate(magnitude);
#endif
// To get the right number we need to know if the value is negative or positive
// truncating a positive number will always give use the correct magnitude
// truncating a negative number will give us a magnitude that is off by 1 (unless integer)
return magnitude < 0f && truncated != magnitude
? truncated - 1
: truncated;
}
/// <summary>
/// Returns the number divided by it's magnitude, effectively returning a number between -10 and 10.
/// </summary>
@ -1174,7 +1162,7 @@ namespace MathNet.Numerics
/// </exception>
public static bool AlmostEqualInDecimalPlaces(this double a, double b, int decimalPlaces)
{
if (decimalPlaces <= 0)
if (decimalPlaces < 0)
{
// Can't have a negative number of decimal places
throw new ArgumentOutOfRangeException("decimalPlaces");
@ -1197,7 +1185,7 @@ namespace MathNet.Numerics
if (Math.Abs(a) < _doubleMachinePrecision || Math.Abs(b) < _doubleMachinePrecision)
{
return AlmostEqualWithAbsoluteDecimalPlaces(a, b, decimalPlaces);
return AlmostEqualInAbsoluteDecimalPlaces(a, b, decimalPlaces);
}
// If both numbers are equal, get out now. This should remove the possibility of both numbers being zero
@ -1207,7 +1195,7 @@ namespace MathNet.Numerics
return true;
}
return AlmostEqualWithRelativeDecimalPlaces(a, b, decimalPlaces);
return AlmostEqualInRelativeDecimalPlaces(a, b, decimalPlaces);
}
/// <summary>
@ -1230,7 +1218,7 @@ namespace MathNet.Numerics
/// </exception>
public static bool AlmostEqualInDecimalPlaces(this float a, float b, int decimalPlaces)
{
if (decimalPlaces <= 0)
if (decimalPlaces < 0)
{
// Can't have a negative number of decimal places
throw new ArgumentOutOfRangeException("decimalPlaces");
@ -1253,7 +1241,7 @@ namespace MathNet.Numerics
if (Math.Abs(a) < _singleMachinePrecision || Math.Abs(b) < _singleMachinePrecision)
{
return AlmostEqualWithAbsoluteDecimalPlaces(a, b, decimalPlaces);
return AlmostEqualInAbsoluteDecimalPlaces(a, b, decimalPlaces);
}
// If both numbers are equal, get out now. This should remove the possibility of both numbers being zero
@ -1263,7 +1251,7 @@ namespace MathNet.Numerics
return true;
}
return AlmostEqualWithRelativeDecimalPlaces(a, b, decimalPlaces);
return AlmostEqualInRelativeDecimalPlaces(a, b, decimalPlaces);
}
/// <summary>
@ -1280,28 +1268,44 @@ namespace MathNet.Numerics
/// <param name="b">The second value.</param>
/// <param name="decimalPlaces">The number of decimal places.</param>
/// <returns><see langword="true" /> if both doubles are equal to each other within the specified number of decimal places; otherwise <see langword="false" />.</returns>
public static bool AlmostEqualWithRelativeDecimalPlaces(this double a, double b, int decimalPlaces)
public static bool AlmostEqualInRelativeDecimalPlaces(this double a, double b, int decimalPlaces)
{
if (decimalPlaces < 0)
{
// Can't have a negative number of decimal places
throw new ArgumentOutOfRangeException("decimalPlaces");
}
// If A or B are a NAN, return false. NANs are equal to nothing,
// not even themselves.
if (double.IsNaN(a) || double.IsNaN(b))
{
return false;
}
// If A or B are infinity (positive or negative) then
// only return true if they are exactly equal to each other -
// that is, if they are both infinities of the same sign.
if (double.IsInfinity(a) || double.IsInfinity(b))
{
return a == b;
}
// If the magnitudes of the two numbers are equal to within one magnitude the numbers could potentially be equal
int magnitudeOfFirst = Magnitude(a);
int magnitudeOfSecond = Magnitude(b);
if (Math.Max(magnitudeOfFirst, magnitudeOfSecond) > (Math.Min(magnitudeOfFirst, magnitudeOfSecond) + 1))
int magnitudeOfMax = Math.Max(magnitudeOfFirst, magnitudeOfSecond);
if (magnitudeOfMax > (Math.Min(magnitudeOfFirst, magnitudeOfSecond) + 1))
{
return false;
}
// Get the power of the number of decimalPlaces
double decimalPlaceMagnitude = Math.Pow(10, -(decimalPlaces - 1));
// The values are equal if the difference between the two numbers is smaller than
// 10^(-numberOfDecimalPlaces). We divide by two so that we have half the range
// on each side of the numbers, e.g. if decimalPlaces == 2,
// then 0.01 will equal between 0.005 and 0.015, but not 0.02 and not 0.00
double maxDifference = decimalPlaceMagnitude / 2.0;
return a > b
? (a*Math.Pow(10, -magnitudeOfFirst)) - maxDifference < (b*Math.Pow(10, -magnitudeOfFirst))
: (b*Math.Pow(10, -magnitudeOfSecond)) - maxDifference < (a*Math.Pow(10, -magnitudeOfSecond));
// then 0.01 will equal between 0.00995 and 0.01005, but not 0.0015 and not 0.0095
double decimalPlaceMagnitude = Math.Pow(10, magnitudeOfMax - decimalPlaces)/2d;
return Math.Abs((a - b)) < decimalPlaceMagnitude;
}
/// <summary>
@ -1318,28 +1322,44 @@ namespace MathNet.Numerics
/// <param name="b">The second value.</param>
/// <param name="decimalPlaces">The number of decimal places.</param>
/// <returns><see langword="true" /> if both floats are equal to each other within the specified number of decimal places; otherwise <see langword="false" />.</returns>
public static bool AlmostEqualWithRelativeDecimalPlaces(this float a, float b, int decimalPlaces)
public static bool AlmostEqualInRelativeDecimalPlaces(this float a, float b, int decimalPlaces)
{
if (decimalPlaces < 0)
{
// Can't have a negative number of decimal places
throw new ArgumentOutOfRangeException("decimalPlaces");
}
// If A or B are a NAN, return false. NANs are equal to nothing,
// not even themselves.
if (float.IsNaN(a) || float.IsNaN(b))
{
return false;
}
// If A or B are infinity (positive or negative) then
// only return true if they are exactly equal to each other -
// that is, if they are both infinities of the same sign.
if (float.IsInfinity(a) || float.IsInfinity(b))
{
return a == b;
}
// If the magnitudes of the two numbers are equal to within one magnitude the numbers could potentially be equal
int magnitudeOfFirst = Magnitude(a);
int magnitudeOfSecond = Magnitude(b);
if (Math.Max(magnitudeOfFirst, magnitudeOfSecond) > (Math.Min(magnitudeOfFirst, magnitudeOfSecond) + 1))
int magnitudeOfMax = Math.Max(magnitudeOfFirst, magnitudeOfSecond);
if (magnitudeOfMax > (Math.Min(magnitudeOfFirst, magnitudeOfSecond) + 1))
{
return false;
}
// Get the power of the number of decimalPlaces
var decimalPlaceMagnitude = (float)Math.Pow(10, -(decimalPlaces - 1));
// The values are equal if the difference between the two numbers is smaller than
// 10^(-numberOfDecimalPlaces). We divide by two so that we have half the range
// on each side of the numbers, e.g. if decimalPlaces == 2,
// then 0.01 will equal between 0.005 and 0.015, but not 0.02 and not 0.00
float maxDifference = decimalPlaceMagnitude / 2.0f;
return a > b
? (a*(float) Math.Pow(10, -magnitudeOfFirst)) - maxDifference < (b*(float) Math.Pow(10, -magnitudeOfFirst))
: (b*(float) Math.Pow(10, -magnitudeOfSecond)) - maxDifference < (a*(float) Math.Pow(10, -magnitudeOfSecond));
// then 0.01 will equal between 0.00995 and 0.01005, but not 0.0015 and not 0.0095
var decimalPlaceMagnitude = (float) Math.Pow(10, magnitudeOfMax - decimalPlaces)/2d;
return Math.Abs((a - b)) < decimalPlaceMagnitude;
}
/// <summary>
@ -1348,7 +1368,7 @@ namespace MathNet.Numerics
/// </summary>
/// <remarks>
/// <para>
/// The values are equal if the difference between the two numbers is smaller than 10^(-numberOfDecimalPlaces). We divide by
/// The values are equal if the difference between the two numbers is smaller than 0.5e-decimalPlaces. We divide by
/// two so that we have half the range on each side of the numbers, e.g. if <paramref name="decimalPlaces"/> == 2, then 0.01 will equal between
/// 0.005 and 0.015, but not 0.02 and not 0.00
/// </para>
@ -1357,15 +1377,29 @@ namespace MathNet.Numerics
/// <param name="b">The second value.</param>
/// <param name="decimalPlaces">The number of decimal places.</param>
/// <returns><see langword="true" /> if both doubles are equal to each other within the specified number of decimal places; otherwise <see langword="false" />.</returns>
public static bool AlmostEqualWithAbsoluteDecimalPlaces(this double a, double b, int decimalPlaces)
public static bool AlmostEqualInAbsoluteDecimalPlaces(this double a, double b, int decimalPlaces)
{
double decimalPlaceMagnitude = Math.Pow(10, -(decimalPlaces - 1));
// If A or B are a NAN, return false. NANs are equal to nothing,
// not even themselves.
if (double.IsNaN(a) || double.IsNaN(b))
{
return false;
}
// If A or B are infinity (positive or negative) then
// only return true if they are exactly equal to each other -
// that is, if they are both infinities of the same sign.
if (double.IsInfinity(a) || double.IsInfinity(b))
{
return a == b;
}
// The values are equal if the difference between the two numbers is smaller than
// 10^(-numberOfDecimalPlaces). We divide by two so that we have half the range
// on each side of the numbers, e.g. if decimalPlaces == 2,
// then 0.01 will equal between 0.005 and 0.015, but not 0.02 and not 0.00
return Math.Abs((a - b)) < decimalPlaceMagnitude / 2.0;
double decimalPlaceMagnitude = Math.Pow(10, -decimalPlaces)/2d;
return Math.Abs((a - b)) < decimalPlaceMagnitude;
}
/// <summary>
@ -1383,15 +1417,29 @@ namespace MathNet.Numerics
/// <param name="b">The second value.</param>
/// <param name="decimalPlaces">The number of decimal places.</param>
/// <returns><see langword="true" /> if both floats are equal to each other within the specified number of decimal places; otherwise <see langword="false" />.</returns>
public static bool AlmostEqualWithAbsoluteDecimalPlaces(this float a, float b, int decimalPlaces)
public static bool AlmostEqualInAbsoluteDecimalPlaces(this float a, float b, int decimalPlaces)
{
var decimalPlaceMagnitude = (float)Math.Pow(10, -(decimalPlaces - 1));
// If A or B are a NAN, return false. NANs are equal to nothing,
// not even themselves.
if (float.IsNaN(a) || float.IsNaN(b))
{
return false;
}
// If A or B are infinity (positive or negative) then
// only return true if they are exactly equal to each other -
// that is, if they are both infinities of the same sign.
if (float.IsInfinity(a) || float.IsInfinity(b))
{
return a == b;
}
// The values are equal if the difference between the two numbers is smaller than
// 10^(-numberOfDecimalPlaces). We divide by two so that we have half the range
// on each side of the numbers, e.g. if decimalPlaces == 2,
// then 0.01 will equal between 0.005 and 0.015, but not 0.02 and not 0.00
return Math.Abs((a - b)) < decimalPlaceMagnitude / 2.0f;
var decimalPlaceMagnitude = (float) Math.Pow(10, -decimalPlaces)/2f;
return Math.Abs((a - b)) < decimalPlaceMagnitude;
}
/// <summary>
@ -1849,4 +1897,4 @@ namespace MathNet.Numerics
}
#endif
}
}
}

12
src/UnitTests/AssertHelpers.cs

@ -159,7 +159,7 @@ namespace MathNet.Numerics.UnitTests
return;
}
if (!expected.AlmostEqualWithAbsoluteDecimalPlaces(actual, decimalPlaces))
if (!expected.AlmostEqualInAbsoluteDecimalPlaces(actual, decimalPlaces))
{
Assert.Fail("Not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected, actual);
}
@ -176,7 +176,7 @@ namespace MathNet.Numerics.UnitTests
return;
}
if (!expected.AlmostEqualWithAbsoluteDecimalPlaces(actual, decimalPlaces))
if (!expected.AlmostEqualInAbsoluteDecimalPlaces(actual, decimalPlaces))
{
Assert.Fail("Not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected, actual);
}
@ -187,12 +187,12 @@ namespace MathNet.Numerics.UnitTests
/// </summary>
public static void AlmostEqualAbsolute(Complex expected, Complex actual, int decimalPlaces)
{
if (!expected.Real.AlmostEqualWithAbsoluteDecimalPlaces(actual.Real, decimalPlaces))
if (!expected.Real.AlmostEqualInAbsoluteDecimalPlaces(actual.Real, decimalPlaces))
{
Assert.Fail("Real components are not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.Real, actual.Real);
}
if (!expected.Imaginary.AlmostEqualWithAbsoluteDecimalPlaces(actual.Imaginary, decimalPlaces))
if (!expected.Imaginary.AlmostEqualInAbsoluteDecimalPlaces(actual.Imaginary, decimalPlaces))
{
Assert.Fail("Imaginary components are not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.Imaginary, actual.Imaginary);
}
@ -203,12 +203,12 @@ namespace MathNet.Numerics.UnitTests
/// </summary>
public static void AlmostEqualAbsolute(Complex32 expected, Complex32 actual, int decimalPlaces)
{
if (!expected.Real.AlmostEqualWithAbsoluteDecimalPlaces(actual.Real, decimalPlaces))
if (!expected.Real.AlmostEqualInAbsoluteDecimalPlaces(actual.Real, decimalPlaces))
{
Assert.Fail("Real components are not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.Real, actual.Real);
}
if (!expected.Imaginary.AlmostEqualWithAbsoluteDecimalPlaces(actual.Imaginary, decimalPlaces))
if (!expected.Imaginary.AlmostEqualInAbsoluteDecimalPlaces(actual.Imaginary, decimalPlaces))
{
Assert.Fail("Imaginary components are not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.Imaginary, actual.Imaginary);
}

213
src/UnitTests/PrecisionTest.cs

@ -68,6 +68,13 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(11, 1e11.Magnitude());
Assert.AreEqual(12, 1e12.Magnitude());
Assert.AreEqual(-7, 1e-7.Magnitude());
Assert.AreEqual(-8, 1e-8.Magnitude());
Assert.AreEqual(-9, 1e-9.Magnitude());
Assert.AreEqual(-10, 1e-10.Magnitude());
Assert.AreEqual(-11, 1e-11.Magnitude());
Assert.AreEqual(-12, 1e-12.Magnitude());
Assert.AreEqual(5, 1.1e5.Magnitude());
Assert.AreEqual(-5, 2.2e-5.Magnitude());
Assert.AreEqual(9, 3.3e9.Magnitude());
@ -95,6 +102,13 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(11, (-1e11).Magnitude());
Assert.AreEqual(12, (-1e12).Magnitude());
Assert.AreEqual(-7, (-1e-7).Magnitude());
Assert.AreEqual(-8, (-1e-8).Magnitude());
Assert.AreEqual(-9, (-1e-9).Magnitude());
Assert.AreEqual(-10, (-1e-10).Magnitude());
Assert.AreEqual(-11, (-1e-11).Magnitude());
Assert.AreEqual(-12, (-1e-12).Magnitude());
Assert.AreEqual(5, (-1.1e5).Magnitude());
Assert.AreEqual(-5, (-2.2e-5).Magnitude());
Assert.AreEqual(9, (-3.3e9).Magnitude());
@ -686,50 +700,141 @@ namespace MathNet.Numerics.UnitTests
}
/// <summary>
/// <c>AlmostEqual</c> within decimal places with decimal places less than one throws <c>ArgumentOutOfRangeException</c>.
/// <c>AlmostEqual</c> within absolute decimal places.
/// </summary>
[Test]
public void AlmostEqualWithinDecimalPlacesWithDecimalPlacesLessThanOneThrowsArgumentOutOfRangeException()
public void AlmostEqualInAbsoluteDecimalPlaces()
{
Assert.Throws<ArgumentOutOfRangeException>(() => Precision.AlmostEqualInDecimalPlaces(1, 2, 0));
Assert.IsFalse(1d.AlmostEqualInAbsoluteDecimalPlaces(double.NaN, 2));
Assert.IsFalse(double.NaN.AlmostEqualInAbsoluteDecimalPlaces(2d, 2));
Assert.IsFalse(double.NaN.AlmostEqualInAbsoluteDecimalPlaces(double.NaN, 2));
Assert.IsFalse(double.NegativeInfinity.AlmostEqualInAbsoluteDecimalPlaces(2, 2));
Assert.IsFalse(1d.AlmostEqualInAbsoluteDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsFalse(double.PositiveInfinity.AlmostEqualInAbsoluteDecimalPlaces(2, 2));
Assert.IsFalse(1d.AlmostEqualInAbsoluteDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsFalse(double.NegativeInfinity.AlmostEqualInAbsoluteDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsFalse(double.PositiveInfinity.AlmostEqualInAbsoluteDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsTrue(double.PositiveInfinity.AlmostEqualInAbsoluteDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsTrue(double.NegativeInfinity.AlmostEqualInAbsoluteDecimalPlaces(double.NegativeInfinity, 2));
// 1 -> +/- 0.05 (0.5e-1)
Assert.IsFalse(1d.AlmostEqualInAbsoluteDecimalPlaces(1.06, 1));
Assert.IsTrue(1d.AlmostEqualInAbsoluteDecimalPlaces(1.04, 1));
Assert.IsTrue(1d.AlmostEqualInAbsoluteDecimalPlaces(1.00, 1));
Assert.IsTrue(1d.AlmostEqualInAbsoluteDecimalPlaces(0.96, 1));
Assert.IsFalse(1d.AlmostEqualInAbsoluteDecimalPlaces(0.94, 1));
Assert.IsFalse(1d.AlmostEqualInAbsoluteDecimalPlaces(0.0, 1));
// -1 -> +/- 5 (0.5e+1)
Assert.IsFalse(100d.AlmostEqualInAbsoluteDecimalPlaces(106.0, -1));
Assert.IsTrue(100d.AlmostEqualInAbsoluteDecimalPlaces(104.0, -1));
Assert.IsTrue(100d.AlmostEqualInAbsoluteDecimalPlaces(100.0, -1));
Assert.IsTrue(100d.AlmostEqualInAbsoluteDecimalPlaces(96.0, -1));
Assert.IsFalse(100d.AlmostEqualInAbsoluteDecimalPlaces(94.0, -1));
Assert.IsFalse(100d.AlmostEqualInAbsoluteDecimalPlaces(0.0, -1));
// 3 -> +/- 0.0005 (0.5e-3)
Assert.IsFalse(0.01.AlmostEqualInAbsoluteDecimalPlaces(0.0106, 3));
Assert.IsTrue(0.01.AlmostEqualInAbsoluteDecimalPlaces(0.0104, 3));
Assert.IsTrue(0.01.AlmostEqualInAbsoluteDecimalPlaces(0.0100, 3));
Assert.IsTrue(0.01.AlmostEqualInAbsoluteDecimalPlaces(0.0096, 3));
Assert.IsFalse(0.01.AlmostEqualInAbsoluteDecimalPlaces(0.0094, 3));
Assert.IsFalse(0.01.AlmostEqualInAbsoluteDecimalPlaces(0.0, 3));
// 12 -> +/- 0.5e-12
Assert.IsTrue(0d.AlmostEqualInAbsoluteDecimalPlaces(4 * _doublePrecision, 12));
Assert.IsTrue(0d.AlmostEqualInAbsoluteDecimalPlaces(-4 * _doublePrecision, 12));
}
/// <summary>
/// <c>AlmostEqual</c> within relative decimal places.
/// </summary>
[Test]
public void AlmostEqualInRelativeDecimalPlaces()
{
Assert.IsFalse(1d.AlmostEqualInRelativeDecimalPlaces(double.NaN, 2));
Assert.IsFalse(double.NaN.AlmostEqualInRelativeDecimalPlaces(2d, 2));
Assert.IsFalse(double.NaN.AlmostEqualInRelativeDecimalPlaces(double.NaN, 2));
Assert.IsFalse(double.NegativeInfinity.AlmostEqualInRelativeDecimalPlaces(2, 2));
Assert.IsFalse(1d.AlmostEqualInRelativeDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsFalse(double.PositiveInfinity.AlmostEqualInRelativeDecimalPlaces(2, 2));
Assert.IsFalse(1d.AlmostEqualInRelativeDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsFalse(double.NegativeInfinity.AlmostEqualInRelativeDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsFalse(double.PositiveInfinity.AlmostEqualInRelativeDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsTrue(double.PositiveInfinity.AlmostEqualInRelativeDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsTrue(double.NegativeInfinity.AlmostEqualInRelativeDecimalPlaces(double.NegativeInfinity, 2));
// 1 -> +/- max * 0.05 (0.5e-1)
Assert.IsTrue(1d.AlmostEqualInRelativeDecimalPlaces(1.04, 1));
Assert.IsFalse(1d.AlmostEqualInRelativeDecimalPlaces(1.06, 1));
Assert.IsTrue(1d.AlmostEqualInRelativeDecimalPlaces(0.96, 1));
Assert.IsFalse(1d.AlmostEqualInRelativeDecimalPlaces(0.94, 1));
// 1 -> +/- max * 0.05 (0.5e-1)
Assert.IsTrue(100d.AlmostEqualInRelativeDecimalPlaces(104.00, 1));
Assert.IsFalse(100d.AlmostEqualInRelativeDecimalPlaces(106.00, 1));
Assert.IsTrue(100d.AlmostEqualInRelativeDecimalPlaces(96.000, 1));
Assert.IsFalse(100d.AlmostEqualInRelativeDecimalPlaces(94.000, 1));
// 0 -> +/- max * 0.5 (0.5e-0)
Assert.IsTrue(0.01.AlmostEqualInRelativeDecimalPlaces(0.014, 0));
Assert.IsFalse(0.01.AlmostEqualInRelativeDecimalPlaces(0.016, 0));
Assert.IsTrue(0.01.AlmostEqualInRelativeDecimalPlaces(0.006, 0));
Assert.IsFalse(0.01.AlmostEqualInRelativeDecimalPlaces(0.004, 0));
}
/// <summary>
/// <c>AlmostEqual</c> within decimal places with negative decimal places throws <c>ArgumentOutOfRangeException</c>.
/// </summary>
[Test]
public void AlmostEqualInRelativeDecimalPlacesWithNegativeDecimalPlacesThrowsArgumentOutOfRangeException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => Precision.AlmostEqualInDecimalPlaces(1, 2, -1));
Assert.Throws<ArgumentOutOfRangeException>(() => Precision.AlmostEqualInRelativeDecimalPlaces(1, 2, -1));
Assert.DoesNotThrow(() => Precision.AlmostEqualInAbsoluteDecimalPlaces(1, 2, -1));
}
/// <summary>
/// <c>AlmostEqual</c> within decimal places.
/// </summary>
[Test]
public void AlmostEqualWithinDecimalPlaces()
public void AlmostEqualInDecimalPlaces()
{
Assert.IsFalse(Precision.AlmostEqualInDecimalPlaces(1, double.NaN, 2));
Assert.IsFalse(1d.AlmostEqualInDecimalPlaces(double.NaN, 2));
Assert.IsFalse(double.NaN.AlmostEqualInDecimalPlaces(2, 2));
Assert.IsFalse(double.NaN.AlmostEqualInDecimalPlaces(double.NaN, 2));
Assert.IsFalse(double.NegativeInfinity.AlmostEqualInDecimalPlaces(2, 2));
Assert.IsFalse(Precision.AlmostEqualInDecimalPlaces(1, double.NegativeInfinity, 2));
Assert.IsFalse(1d.AlmostEqualInDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsFalse(double.PositiveInfinity.AlmostEqualInDecimalPlaces(2, 2));
Assert.IsFalse(Precision.AlmostEqualInDecimalPlaces(1, double.PositiveInfinity, 2));
Assert.IsFalse(1d.AlmostEqualInDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsFalse(double.NegativeInfinity.AlmostEqualInDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsFalse(double.PositiveInfinity.AlmostEqualInDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsTrue(double.PositiveInfinity.AlmostEqualInDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsTrue(double.NegativeInfinity.AlmostEqualInDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsTrue(1.0.AlmostEqualInDecimalPlaces(1.04, 2));
Assert.IsTrue(1.0.AlmostEqualInDecimalPlaces(0.96, 2));
Assert.IsFalse(1.0.AlmostEqualInDecimalPlaces(1.06, 2));
Assert.IsFalse(1.0.AlmostEqualInDecimalPlaces(0.94, 2));
Assert.IsTrue(100.0.AlmostEqualInDecimalPlaces(104.00, 2));
Assert.IsTrue(100.0.AlmostEqualInDecimalPlaces(96.000, 2));
Assert.IsFalse(100.0.AlmostEqualInDecimalPlaces(106.00, 2));
Assert.IsFalse(100.0.AlmostEqualInDecimalPlaces(94.000, 2));
Assert.IsTrue(0.0.AlmostEqualInDecimalPlaces(4 * _doublePrecision, 12));
Assert.IsTrue(0.0.AlmostEqualInDecimalPlaces(-4 * _doublePrecision, 12));
// 1 -> +/- max * 0.05 (0.5e-1)
Assert.IsTrue(1d.AlmostEqualInDecimalPlaces(1.04, 1));
Assert.IsFalse(1d.AlmostEqualInDecimalPlaces(1.06, 1));
Assert.IsTrue(1d.AlmostEqualInDecimalPlaces(0.96, 1));
Assert.IsFalse(1d.AlmostEqualInDecimalPlaces(0.94, 1));
// 1 -> +/- max * 0.05 (0.5e-1)
Assert.IsTrue(100d.AlmostEqualInDecimalPlaces(104.00, 1));
Assert.IsFalse(100d.AlmostEqualInDecimalPlaces(106.00, 1));
Assert.IsTrue(100d.AlmostEqualInDecimalPlaces(96.000, 1));
Assert.IsFalse(100d.AlmostEqualInDecimalPlaces(94.000, 1));
// 0 -> +/- max * 0.5 (0.5e-0)
Assert.IsTrue(0.01.AlmostEqualInDecimalPlaces(0.014, 0));
Assert.IsFalse(0.01.AlmostEqualInDecimalPlaces(0.016, 0));
Assert.IsTrue(0.01.AlmostEqualInDecimalPlaces(0.006, 0));
Assert.IsFalse(0.01.AlmostEqualInDecimalPlaces(0.004, 0));
Assert.IsTrue(0d.AlmostEqualInDecimalPlaces(4 * _doublePrecision, 12));
Assert.IsTrue(0d.AlmostEqualInDecimalPlaces(-4 * _doublePrecision, 12));
}
/// <summary>
@ -835,23 +940,21 @@ namespace MathNet.Numerics.UnitTests
Assert.IsFalse(double.PositiveInfinity.IsLargerWithDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsFalse(double.NegativeInfinity.IsLargerWithDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsFalse(1.0.IsLargerWithDecimalPlaces(1.04, 2));
Assert.IsFalse(1.0.IsLargerWithDecimalPlaces(0.96, 2));
Assert.IsFalse(1.0.IsLargerWithDecimalPlaces(1.06, 2));
Assert.IsTrue(1.0.IsLargerWithDecimalPlaces(0.94, 2));
Assert.IsFalse(1.0.IsLargerWithDecimalPlaces(1.006, 2));
Assert.IsFalse(1.0.IsLargerWithDecimalPlaces(1.004, 2));
Assert.IsFalse(1.0.IsLargerWithDecimalPlaces(0.996, 2));
Assert.IsTrue(1.0.IsLargerWithDecimalPlaces(0.994, 2));
Assert.IsFalse(100.0.IsLargerWithDecimalPlaces(104.00, 2));
Assert.IsFalse(100.0.IsLargerWithDecimalPlaces(96.000, 2));
Assert.IsFalse(100.0.IsLargerWithDecimalPlaces(100.6, 2));
Assert.IsFalse(100.0.IsLargerWithDecimalPlaces(100.4, 2));
Assert.IsFalse(100.0.IsLargerWithDecimalPlaces(99.6, 2));
Assert.IsTrue(100.0.IsLargerWithDecimalPlaces(99.4, 2));
Assert.IsFalse(100.0.IsLargerWithDecimalPlaces(106.00, 2));
Assert.IsTrue(100.0.IsLargerWithDecimalPlaces(94.000, 2));
var max = 4 * Math.Pow(10, _doublePrecision.Magnitude());
var max = 0.4 * Math.Pow(10, _doublePrecision.Magnitude());
Assert.IsFalse(0.0.IsLargerWithDecimalPlaces(max, -_doublePrecision.Magnitude()));
Assert.IsFalse(0.0.IsLargerWithDecimalPlaces(-max, -_doublePrecision.Magnitude()));
max = 6 * Math.Pow(10, _doublePrecision.Magnitude());
max = 0.6 * Math.Pow(10, _doublePrecision.Magnitude());
Assert.IsFalse(0.0.IsLargerWithDecimalPlaces(max, -_doublePrecision.Magnitude()));
Assert.IsTrue(0.0.IsLargerWithDecimalPlaces(-max, -_doublePrecision.Magnitude()));
}
@ -934,23 +1037,21 @@ namespace MathNet.Numerics.UnitTests
Assert.IsFalse(double.PositiveInfinity.IsSmallerWithDecimalPlaces(double.PositiveInfinity, 2));
Assert.IsFalse(double.NegativeInfinity.IsSmallerWithDecimalPlaces(double.NegativeInfinity, 2));
Assert.IsFalse(1.0.IsSmallerWithDecimalPlaces(1.04, 2));
Assert.IsFalse(1.0.IsSmallerWithDecimalPlaces(0.96, 2));
Assert.IsTrue(1.0.IsSmallerWithDecimalPlaces(1.06, 2));
Assert.IsFalse(1.0.IsSmallerWithDecimalPlaces(0.94, 2));
Assert.IsFalse(100.0.IsSmallerWithDecimalPlaces(104.00, 2));
Assert.IsFalse(100.0.IsSmallerWithDecimalPlaces(96.000, 2));
Assert.IsTrue(1.0.IsSmallerWithDecimalPlaces(1.006, 2));
Assert.IsFalse(1.0.IsSmallerWithDecimalPlaces(1.004, 2));
Assert.IsFalse(1.0.IsSmallerWithDecimalPlaces(0.996, 2));
Assert.IsFalse(1.0.IsSmallerWithDecimalPlaces(0.994, 2));
Assert.IsTrue(100.0.IsSmallerWithDecimalPlaces(106.00, 2));
Assert.IsFalse(100.0.IsSmallerWithDecimalPlaces(94.000, 2));
Assert.IsTrue(100.0.IsSmallerWithDecimalPlaces(100.6, 2));
Assert.IsFalse(100.0.IsSmallerWithDecimalPlaces(100.4, 2));
Assert.IsFalse(100.0.IsSmallerWithDecimalPlaces(99.6, 2));
Assert.IsFalse(100.0.IsSmallerWithDecimalPlaces(99.4, 2));
var max = 4 * Math.Pow(10, _doublePrecision.Magnitude());
var max = 0.4 * Math.Pow(10, _doublePrecision.Magnitude());
Assert.IsFalse(0.0.IsSmallerWithDecimalPlaces(max, -_doublePrecision.Magnitude()));
Assert.IsFalse(0.0.IsSmallerWithDecimalPlaces(-max, -_doublePrecision.Magnitude()));
max = 6 * Math.Pow(10, _doublePrecision.Magnitude());
max = 0.6 * Math.Pow(10, _doublePrecision.Magnitude());
Assert.IsTrue(0.0.IsSmallerWithDecimalPlaces(max, -_doublePrecision.Magnitude()));
Assert.IsFalse(0.0.IsSmallerWithDecimalPlaces(-max, -_doublePrecision.Magnitude()));
}
@ -1084,22 +1185,22 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(0, Precision.CompareToInDecimalPlaces(0, -0, Precision.NumberOfDecimalPlacesForFloats));
// compare two nearby numbers
Assert.AreEqual(-1, 1.0.CompareToInDecimalPlaces(1.0 + (10 * _doublePrecision), Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(-1, 1.0.CompareToInDecimalPlaces(1.0 + 10*_doublePrecision, Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(0, 1.0.CompareToInDecimalPlaces(1.0 + _doublePrecision, Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(0, 1.0.CompareToInDecimalPlaces(1.0 - _doublePrecision, Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(1, 1.0.CompareToInDecimalPlaces(1.0 - (10 * _doublePrecision), Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(1, 1.0.CompareToInDecimalPlaces(1.0 - 10*_doublePrecision, Precision.NumberOfDecimalPlacesForDoubles));
// compare with the two numbers reversed in compare order
Assert.AreEqual(1, (1.0 + (10 * _doublePrecision)).CompareToInDecimalPlaces(1.0, Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(1, (1.0 + 10*_doublePrecision).CompareToInDecimalPlaces(1.0, Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(0, (1.0 + _doublePrecision).CompareToInDecimalPlaces(1.0, Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(0, (1.0 - _doublePrecision).CompareToInDecimalPlaces(1.0, Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(-1, (1.0 - (10 * _doublePrecision)).CompareToInDecimalPlaces(1.0, Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(-1, (1.0 - 10*_doublePrecision).CompareToInDecimalPlaces(1.0, Precision.NumberOfDecimalPlacesForDoubles));
// compare two slightly more different numbers
Assert.AreEqual(-1, 1.0.CompareToInDecimalPlaces(1.0 + (50 * _doublePrecision), Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(0, 1.0.CompareToInDecimalPlaces(1.0 + (50 * _doublePrecision), Precision.NumberOfDecimalPlacesForDoubles - 2));
Assert.AreEqual(0, 1.0.CompareToInDecimalPlaces(1.0 - (50 * _doublePrecision), Precision.NumberOfDecimalPlacesForDoubles - 2));
Assert.AreEqual(1, 1.0.CompareToInDecimalPlaces(1.0 - (50 * _doublePrecision), Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(-1, 1.0.CompareToInDecimalPlaces(1.0 + (50*_doublePrecision), Precision.NumberOfDecimalPlacesForDoubles));
Assert.AreEqual(0, 1.0.CompareToInDecimalPlaces(1.0 + (50*_doublePrecision), Precision.NumberOfDecimalPlacesForDoubles - 2));
Assert.AreEqual(0, 1.0.CompareToInDecimalPlaces(1.0 - (50*_doublePrecision), Precision.NumberOfDecimalPlacesForDoubles - 2));
Assert.AreEqual(1, 1.0.CompareToInDecimalPlaces(1.0 - (50*_doublePrecision), Precision.NumberOfDecimalPlacesForDoubles));
// compare different numbers
Assert.AreEqual(1, 2.0.CompareToInDecimalPlaces(1.0, Precision.NumberOfDecimalPlacesForDoubles));

Loading…
Cancel
Save