Pourquoi variable flottante valeur permet d'économiser en coupant chiffres après le point d'une manière bizarre?

StackOverflow https://stackoverflow.com/questions/9328854

Question

Je cette simple ligne de code:

float val = 123456.123456;

quand j'imprimer ce val ou regarder une portée, il stocke la valeur 123456,13

Ok, il va bien, il ne peut pas stocker tous ces chiffres après le point juste à 4 octets, mais pourquoi faut-il faire 13 après le point? Ça ne devrait pas être 12?

(en utilisant vc ++ 2010 express sur Win32)

Était-ce utile?

La solution

Lorsque représentée comme un flotteur, le nombre a un exposant de 16 (à savoir la valeur est ses deux fois mantisse ^ 16 ou 65536). La mantisse devient alors

123456.123456 / 65536 = 1.8837909462890625

Pour tenir dans un flotteur 32 bits, la mantisse est tronquée à 23 bits, il devient maintenant 1.883791. De retour Multiplié par 65536, il devient 123456.125.

Notez la 5 dans la troisième position après le point décimal:. La routine de sortie de C ++ que vous avez utilisé arrondit, rendant votre look nombre final comme 123456.13

EDIT Explication de l'arrondissement: (commentaire de Rick Regan)

L'arrondi se produit en premier binaire (24 bits), en décimal à la conversion binaire, puis en décimal, en printf. La valeur mémorisée est 1,1110001001000000001 x 2 ^ 16 = 2 ^ 1,8837909698486328125 x 16 = 123.456,125. Il imprime comme 123456,13, mais seulement parce que Visual C ++ utilise « un demi-tour loin de zéro » arrondi.

Rick a un article exceptionnel sur le sujet aussi.

Si vous voulez jouer avec d'autres chiffres et leurs représentations flottantes, voici un très utile calculatrice IEEE-754 .

Autres conseils

En binaire, 123456.123456 est 11110001001000000,000111111001 ... (infini). Il arrondit à 11110001001000000,001 ou 123456,125. que tours à 123456,13 à l'impression.

La valeur stockée dans val est égale à 123456.125. Vous obtenez .13 parce que vous l'arrondir:

float val = 123456.123456;
printf("%.4f %.2f\n", val, val);

sortie: 123456.1250 123456.13

Vous devriez utiliser le double dans ce cas pour éviter troncature. Compilateur devrait également vous avertir: "avertissement C4305: 'initialisation': troncature de 'double' 'flotter'"

.

Essayez d'imprimer la valeur de std::numeric_limits<float>::digits10. Ceci est grosso modo la quantité de précision dans la base 10 un flotteur a. Vous essayez de le dépasser, si vous rencontrez une perte de précision (ce qui signifie que les chiffres au-delà de ceux significatifs ne sont pas vraiment significatifs).

Voir par exemple Quelle est la signification de numeric_limits :: digits10

Il est totalement dépendant compilateur. Vérifiez dans GCC. Il devrait être xxx.12

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top