Comparer les nombres en virgule flottante en C

J’ai un double qui imprime comme 0.000000 et j’essaye de le comparer à 0.0f , sans succès. Pourquoi y a-t-il une différence ici? Quel est le moyen le plus fiable de déterminer si votre double est égal à zéro?

Pour déterminer si elle est suffisamment proche de zéro, elle affichera 0.000000 décimales à six décimales, par exemple:

 fabs(d) < 0.0000005 

Composer avec de petites inexactitudes dans les calculs en virgule flottante peut toutefois s'avérer assez compliqué en général.

Si vous voulez une meilleure idée de la valeur que vous avez, essayez d’imprimer avec %g au lieu de %f .

Vous pouvez faire une gamme. J’aime -0.00001 <= x <= 0.00001

C’est un problème fondamental de l’arithmétique en virgule flottante sur les ordinateurs modernes. Ils sont par nature imprécis et ne peuvent être comparés de manière fiable. Par exemple, le langage ML interdit explicitement la comparaison d’égalité sur des types réels car il a été jugé trop dangereux. Voir aussi l’excellent article (bien qu’un peu long et mathématiquement orienté) de David Goldberg sur ce sujet.

Edit: tl; dr: vous le faites peut-être mal.

De plus, les nombres dénormalisés sont des caractéristiques souvent négligées du nombre à virgule flottante. Ce sont des nombres qui ont l’exposant minimal, mais ne se situent pas dans la gamme 0.5-1.

Ces nombres sont inférieurs à FLT_MIN pour float et à DBL_MIN pour double.

Une erreur courante avec l’utilisation d’un seuil consiste à comparer deux valeurs ou à utiliser FLT_MIN / DBL_MIN comme limite.

Par exemple, cela donnerait un résultat peu logique (si vous ne connaissez pas les dénormalités):

 bool areDifferent(float a, float b) { if (a == b) return false; // Or also: if ((a - b) == FLT_MIN) return true; } // What is the output of areDifferent(val, val + FLT_MIN * 0.5f) ? // true, not false, even if adding half the "minimum value". 

Les dénormalités impliquent aussi généralement une perte de performance dans les calculs. Cependant, vous ne pouvez pas les désactiver, sinon un tel code pourrait toujours produire une exception de virgule flottante DIVIDE BY ZERO (si activée):

 float getInverse(float a, float b) { if (a != b) return 1.0f / (ab); // With denormals disabled, a != b can be true, but (a - b) can still be denormals, it'll rounded to 0 and throw the exception return FLT_MAX; }