Je peux seulement supposer que c'est un bug. La première affirmation passe alors que la seconde échoue: sinon un bug, pourquoi? P> p> p>
7 Réponses :
Vous comparez des nombres de points flottants. Ne faites pas cela, les numéros de points flottants ont une erreur de précision inhérente dans certaines circonstances. Au lieu de cela, prenez la valeur absolue de la différence des deux valeurs et affirmez que la valeur est inférieure à un petit nombre (Epsilon).
void CompareFloats( double d1, double d2, double epsilon ) { assert( abs( d1 - d2 ) < epsilon ); }
Ce qui appelle Ed Erreur de précision est une caractéristique d'arithmétique à virgule flottante. Il n'y a aucun moyen de le faire, ce n'est pas un bug, pas une mise en œuvre négligente de la part des écrivains de la GCC, c'est ainsi que les ordinateurs font des arithmétiques sur les fractions. Google pour «Ce que chaque informaticien doit connaître sur l'arithmétique des points flottants» et commettre ses leçons au cœur.
Ouais, j'ai ajouté un lien vers la spécification.
Google a aussi ce "bogue": Google.com/...
Les comparaisons de nombres de double précision sont intrinsèquement inexactes. Par exemple, vous pouvez souvent trouver Wikipedia dit : p>
Les tests d'égalité sont problématiques. Deux séquences informatiques qui sont mathématiquement égales peuvent produire des valeurs à virgule flottante différentes. P>
blockQuote>
Vous devrez utiliser un delta pour donner une tolérance à vos comparaisons, plutôt qu'une valeur exacte. P> 0.0 == 0.0 code> retour false em>. Cela est dû à la manière dont la FPU stocke et suit les numéros. P>
Ce peut être que dans l'un des cas, vous comprenez de comparer un double enregistreur interne à 64 bits à un registre interne 80 bits. Il peut être éclairant de regarder les instructions de montage émet des éditions GCC pour les deux cas ... p>
C'est quelque chose qui m'a mordu, aussi.
Oui, les numéros de points flottants ne doivent jamais être comparés à l'égalité en raison d'une erreur d'arrondi, et vous saviez probablement cela. P>
mais dans ce cas, Vous êtes informatique Voici ce qui se passe probablement. Je vais parier que vous exécutez ceci sur un processeur X86, correct? Le X86 FPU utilise 80 bits pour ses registres internes, mais les valeurs de la mémoire sont stockées sous forme de double 64 bits. P> donc éditer em> alors pourquoi le premier test de test? Dans ce cas, le compilateur évalue probablement secondaire (em> voici le code de montage généré pour la deuxième partie du code (GCC, X86), avec des commentaires - Suit à peu près le scénario décrit ci-dessus: p> côté intéressant Remarque: ceci a été compilé sans optimisation. Quand il est compilé avec t1 + t2 code>, puis le calculant à nouveau. sûrement em> qui doit produire un résultat identique? P>
t1 + t2 code> est d'abord calculé avec 80 bits de précision, Ensuite, je présume - stocké - stocké à la mémoire dans
Sum_2 code> avec 64 bits de précision - et une certaine arrondi se produit. Pour l'affirmation, elle est chargée dans un registre de point flottant et
t1 + t2 code> est à nouveau calculé, à nouveau avec 80 bits de précision. Alors maintenant, vous comparez
sum_2 code>, qui a déjà été arrondi sur une valeur de point flottante de 64 bits, avec
t1 + t2 code>, calculé avec une précision supérieure (80 bits) - Et c'est pourquoi les valeurs ne sont pas exactement identiques. p>
4.0 + 6,3 code> au moment de la compilation et le stocke comme une quantité de 64 bits - à la fois pour l'affectation et pour l'affirmation. Les valeurs donc identiques sont comparées et les affirmations passent. P>
-O3 code>, le compilateur optimise tous em> du code. P> p>
Je ne pense pas que c'est même ça. La chose est que 4.0 + 6,3 code> est une expression qui est pliée constante par le compilateur à 10.3. Donc, la première affirmation devient équivalente à
Assert (10.3 == 10.3) code> qui passe de manière triviale. Dans le deuxième test, cela prend réellement de 4,0, le mettre en double, prendre 6,3, mettez-le dans un double (perte d'un peu de précision), ajoutez-les ensemble et comparez que i> constante 10.3 , qui échoue parce que c'est différent de 2 ^ -70 environ. :)
Je ne suis pas convaincu ... Si le compilateur peut optimiser T1 + T2 à 10.3 dans la déclaration d'assertion, pourquoi ne peut-il pas faire la même optimisation dans l'affectation à Sum_2?
En regardant la liste, tu m'as eu. :) Pauvre deviner de ma part, je suppose.
Merci pour la réponse géniale! Vous avez raison - je cours sur un X86 et je savais que je ne devrais pas comparer des flotteurs en général, mais c'était dans un test unitaire en veillant à ce que certaines opérations matricielles fonctionnaient correctement. Il passe bien lorsqu'il est compilé avec Visual Studio ... Oh bien.
C'est exactement la situation dans laquelle j'ai rencontré cela - dans un test unitaire dans un cas où je pensais pouvoir exiger une égalité exacte.
J'ai dupliqué votre problème sur mon duo Intel Core 2, et j'ai examiné le code de montage. Voici ce qui se passe: lorsque votre compilateur évalue quand il stocke dans alors la comparaison Qu'est-ce qui est vraiment irritant, c'est que si vous irritant, c'est que si vous êtes vraiment irritant, c'est que si votre compilateur avec < Code> GCC -O1 CODE> ou P.S. Quand je dis que se résout à p> et p> résout à p> Bienvenue dans le monde merveilleux du point flottant! p> p> t1 + t2 code>, il fait
sommate2 code> il fait p>
== code> compare la somme de 80 bits à une somme de 64 bits, et ils sont différents, principalement parce que la partie fractionnelle 0.3 ne peut pas être Représenté avec exactement à l'aide d'un numéro de point flottant binaire, vous comparez donc une "décimale répétée" (répétant réellement binaire) qui a été tronquée à deux longueurs différentes. p>
GCC -O2 CODE>, GCC fait le mauvais arithmétique à la compilation, et le problème disparaît. Peut-être que cela va bien selon la norme, mais c'est juste une autre raison que GCC n'est pas mon compilateur préféré. P>
== code> compare une somme de 80 bits avec une somme de 64 bits, bien sûr, je veux vraiment dire que cela compare la version étendue de la somme 64 bits. Vous risquez de bien vouloir penser p>
Lors de la comparaison des nombres de points flottants pour la proximité, vous souhaitez généralement mesurer leur différence relative, qui est définie comme par exemple, p> Si vous devez déterminer si deux numéros de points flottants sont égaux, vous devez Faites quelque chose comme p> où Machine Epsilon est le plus petit nombre qui peut être maintenu dans la mantissa du matériel à virgule flottante utilisé. La plupart des langues informatiques ont une fonction d'appel pour obtenir cette valeur. ERROR_Factor devrait être basé sur le nombre de chiffres significatifs que vous pensez être consommé par des erreurs d'arrondi (et des autres) dans les calculs des nombres x et y. Par exemple, si je savais que X et Y étaient le résultat d'environ 1 000 sommations et que vous ne connaissiez aucune limite sur les chiffres en cours de sommation, je définirais Errest_Factor sur environ 100. P> essayé de les ajouter comme des liens Mais ne pouvait-il pas puisque c'est mon premier post: p>
Ce "problème" peut être "corrigé" en utilisant ces options: p>
-MSE2 -MFPMATH = SSE P>
Comme expliqué sur cette page: p>
http://www.network-theory.co.uk /docs/gccinttro/gccintro_70.html P>
Une fois que j'ai utilisé ces options, les deux affirmations passées. p>
Vous pouvez aussi regarder: - http://stackoverflow.com/questions/21265 / Comparaison-ICEE-Floa TS-and-Doubles-For-e Qualité - http://stackoverflow.com/questions/17333/ plus -effective-way- For-Float-and-Double -Comparison - Http://stackoverflow.com/questions/713763/strange-Results-wi th-flottant-point-point-bocparison < / a>