Why float.Epsilon and not zero?
Asked Answered
J

2

48

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;
    }
}
Japha answered 13/5, 2015 at 13:37 Comment(6)
Because float.Epsilon is not 0. en.wikipedia.org/wiki/Machine_epsilonAfton
#2411892Alverta
It's either unnecessary or it's incorrect. If the author is attempting to avoid rounding errors, then float.Epsilon is generally too small a value to use. If they are not attempting to avoid rounding errors, they are doing something very strange (which is likely also incorrect) or unnecessary.Easement
Why was this downvoted? Seems like a legit question to me.Mountbatten
I was seeing "Unity 2D Roguelike" tutorial and was also wondering about "float.Epsilon" and just found out this same code :)Earing
Unity 2D Roguelike tutorial brought me here too :) Thanks for the question!Calcium
F
53

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.)

Faustofaustus answered 13/5, 2015 at 14:2 Comment(0)
U
0

Because floating point math is not precise. The article I linked is long and detailed, so let me explain with a simple example:

43.65+61.11=104.75999999999999

The reason behind is how float-point numbers are actually saved. If you don't want to dive into this, just keep in mind the general limitations of floating-point arithmetic and don't expect them to be precisely what they should be according to math — including, in this case, 0.

Urinalysis answered 13/5, 2015 at 14:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.