diff --git a/Nuclex.Support (x86).csproj b/Nuclex.Support (x86).csproj
index dcc9a8d..0a0e8ab 100644
--- a/Nuclex.Support (x86).csproj
+++ b/Nuclex.Support (x86).csproj
@@ -108,6 +108,10 @@
TransformingReadOnlyCollection.cs
+
+
+ FloatHelper.cs
+
LicenseKey.cs
diff --git a/Source/FloatHelper.Test.cs b/Source/FloatHelper.Test.cs
new file mode 100644
index 0000000..d84e752
--- /dev/null
+++ b/Source/FloatHelper.Test.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+
+#if UNITTEST
+
+using NUnit.Framework;
+
+namespace Nuclex.Support {
+
+ /// Unit Test for the FloatHelper class
+ [TestFixture]
+ public class FloatHelperTest {
+
+ /// Tests the floating point value comparison helper
+ [Test]
+ public void TestFloatComparison() {
+ Assert.IsTrue(
+ FloatHelper.AreAlmostEqual(0.00000001f, 0.0000000100000008f, 1),
+ "Minimal difference between very small floating point numbers is considered equal"
+ );
+ Assert.IsFalse(
+ FloatHelper.AreAlmostEqual(0.00000001f, 0.0000000100000017f, 1),
+ "Larger difference between very small floating point numbers is not considered equal"
+ );
+
+ Assert.IsTrue(
+ FloatHelper.AreAlmostEqual(1000000.00f, 1000000.06f, 1),
+ "Minimal difference between very large floating point numbers is considered equal"
+ );
+ Assert.IsFalse(
+ FloatHelper.AreAlmostEqual(1000000.00f, 1000000.13f, 1),
+ "Larger difference between very large floating point numbers is not considered equal"
+ );
+ }
+
+ /// Tests the double precision floating point value comparison helper
+ [Test]
+ public void TestDoubleComparison() {
+ Assert.IsTrue(
+ FloatHelper.AreAlmostEqual(0.00000001, 0.000000010000000000000002, 1),
+ "Minimal difference between very small double precision floating point " +
+ "numbers is considered equal"
+ );
+ Assert.IsFalse(
+ FloatHelper.AreAlmostEqual(0.00000001, 0.000000010000000000000004, 1),
+ "Larger difference between very small double precision floating point " +
+ "numbers is not considered equal"
+ );
+
+ Assert.IsTrue(
+ FloatHelper.AreAlmostEqual(1000000.00, 1000000.0000000001, 1),
+ "Minimal difference between very large double precision floating point " +
+ "numbers is considered equal"
+ );
+ Assert.IsFalse(
+ FloatHelper.AreAlmostEqual(1000000.00, 1000000.0000000002, 1),
+ "Larger difference between very large double precision floating point " +
+ "numbers is not considered equal"
+ );
+ }
+
+ }
+
+} // namespace Nuclex.Support
+
+#endif // UNITTEST
\ No newline at end of file
diff --git a/Source/FloatHelper.cs b/Source/FloatHelper.cs
new file mode 100644
index 0000000..412ac98
--- /dev/null
+++ b/Source/FloatHelper.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace Nuclex.Support {
+
+ /// Helper routines for working with floating point numbers
+ ///
+ /// The floating point comparison code is based on this excellent article:
+ /// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
+ ///
+ public static class FloatHelper {
+
+ #region struct FloatIntUnion
+
+ /// Union of a floating point variable and an integer
+ [StructLayout(LayoutKind.Explicit)]
+ private struct FloatIntUnion {
+
+ /// The union's value as a floating point variable
+ [FieldOffset(0)]
+ public float Float;
+
+ /// The union's value as an integer
+ [FieldOffset(0)]
+ public int Int;
+
+ /// The union's value as an unsigned integer
+ [FieldOffset(0)]
+ public uint UInt;
+
+ }
+
+ #endregion // struct FloatIntUnion
+
+ #region struct DoubleLongUnion
+
+ /// Union of a double precision floating point variable and a long
+ [StructLayout(LayoutKind.Explicit)]
+ private struct DoubleLongUnion {
+
+ /// The union's value as a double precision floating point variable
+ [FieldOffset(0)]
+ public double Double;
+
+ /// The union's value as a long
+ [FieldOffset(0)]
+ public long Long;
+
+ /// The union's value as an unsigned long
+ [FieldOffset(0)]
+ public ulong ULong;
+
+ }
+
+ #endregion // struct DoubleLongUnion
+
+ /// Compares two floating point values for equality
+ /// First floating point value to be compared
+ /// Second floating point value t be compared
+ ///
+ /// Maximum number of representable floating point values that are allowed to
+ /// be between the left and the right floating point values
+ ///
+ /// True if both numbers are equal or close to being equal
+ ///
+ ///
+ /// Floating point values can only represent a limited series of natural numbers.
+ /// For example, the values 2.00000000 and 2.00000024 can be stored in a float,
+ /// but nothing inbetween them.
+ ///
+ ///
+ /// This comparison will count how many possible floating point values are between
+ /// the left and the right number. If the number of possible values between both
+ /// numbers is less than or equal to maxUlps, then the numbers are considered as
+ /// being equal.
+ ///
+ ///
+ /// Implementation partially follows the code outlined here:
+ /// http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/
+ ///
+ ///
+ public static bool AreAlmostEqual(float left, float right, int maxUlps) {
+ FloatIntUnion leftUnion = new FloatIntUnion();
+ FloatIntUnion rightUnion = new FloatIntUnion();
+
+ leftUnion.Float = left;
+ rightUnion.Float = right;
+
+ uint leftSignMask = (leftUnion.UInt >> 31);
+ uint rightSignMask = (rightUnion.UInt >> 31);
+
+ uint leftTemp = ((0x80000000 - leftUnion.UInt) & leftSignMask);
+ leftUnion.UInt = leftTemp | (leftUnion.UInt & ~leftSignMask);
+
+ uint rightTemp = ((0x80000000 - rightUnion.UInt) & rightSignMask);
+ rightUnion.UInt = rightTemp | (rightUnion.UInt & ~rightSignMask);
+
+ return (Math.Abs(leftUnion.Int - rightUnion.Int) <= maxUlps);
+ }
+
+ /// Compares two double precision floating point values for equality
+ /// First double precision floating point value to be compared
+ /// Second double precision floating point value t be compared
+ ///
+ /// Maximum number of representable double precision floating point values that are
+ /// allowed to be between the left and the right double precision floating point values
+ ///
+ /// True if both numbers are equal or close to being equal
+ ///
+ ///
+ /// Double precision floating point values can only represent a limited series of
+ /// natural numbers. For example, the values 2.0000000000000000 and 2.0000000000000004
+ /// can be stored in a double, but nothing inbetween them.
+ ///
+ ///
+ /// This comparison will count how many possible double precision floating point
+ /// values are between the left and the right number. If the number of possible
+ /// values between both numbers is less than or equal to maxUlps, then the numbers
+ /// are considered as being equal.
+ ///
+ ///
+ /// Implementation partially follows the code outlined here:
+ /// http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/
+ ///
+ ///
+ public static bool AreAlmostEqual(double left, double right, long maxUlps) {
+ DoubleLongUnion leftUnion = new DoubleLongUnion();
+ DoubleLongUnion rightUnion = new DoubleLongUnion();
+
+ leftUnion.Double = left;
+ rightUnion.Double = right;
+
+ ulong leftSignMask = (leftUnion.ULong >> 63);
+ ulong rightSignMask = (rightUnion.ULong >> 63);
+
+ ulong leftTemp = ((0x8000000000000000 - leftUnion.ULong) & leftSignMask);
+ leftUnion.ULong = leftTemp | (leftUnion.ULong & ~leftSignMask);
+
+ ulong rightTemp = ((0x8000000000000000 - rightUnion.ULong) & rightSignMask);
+ rightUnion.ULong = rightTemp | (rightUnion.ULong & ~rightSignMask);
+
+ return (Math.Abs(leftUnion.Long - rightUnion.Long) <= maxUlps);
+ }
+
+ }
+
+} // namespace Nuclex.Support