Comparaison à virgule flottante `a! = 0.7`

Dupliquer possible:
problèmes de comparaison en virgule flottante

#include  #include  main() { float a = 0.7; if(a < 0.7) printf("C"); else printf("C++"); } 

Dans le code ci-dessus, la sortie est C J’ai essayé ce code dans Code :: Blocks et Pelles C mais j’ai obtenu la même réponse. Je voudrais savoir la raison de cela en détail!

En binary, 0.7 est:

 b0.1011001100110011001100110011001100110011001100110011001100110... 

Cependant, 0.7 est un littéral à double précision, dont la valeur est arrondie à la valeur à double précision représentable la plus proche, qui est:

 b0.10110011001100110011001100110011001100110011001100110 

En décimal, c’est exactement:

  0.6999999999999999555910790149937383830547332763671875 

Lorsque vous écrivez float a = 0.7 , cette valeur double est arrondie à la précision simple et a obtient la valeur binary:

 b0.101100110011001100110011 

qui est exactement

  0.699999988079071044921875 

en décimal.

Lorsque vous effectuez la comparaison (a < 0.7) , vous comparez cette valeur à simple précision (convertie en double, ce qui n’arrondit pas car toutes les valeurs à simple précision sont représentables en double précision) à la valeur à double précision originale. Parce que

  0.699999988079071044921875 < 0.6999999999999999555910790149937383830547332763671875 

la comparaison retourne correctement la valeur true et votre programme imprime "C" .

Notez que rien de tout cela n’est différent en C ++, le code en question semble au contraire. Certaines optimisations du compilateur (non fiables sur le plan numérique) peuvent modifier le comportement, mais elles ne sont pas propres à C ou C ++.

C’est parce que 0.7 a le type double , donc a est converti en double et la comparaison est faite dans ce type. Comme 0.7 n’est pas représentable exactement en virgule flottante binary, vous obtenez une erreur d’arrondi et la comparaison devient vraie.

Vous pouvez:

 if( a < 0.7f ) { .... 

Mais en réalité, cet effet est également vrai pour C ++, votre conditionnel n'est donc pas tout à fait légitime.

Bart a donné une très bonne référence dans son commentaire, mais je recommanderais aussi cette règle très simple:

Tous les nombres ne peuvent pas être représentés exactement sur l’ordinateur. Par conséquent, dès que vous utilisez des nombres à virgule flottante (tels que float et double), vous devez vous attendre à une petite erreur imprévisible dans chaque numéro stocké. Non, ce n’est pas vraiment aléatoire ou imprévisible, mais jusqu’à ce que vous en sachiez plus, vous pouvez le considérer comme imprévisible. Par conséquent, une copie telle que votre <0,7 peut se révéler vraie, mais peut-être pas. N’écrivez pas de code qui en dépend.