Click or drag to resize
DigitalRuneHow To: Compare Floating-Point Numbers

This section shows how to safely compare floating-point numbers.

This topic contains the following sections:

The class Numeric

This library contains a class Numeric that supports proper comparison of floating-point values. The comparisons are performed by checking if two values differ by less than a tolerance value epsilon. (Note: The class Numeric is part of the DigitalRune.dll not the DigitalRune.Mathematics.dll.)

Following code shows a simple example where comparison with == is not desired.

C#
// Lets do some arbitrary calculations.
float a = (float)Math.PI;
float b = (float)Math.Sqrt(a);
float c = (float)Math.Sqrt(b);
float d = c * c * c * c;

// --> d should be equal to a, but because of limited precision and numerical errors a != d.
if (a == d)
  Console.WriteLine("a == d");
else
  Console.WriteLine("a != d");     // This message is written. :-(

// Comparison methods in Numeric allow a small error.
if (Numeric.AreEqual(a, d))
  Console.WriteLine("Numeric.AreEqual(a, d) is true.");  // This message is written. :-)
else
  Console.WriteLine("Numeric.AreEqual(a, d) is false.");

Numeric has several other methods for comparison of floating-point numbers (single or double precision).

Epsilon values

The values EpsilonF and EpsilonD in Numeric define the allowed error for the numerical comparison methods for single- and double-precision floating-point numbers. These values are used in the methods of Numeric - unless the method allows to specify a different epsilon as a method parameter.

These epsilon values have been optimized for typical 3D simulations and games - including 3D collision detection and rigid body physics simulation.

Common pitfalls

EpsilonF is used for single-precision floating-point numbers. EpsilonD is used for double-precision floating-point numbers. One common mistake is to invoke a method that uses the wrong epsilon value:

C#
float myFloat = ...;
bool result1 = Numeric.AreEqual(myFloat, Math.Cos(0.3f)));        // Warning: This uses EpsilonD because Math.Cos() returns double!
bool result2 = Numeric.AreEqual(myFloat, (float)Math.Cos(0.3f))); // This uses EpsilonF!
Floating-point numbers in other types

Several types implement the comparison operators (==, !=, >=, etc. in C#), for example: Vector3F, Matrix44F. These overloaded operations compare the floating-point values directly (without using an epsilon tolerance). In addition to the equality operators most types have methods, like AreNumericallyEqual, that perform comparisons using an epsilon tolerance.

This example compares two vectors:

C#
// Define a vector.
Vector3F v0 = new Vector3F(1000, 2000, 3000);

// Define a rotation quaternion that rotates 360° around the x axis.
QuaternionF rotation = QuaternionF.CreateRotationX(MathHelper.ToRadians(360));

// Rotate v0.
Vector3F v1 = rotation.Rotate(v0);

// The rotated vector v1 should be identical to v0 because a 360° rotation should not
// change the vector. - But due to numerical errors v0 and v1 are not equal.
if (v0 == v1)
  Console.WriteLine("Vectors are equal.");
else
  Console.WriteLine("Vectors are not equal.");   // This message is written. :-(

// With Vector3F.AreNumericallyEqual() we can check if two vectors are equal when we allow
// a small numeric tolerance.
if (Vector3F.AreNumericallyEqual(v0, v1))
  Console.WriteLine("Vectors are numerically equal."); // This message is written. :-)
else
  Console.WriteLine("Vectors are not numerically equal.");