Why float.Epsilon and not zero?

Olivier Pons picture Olivier Pons · May 13, 2015 · Viewed 21.7k times · Source

In the following code, why is there a comparison against float.Epsilon and not 0?

// Coroutine to move elements
protected IEnumerator SmoothMovement (Vector3 end)
{
    // Distance computation
    float sqrRemainingDistance = (transform.position - end).sqrMagnitude;

    while(sqrRemainingDistance > float.Epsilon)
    {
        Vector3 newPostion = Vector3.MoveTowards(
            rb2D.position, end, inverseMoveTime * Time.deltaTime
        );
        rb2D.MovePosition (newPostion);
        sqrRemainingDistance = (transform.position - end).sqrMagnitude;
        yield return null;
    }
}

Answer

D Stanley picture D Stanley · May 13, 2015

Actually, using float.Epsilon may not make any significant difference here. float.Epsilon is the smallest possible float greater than zero (roughly 1.401298E-45), which does not mean that it's the smallest difference between any two arbitrary floats. Since floating-point math is imprecise, the difference between two seemingly equal numbers can be much greater than float.Epsilon. For example:

float f1 = 1.0f / 3.0f;
float f = 1.0f;

(f1 * 3).Dump();  // 1
(f1 * 3 - f).Dump();  // 2.980232E-08

When comparing floats, a better practice is to choose a reasonable value to determine if two floats are "close enough" to be equal. That's a contextual definition - e.g. for distance, is 1mm "close enough"? Maybe when building a doghouse, but not a circuit board. You're not going to keep cutting a piece of wood until it's length is within 1.401298E-45 meters of the target. You're going to choose a difference that's "close enough" to call them equal.

For sprite movement (which I'm assuming that's what's being done in the sample) - maybe a more reasonable "epsilon" is the smallest distance that can be represented on a high-res monitor (or at least that would be noticed by the human eye).

All that to say that sqrRemainingDistance > 0 may be just as reasonable here, since there's no other number between 0 and float.Epsilon that the number could be, but a better choice may be some number much larger than Epsilon to determine when to stop looping. The program may be looping a lot more than it has to in order to get to a "reasonable" result.

In fact, it's documented on MSDN:

If you create a custom algorithm that determines whether two floating-point numbers can be considered equal, you must use a value that is greater than the Epsilon constant to establish the acceptable absolute margin of difference for the two values to be considered equal. (Typically, that margin of difference is many times greater than Epsilon.)