Is Mathf.Approximately(0.0f, float.Epsilon) == true its correct behavior?

Viewed 1506

I have just noticed that the following code returns true:

Mathf.Approximately(0.0f, float.Epsilon); // true

I have read the Mathf.Approximately Documentation and it states that:

Approximately() compares two floats and returns true if they are within a small value (Epsilon) of each other.

And Mathf.Epsilon Documentation states that:

  • anyValue + Epsilon = anyValue
  • anyValue - Epsilon = anyValue
  • 0 + Epsilon = Epsilon
  • 0 - Epsilon = -Epsilon

As a result, I ran the following code, expecting it to be false, but it also returns true.

Mathf.Approximately(0.0f, 2.0f * float.Epsilon); // true

By the way:

Mathf.Approximately(0.0f, 2.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 3.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 4.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 5.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 6.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 7.0f * float.Epsilon); // true

Mathf.Approximately(0.0f, 8.0f * float.Epsilon); // false
Mathf.Approximately(0.0f, 9.0f * float.Epsilon); // false

Q: Based on that evidence, can I safely say that Mathf.Approximately is not correctly implemented according to its documentation*?

(* and as a result, I should move to different solutions, such as the one in Floating point comparison functions for C#)

2 Answers

Here is the decompiled code of Unity's public static bool Mathf.Approximately(float a, float b); You can see the * 8.0f at the end ^^, so a truely badly documented method indeed.

/// <summary>
/// <para>Compares two floating point values if they are similar.</para>
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
public static bool Approximately(float a, float b)
{
   return (double) Mathf.Abs(b - a) < (double) Mathf.Max(1E-06f * Mathf.Max(Mathf.Abs(a),
       Mathf.Abs(b)), Mathf.Epsilon * 8.0f);
}

It should be Mathf.Approximate(0.0f - 8.0f, float.Epsilon);. Since floats can have an insanely small floating number, you'll need to get subtract both float a and b to get that small number and compare it to float.epsilon.

[EDIT]

It was pointed out that Mathf.Approximate doesn't require an epsilon to be passed so Mathf.Approximate(float a, float b) should suffice. However, if you need to set your own threshold, you can use the above mentioned code.

Related