web-dev-qa-db-fra.com

Pourquoi float.Epsilon et pas zéro?

Dans le code suivant, pourquoi y a-t-il une comparaison avec float.Epsilon et non 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;
    }
}
32
Olivier Pons

En fait, en utilisant float.Epsilon ne peut faire aucune différence significative ici. float.Epsilon est le plus petit possible float supérieur à zéro (environ 1.401298E-45), ce qui ne signifie pas que c'est la plus petite différence entre deux float arbitraires. Étant donné que les mathématiques à virgule flottante sont imprécises, la différence entre deux nombres apparemment égaux peut être beaucoup plus grande que float.Epsilon. Par exemple:

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

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

Lors de la comparaison des flottants, une meilleure pratique consiste à choisir une valeur raisonnable pour déterminer si deux flotteurs sont "suffisamment proches" pour être égaux. C'est une définition contextuelle - par exemple pour la distance, 1 mm est-il "assez proche"? Peut-être lors de la construction d'une niche, mais pas d'un circuit imprimé. Vous n'allez pas continuer à couper un morceau de bois tant que sa longueur n'est pas inférieure à 1.401298E-45 mètres de la cible. Vous allez choisir une différence qui est "assez proche" pour les appeler égaux.

Pour le mouvement Sprite (que je suppose que c'est ce qui se fait dans l'échantillon) - peut-être qu'un "epsilon" plus raisonnable est la plus petite distance qui peut être représentée sur un moniteur haute résolution (ou du moins qui serait remarquée par l'humain œil).

Tout ça pour dire que sqrRemainingDistance > 0 peut être tout aussi raisonnable ici, car il n'y a pas d'autre nombre entre 0 et float.Epsilon que le nombre pourrait être, mais un choix meilleur peut être un nombre beaucoup plus grand que Epsilon pour déterminer quand arrêter la boucle. Le programme peut boucler beaucoup plus qu'il ne doit pour arriver à un résultat "raisonnable".

En fait, il est documenté sur MSDN :

Si vous créez un algorithme personnalisé qui détermine si deux nombres à virgule flottante peuvent être considérés comme égaux, vous devez utiliser une valeur supérieure à la constante Epsilon pour établir la marge de différence absolue acceptable pour les deux valeurs à considérer comme égales. (En règle générale, cette marge de différence est plusieurs fois supérieure à Epsilon.)

37
D Stanley

Parce que les maths à virgule flottante ne sont pas précises . L'article que j'ai lié est long et détaillé, alors laissez-moi vous expliquer avec un exemple simple:

43,65 + 61,11 = 104,75999999999999

La raison en est la façon dont les nombres à virgule flottante sont réellement enregistrés. Si vous ne voulez pas vous plonger dans cela, gardez à l'esprit les limites générales de l'arithmétique à virgule flottante et ne vous attendez pas à ce qu'elles soient précisément ce qu'elles devraient être selon les mathématiques - y compris, dans ce cas, 0.

2
Max Yankov