représentation exacte des points flottants en c

void main() { float a = 0.7; if (a < 0.7) printf("c"); else printf("c++"); } 

Dans la question ci-dessus pour 0.7, “c” sera imprimé, mais pour 0.8, “c ++” sera imprimé. Pourquoi?

Et comment un float est-il représenté sous forme binary?

À certains endroits, il est mentionné que 0,7 sera stocké à l’intérieur de 0,699997, mais 0,8 à 0,8000011. Pourquoi

essentiellement avec float vous obtenez 32 bits qui codent

 VALUE = SIGN * MANTISSA * 2 ^ (128 - EXPONENT) 32-bits = 1-bit 23-bits 8-bits 

et qui est stocké comme

 MSB LSB [SIGN][EXPONENT][MANTISSA] 

puisque vous n’obtenez que 23 bits, c’est la quantité de “précision” que vous pouvez stocker. Si vous essayez de représenter une fraction irrationnelle (ou répétée) en base 2, la séquence de bits sera “arrondie” au 23ème bit.

0.7 base 10 est 7/10 qui en binary est 0b111 / 0b1010 vous obtenez:

 0.1011001100110011001100110011001100110011001100110011... etc 

Depuis que cela se répète, avec une précision fixe, il n’ya aucun moyen de le représenter exactement. Il en va de même pour 0.8 qui en binary est:

 0.1100110011001100110011001100110011001100110011001101... etc 

Pour voir quelle est la valeur de précision fixe de ces nombres, vous devez les “couper” au nombre de bits que vous avez et faire le calcul. Le seul truc, c’est que le premier 1 est impliqué et non enregistré, ce qui vous donne techniquement un peu plus de précision. En raison de l’arrondi, le dernier bit sera 1 ou 0 en fonction de la valeur du bit tronqué.

Donc, la valeur de 0,7 est effectivement 11 744 051/2 ^ 24 (aucun effet d’arrondi) = 0,699999988 et la valeur de 0,8 est effectivement 13 421 773/2 ^ 24 (arrondi à la hausse) = 0,800000012.

C’est tout ce qu’on peut en dire 🙂

Ce que tous les informaticiens devraient savoir sur l’arithmétique en virgule flottante est une bonne référence. Vous pouvez utiliser des types de précision plus élevés (par exemple, double) ou une bibliothèque décimale codée binary (BCD) pour obtenir une meilleure précision en virgule flottante si vous en avez besoin.

La représentation interne est IEE754 .

Vous pouvez également utiliser cette calculasortingce pour convertir des nombres décimaux en nombres flottants. J’espère que cela vous aidera à comprendre le format.

float s seront stockées comme décrit dans IEEE 754: 1 bit pour le signe, 8 pour un exposant biaisé et le rest pour stocker la partie décimale.

Pensez aux nombres pouvant être représentés comme des flottants comme des points sur la droite numérique, à une certaine distance les uns des autres; fréquemment, des fractions décimales se situent entre ces points et la représentation la plus proche est utilisée; cela conduit aux résultats contre-intuitifs que vous décrivez.

“Ce que tout informaticien devrait savoir sur l’arithmétique en virgule flottante” devrait répondre à toutes vos questions en détail.

Si vous souhaitez savoir comment float / double est présenté en C (et dans presque toutes les langues), reportez-vous à la norme pour l’arithmétique en virgule flottante (IEEE 754) http://en.wikipedia.org/wiki/IEEE_754-2008

 Using single-precision floats as an example, here is the bit layout: seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm meaning 31 0 bit # s = sign bit, e = exponent, m = mantissa 

Une autre bonne ressource pour voir comment les nombres en virgule flottante sont stockés sous forme binary dans les ordinateurs est la page de Wikipedia sur IEEE-754 .

Les nombres en virgule flottante en C / C ++ sont représentés au format standard IEEE-754. Il existe de nombreux articles sur Internet qui décrivent de manière beaucoup plus détaillée que ce que je peux ici, comment exactement un point flottant est représenté en binary. Une simple recherche d’IEEE-754 devrait éclairer le mystère.

0,7 est un littéral numérique; sa valeur est le nombre mathématique réel 0.7, arrondi à la valeur double la plus proche.

Après l’initialisation de float a = 0,7, la valeur de a est 0,7 arrondie à float, c’est-à-dire le nombre réel 0,7, arrondie à la valeur double la plus proche, arrondie à la valeur float la plus proche. Sauf par une énorme coïncidence, vous ne vous attendriez pas à une valeur égale à 0,7.

“if (a <0.7)" compare 0,7 arrondi au double, puis flotte avec le nombre 0,7 arrondi au double. Il semble que dans le cas de 0,7, l’arrondi ait produit un nombre inférieur. Et dans la même expérience avec 0.8, arrondir 0.8 à float produira un nombre supérieur à 0.8.

Les comparaisons en virgule flottante ne sont pas fiables, quoi que vous fassiez. Vous devez utiliser une comparaison tolérante au seuil / une comparaison epsilon des points flottants.

Essayez la conversion à virgule flottante IEEE-754 et voyez ce que vous obtenez. 🙂