diff --git a/Nuclex.Support (net-4.0).csproj b/Nuclex.Support (net-4.0).csproj
index e01352e..65e37d4 100644
--- a/Nuclex.Support (net-4.0).csproj
+++ b/Nuclex.Support (net-4.0).csproj
@@ -188,7 +188,7 @@
- TransformingReadOnlyCollection.cs
+ Variegator.cs
diff --git a/Nuclex.Support (xna-4.0-phone7).csproj b/Nuclex.Support (xna-4.0-phone7).csproj
index 65fc357..1cc52ce 100644
--- a/Nuclex.Support (xna-4.0-phone7).csproj
+++ b/Nuclex.Support (xna-4.0-phone7).csproj
@@ -217,6 +217,10 @@
TransformingReadOnlyCollection.cs
+
+
+ Variegator.cs
+
WeakCollection.cs
diff --git a/Nuclex.Support (xna-4.0-xbox360).csproj b/Nuclex.Support (xna-4.0-xbox360).csproj
index e2fcedb..7c6607f 100644
--- a/Nuclex.Support (xna-4.0-xbox360).csproj
+++ b/Nuclex.Support (xna-4.0-xbox360).csproj
@@ -228,6 +228,10 @@
TransformingReadOnlyCollection.cs
+
+
+ Variegator.cs
+
WeakCollection.cs
diff --git a/Source/Collections/Variegator.Test.cs b/Source/Collections/Variegator.Test.cs
index 7f0086e..a28b3e7 100644
--- a/Source/Collections/Variegator.Test.cs
+++ b/Source/Collections/Variegator.Test.cs
@@ -29,7 +29,7 @@ namespace Nuclex.Support.Collections {
/// Unit Test for the Variegator multi dictionary
[TestFixture]
- public class VariegatorTest {
+ internal class VariegatorTest {
///
/// Tests whether the default constructor of the reverse comparer works
diff --git a/Source/Collections/Variegator.cs b/Source/Collections/Variegator.cs
index 4e03563..d2397c7 100644
--- a/Source/Collections/Variegator.cs
+++ b/Source/Collections/Variegator.cs
@@ -20,7 +20,6 @@ License along with this library
using System;
using System.Collections.Generic;
-using System.Text;
namespace Nuclex.Support.Collections {
diff --git a/Source/FloatHelper.Test.cs b/Source/FloatHelper.Test.cs
index 82d0bb4..accf4d4 100644
--- a/Source/FloatHelper.Test.cs
+++ b/Source/FloatHelper.Test.cs
@@ -29,11 +29,11 @@ namespace Nuclex.Support {
/// Unit Test for the FloatHelper class
[TestFixture]
- internal class FloatHelperTest {
+ public class FloatHelperTest {
/// Tests the floating point value comparison helper
[Test]
- public void TestFloatComparison() {
+ public void UlpDistancesOnFloatsCompareAsEqual() {
Assert.IsTrue(
FloatHelper.AreAlmostEqual(0.00000001f, 0.0000000100000008f, 1),
"Minimal difference between very small floating point numbers is considered equal"
@@ -55,7 +55,7 @@ namespace Nuclex.Support {
/// Tests the double precision floating point value comparison helper
[Test]
- public void TestDoubleComparison() {
+ public void UlpDistancesOnDoublesCompareAsEqual() {
Assert.IsTrue(
FloatHelper.AreAlmostEqual(0.00000001, 0.000000010000000000000002, 1),
"Minimal difference between very small double precision floating point " +
@@ -81,7 +81,7 @@ namespace Nuclex.Support {
/// Tests the integer reinterpretation functions
[Test]
- public void TestIntegerReinterpretation() {
+ public void IntegersCanBeReinterpretedAsFloats() {
Assert.AreEqual(
12345.0f,
FloatHelper.ReinterpretAsFloat(FloatHelper.ReinterpretAsInt(12345.0f)),
@@ -91,7 +91,7 @@ namespace Nuclex.Support {
/// Tests the long reinterpretation functions
[Test]
- public void TestLongReinterpretation() {
+ public void LongsCanBeReinterpretedAsDoubles() {
Assert.AreEqual(
12345.67890,
FloatHelper.ReinterpretAsDouble(FloatHelper.ReinterpretAsLong(12345.67890)),
@@ -101,7 +101,7 @@ namespace Nuclex.Support {
/// Tests the floating point reinterpretation functions
[Test]
- public void TestFloatReinterpretation() {
+ public void FloatsCanBeReinterpretedAsIntegers() {
Assert.AreEqual(
12345,
FloatHelper.ReinterpretAsInt(FloatHelper.ReinterpretAsFloat(12345)),
@@ -109,12 +109,33 @@ namespace Nuclex.Support {
);
}
+ ///
+ /// Verifies that the IsZero() method can distinguish zero from very small values
+ ///
+ [Test]
+ public void CanDetermineIfFloatIsZero() {
+ Assert.IsTrue(FloatHelper.IsZero(FloatHelper.PositiveZeroFloat));
+ Assert.IsTrue(FloatHelper.IsZero(FloatHelper.NegativeZeroFloat));
+ Assert.IsFalse(FloatHelper.IsZero(1.401298E-45f));
+ Assert.IsFalse(FloatHelper.IsZero(-1.401298E-45f));
+ }
+
+ ///
+ /// Verifies that the IsZero() method can distinguish zero from very small values
+ ///
+ [Test]
+ public void CanDetermineIfDoubleIsZero() {
+ Assert.IsTrue(FloatHelper.IsZero(FloatHelper.PositiveZeroDouble));
+ Assert.IsTrue(FloatHelper.IsZero(FloatHelper.NegativeZeroDouble));
+ Assert.IsFalse(FloatHelper.IsZero(4.94065645841247E-324));
+ Assert.IsFalse(FloatHelper.IsZero(-4.94065645841247E-324));
+ }
///
/// Tests the double prevision floating point reinterpretation functions
///
[Test]
- public void TestDoubleReinterpretation() {
+ public void DoublesCanBeReinterpretedAsLongs() {
Assert.AreEqual(
1234567890,
FloatHelper.ReinterpretAsLong(FloatHelper.ReinterpretAsDouble(1234567890)),
@@ -122,6 +143,26 @@ namespace Nuclex.Support {
);
}
+ // http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/
+ // Make both positive
+ // If both are negative -> fine
+ // If both are positive -> fine
+ // If different -> Measure both distances to zero in ulps and sum them
+ public void NegativeZeroEqualsPositiveZero() {
+ float zero = 0.0f;
+ float zeroPlusOneUlp = FloatHelper.ReinterpretAsFloat(
+ FloatHelper.ReinterpretAsInt(zero) + 1
+ );
+ float zeroMinusOneUlp = -zeroPlusOneUlp;
+
+ bool test = FloatHelper.AreAlmostEqual(zeroMinusOneUlp, zeroPlusOneUlp, 1);
+
+ Assert.IsFalse(FloatHelper.AreAlmostEqual(zero, zeroPlusOneUlp, 0));
+ Assert.IsTrue(FloatHelper.AreAlmostEqual(zero, zeroPlusOneUlp, 1));
+ Assert.IsFalse(FloatHelper.AreAlmostEqual(zero, zeroMinusOneUlp, 0));
+ Assert.IsTrue(FloatHelper.AreAlmostEqual(zero, zeroMinusOneUlp, 1));
+ }
+
}
} // namespace Nuclex.Support
diff --git a/Source/FloatHelper.cs b/Source/FloatHelper.cs
index ce4636a..0833753 100644
--- a/Source/FloatHelper.cs
+++ b/Source/FloatHelper.cs
@@ -88,6 +88,40 @@ namespace Nuclex.Support {
#endregion // struct DoubleLongUnion
+ /// A floating point value that holds a positive zero
+ public const float PositiveZeroFloat = +0.0f;
+
+ /// A floating point value that holds a negative zero
+ ///
+ /// Negative zeros have a special representation in IEEE 752 floating point math
+ ///
+ public const float NegativeZeroFloat = -0.0f;
+
+ /// A double precision floating point value that holds a positive zero
+ public const double PositiveZeroDouble = +0.0;
+
+ /// A doublep precision floating point value that holds a negative zero
+ ///
+ /// Negative zeros have a special representation in IEEE 752 floating point math
+ ///
+ public const double NegativeZeroDouble = -0.0;
+
+ /// Checks whether the floating point value is exactly zero
+ /// Value that will be checked for being zero
+ /// True if the value is zero, false otherwise
+ public static bool IsZero(float value) {
+ return (value == PositiveZeroFloat) || (value == NegativeZeroFloat);
+ }
+
+ ///
+ /// Checks whether the double precision floating point value is exactly zero
+ ///
+ /// Value that will be checked for being zero
+ /// True if the value is zero, false otherwise
+ public static bool IsZero(double value) {
+ return (value == PositiveZeroDouble) || (value == NegativeZeroDouble);
+ }
+
/// Compares two floating point values for equality
/// First floating point value to be compared
/// Second floating point value t be compared