Question

Je sais que vous ne pouvez pas compter normalement sur l'égalité entre les valeurs de type double ou décimale, mais je me demande si 0 est un cas spécial.

Bien que je puisse comprendre les imprécisions entre 0.00000000000001 et 0.00000000000002, 0 lui-même semble assez difficile à gâcher car ce n'est rien. Si vous êtes imprécis sur rien, ce n'est plus rien.

Mais je ne connais pas grand chose à ce sujet, donc ce n'est pas à moi de le dire.

double x = 0.0;
return (x == 0.0) ? true : false;

Cela reviendra-t-il toujours vrai?

Était-ce utile?

La solution

Il est sûr de s'attendre à ce que la comparaison retourne true si et seulement si la variable double a exactement la valeur 0.0 (ce qui, dans votre extrait de code d'origine, est bien sûr: l'affaire). Ceci est cohérent avec la sémantique de l'opérateur ==. a == b signifie que " a est égal à b ".

Il est dangereux (car inexact ) de s'attendre à ce que le résultat de certains calculs soit nul dans l'arithmétique double (ou plus généralement, à virgule flottante). chaque fois que le résultat du même calcul en mathématiques pures est égal à zéro. En effet, lorsque les calculs entrent dans le sol, une erreur de précision en virgule flottante apparaît - un concept qui n’existe pas dans l’arithmétique des nombres réels en mathématiques.

Autres conseils

Si vous devez faire beaucoup de " égalité " comparaisons, il peut être judicieux d’écrire une petite fonction d’aide ou une méthode d’extension dans .NET 3.5 pour comparer:

public static bool AlmostEquals(this double double1, double double2, double precision)
{
    return (Math.Abs(double1 - double2) <= precision);
}

Ceci pourrait être utilisé de la manière suivante:

double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);

Pour votre exemple simple, ce test est correct. Mais qu'en est-il de cela:

bool b = ( 10.0 * .1 - 1.0 == 0.0 );

N'oubliez pas que .1 est un nombre décimal répété en binaire et ne peut pas être représenté exactement. Comparez ensuite cela à ce code:

double d1 = 10.0 * .1; // make sure the compiler hasn't optimized the .1 issue away
bool b = ( d1 - 1.0 == 0.0 );

Je vous laisserai faire un test pour voir les résultats réels: vous vous en souviendrez probablement mieux.

À partir de l'entrée MSDN pour Double.Equals :

  

Précision dans les comparaisons

     

La méthode Equals doit être utilisée avec   prudence, car deux apparemment   les valeurs équivalentes peuvent être inégales en raison   à la précision différente des deux   valeurs. Les exemples suivants de rapports   que la valeur double .3333 et la   Double retourné en divisant 1 par 3 sont   inégale.

     

...

     

Plutôt que de comparer pour l'égalité,   une technique recommandée implique   définir une marge acceptable de   différence entre deux valeurs (telles que   .01% d'une des valeurs). Si la   valeur absolue de la différence   entre les deux valeurs est inférieure ou   égale à cette marge, la différence   est susceptible d'être due à des différences de   la précision et, par conséquent, les valeurs   sont susceptibles d'être égaux. Le suivant   exemple utilise cette technique pour comparer   .33333 et 1/3, les deux valeurs de Double   que l'exemple de code précédent trouvé   être inégale.

Voir également Double.Epsilon .

Le problème survient lorsque vous comparez différents types d'implémentation de valeurs en virgule flottante, par exemple. comparer float avec double. Mais avec le même type, cela ne devrait pas être un problème.

float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true

Le problème est que le programmeur oublie parfois que le transtypage de type implicite (double à float) est en cours pour la comparaison et qu'il en résulte un bogue.

Si le numéro a été directement attribué au nombre à virgule flottante ou au numéro double, il est prudent de tester le nombre zéro ou tout nombre entier pouvant être représenté sur 53 bits pour un nombre double ou 24 bits pour un nombre à virgule flottante.

Ou, autrement dit, vous pouvez toujours attribuer une valeur entière à un double, puis comparer le double au même nombre entier et vous assurer qu'il sera égal.

Vous pouvez également commencer par attribuer un nombre entier et faire en sorte que des comparaisons simples continuent de s’en tenir à l’ajout, la soustraction ou la multiplication par des nombres entiers (en supposant que le résultat est inférieur à 24 bits pour un float et à 53 bits pour un double) . Vous pouvez donc traiter les flottants et les doublons comme des entiers dans certaines conditions contrôlées.

Non, ce n'est pas OK. Les valeurs dites dénormalisées (sous-normales), lorsqu'elles sont comparées à 0,0, sont considérées comme fausses (non nulles), mais lorsqu'elles sont utilisées dans une équation, elles sont normalisées (deviennent 0,0). Par conséquent, l’utilisation de ce mécanisme pour éviter une division par zéro n’est pas sans danger. Au lieu de cela, ajoutez 1.0 et comparez à 1.0. Cela garantira que toutes les sous-normales sont traitées comme zéro.

Essayez ceci et vous constaterez que == n’est pas fiable pour le double / float.
double d = 0.1 + 0.2; bool b = d == 0.3;

Voici les réponse de Quora.

En fait, je pense qu'il est préférable d'utiliser les codes suivants pour comparer une valeur double à 0.0:

double x = 0.0;
return (Math.Abs(x) < double.Epsilon) ? true : false;

Idem pour float:

float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top