From 87de6dda4dc0ea766a0b514e13c2985497fb1df8 Mon Sep 17 00:00:00 2001 From: Jarl Gullberg Date: Wed, 7 Jun 2017 14:27:36 +0200 Subject: [PATCH] Merged new equivalence function. --- src/OpenTK/Math/MathHelper.cs | 44 +++++++++++++++++++++++++++++++++ tests/OpenTK.Tests/Assertions.fs | 7 +++++- tests/OpenTK.Tests/MathHelperTests.fs | 46 ++++++++++++++++++++++++++++++++++- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/OpenTK/Math/MathHelper.cs b/src/OpenTK/Math/MathHelper.cs index c13cd89..0dc553f 100644 --- a/src/OpenTK/Math/MathHelper.cs +++ b/src/OpenTK/Math/MathHelper.cs @@ -422,6 +422,50 @@ namespace OpenTK return relativeError < epsilon; } + /// + /// Approximates equivalence between two single-precision floating-point numbers on a direct human scale. + /// It is important to note that this does not approximate equality - instead, it merely checks whether or not + /// two numbers could be considered equivalent to each other within a certain tolerance. + /// + /// The first value to compare. + /// The second value to compare· + /// The tolerance within which the two values would be considered equivalent. + /// Whether or not the values can be considered equivalent within the tolerance. + [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")] + public static bool ApproximatelyEquivalent(float a, float b, float tolerance) + { + if (a == b) + { + // Early bailout, handles infinities + return true; + } + + float diff = Math.Abs(a - b); + return diff < tolerance; + } + + /// + /// Approximates equivalence between two double-precision floating-point numbers on a direct human scale. + /// It is important to note that this does not approximate equality - instead, it merely checks whether or not + /// two numbers could be considered equivalent to each other within a certain tolerance. + /// + /// The first value to compare. + /// The second value to compare· + /// The tolerance within which the two values would be considered equivalent. + /// Whether or not the values can be considered equivalent within the tolerance. + [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")] + public static bool ApproximatelyEquivalent(double a, double b, double tolerance) + { + if (a == b) + { + // Early bailout, handles infinities + return true; + } + + double diff = Math.Abs(a - b); + return diff < tolerance; + } + #endregion #endregion diff --git a/tests/OpenTK.Tests/Assertions.fs b/tests/OpenTK.Tests/Assertions.fs index 72673de..b54ef7a 100644 --- a/tests/OpenTK.Tests/Assertions.fs +++ b/tests/OpenTK.Tests/Assertions.fs @@ -11,8 +11,13 @@ module private AssertHelpers = [] let private BitAccuracy = 16 + [] + let private EquivalenceTolerance = 0.0001f + + let approxEq a b = MathHelper.ApproximatelyEquivalent(a, b, EquivalenceTolerance) //let approxEq a b = MathHelper.ApproximatelyEqual(a,b,BitAccuracy) - let approxEq a b = MathHelper.ApproximatelyEqualEpsilon(a,b,0.0001f) + //let approxEq a b = MathHelper.ApproximatelyEqualEpsilon(a,b,0.0001f) + let approxEqSingleEpsilon a b = MathHelper.ApproximatelyEqualEpsilon(a, b, 0.00001f) let approxEqDoubleEpsilon a b = MathHelper.ApproximatelyEqualEpsilon(a, b, 0.00001) diff --git a/tests/OpenTK.Tests/MathHelperTests.fs b/tests/OpenTK.Tests/MathHelperTests.fs index 554341a..fdd21f9 100644 --- a/tests/OpenTK.Tests/MathHelperTests.fs +++ b/tests/OpenTK.Tests/MathHelperTests.fs @@ -305,4 +305,48 @@ module MathHelper = Assert.NotApproximatelyEqualEpsilon(0.000000001, -System.Double.Epsilon); Assert.NotApproximatelyEqualEpsilon(0.000000001, System.Double.Epsilon); Assert.NotApproximatelyEqualEpsilon(System.Double.Epsilon, 0.000000001); - Assert.NotApproximatelyEqualEpsilon(-System.Double.Epsilon, 0.000000001); \ No newline at end of file + Assert.NotApproximatelyEqualEpsilon(-System.Double.Epsilon, 0.000000001); + + [ |], MaxTest = 10000)>] + module ``ApproximatelyEquivalent (tolerance diff)`` = + [] + let ``ApproximatelyEquivalent correctly approximates equivalence where the difference falls below the tolerance``() = + let a = 0.0001f + let b = 0.00019f + Assert.NotEqual(a,b) + Assert.True(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) + + [] + let ``ApproximatelyEquivalent correctly approximates inequivalence where the difference is the tolerance``() = + let a = 0.0001f + let b = 0.0002f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) + + [] + let ``ApproximatelyEquivalent correctly approximates inequivalence where the difference exceeds the tolerance``() = + let a = 0.0001f + let b = 0.00021f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) + + [] + let ``ApproximatelyEquivalent reports very different values as non-equal even with a high tolerance``() = + let a = 2.0f + let b = 1.0f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEquivalent(a, b, 1.0f)) + + [] + let ``ApproximatelyEquivalent works with single zero value``() = + let a = 1.0f + let b = 0.0f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) + + [] + let ``ApproximatelyEquivalent works with both zero values``() = + let a = 0.0f + let b = 0.0f + Assert.Equal(a,b) + Assert.True(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) \ No newline at end of file -- 2.7.4