9
votes

Pourquoi la variable float enregistre la valeur en coupant des chiffres après le point d'une manière étrange?

J'ai cette ligne de code simple: xxx

Lorsque j'imprime ce Val ou regarde dans la portée, il stocke la valeur 123456.13

OK, ça va bien, ça va " T Stocker tous ces chiffres après le point juste en 4 octets, mais pourquoi cela fait-il 13 après le point? Ne devrait-il pas être 12?

(Utilisation de VC ++ 2010 Express sur Win32)


1 commentaires

Merci à tout le monde pour les réponses. je l'ai maintenant. Je viens de laisser tomber des chiffres soulevés après le point, au lieu de l'arrondir.


5 Réponses :


2
votes

Essayez d'imprimer la valeur de std :: numeric_limits :: chiffres10 . Cela parle à peu près combien de précision dans la base 10 un flotteur a. Vous essayez de le dépasser, vous vivez donc une perte de précision (ce qui signifie que les chiffres au-delà des importants ne sont pas vraiment significatifs).

Voir par ex. Quelle est la signification de numeric_limits :: chiffres10


0 commentaires

2
votes

C'est totalement dépendant du compilateur. Vérifiez-le dans GCC. Il devrait être xxx.12


2 commentaires

Si le format utilisé en interne est IEEE-754, il ne devrait pas être dépendant du compilateur du tout.


Je pense que nous donnons des significations différentes "dépendantes du compilateur"; Ce que je - et les autres - ont compris, c'est que vous dites que "il est normal qu'il varie de compilateur au compilateur". Dites-vous à la place que c'est un bogue Spécifique compilateur ?



8
votes

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

sortie: 123456.1250 123456.1250

Vous devez utiliser Double dans ce cas pour éviter la troncature. COMPILER devrait également vous avertir: "AVERTISSEMENT C4305:" Initialisation ": TRONCRATION DU 'DOUBLE' AUX 'FLOAT'"


0 commentaires

10
votes

en binaire, 123456.123456 est 1111000100100000000.000111111001 ... (infini). Il fait partie de 11110001001000000.001, ou 123456.125. que tonne à 123456.13 lorsqu'il est imprimé.


0 commentaires

7
votes

Lorsqu'il est représenté comme un flotteur, votre numéro a un exposant de 16 (c'est-à-dire que la valeur est sa manipication Times 2 ^ 16, ou 65536). La Manjusse devient alors xxx

afin de s'intégrer dans un flotteur 32 bits, la rencontre est tronquée à 23 bits, alors cela devient maintenant 1.883791 . Lorsqu'il est multiplié par 65536 , il devient 123456.125 .

notez le 5 en troisième position après le point décimal: La routine de sortie de C ++ que vous avez utilisée l'arrondit, rendant votre numéro final ressemblant à 123456.13 .

Edit Explication de l'arrondi: (Rick Regan's Commentaire)

L'arrondi se produit d'abord en binaire (à 24 bits), en décimalement à une conversion binaire, puis en décimal, dans printf . La valeur stockée est 1.1110001001000000001 x 2 ^ 16 = 1.8837909698486328125 x 2 ^ 16 = 123456.125. Il imprime comme 123456.13, mais seulement parce que Visual C ++ utilise "à la moitié tour à moitié de zéro" arrondi.

Rick a un article exceptionnel sur le sujet , aussi.

Si vous souhaitez jouer avec d'autres numéros et leurs représentations de flotteur, ici est un calculatrice IEEE-754 très utile .


4 commentaires

Pourriez-vous s'il vous plaît expliquer un peu plus .. Je ne pouvais pas comprendre particulièrement cette ligne "lorsqu'il est représenté comme un flotteur, votre numéro a un exposant de 16". Pourquoi c'est nécessaire?


@Rasmiranjannayak 32 bits Float est représenté comme une manipication 23 bits, un exposant binaire sept bits et un bit de signalisation. Logiquement, vous divisez votre numéro d'origine par deux et incrémentez l'exposant jusqu'à ce que le seul chiffre restant devant le point décimal soit 1 . Pour 123456.123456 , 16 divisions sont nécessaires.


@dasblinkenlight au mieux cette description est trompeuse. L'arrondi survient d'abord chez Binary (à 24 bits), en décimale à la conversion binaire, puis en décimal, dans Printf. La valeur stockée est 1.1110001001000000001 x 2 ^ 16 = 1.8837909698486328125 x 2 ^ 16 = 123456.125. Il imprime comme 123456.13, mais uniquement parce que Visual C ++ utilise "à la moitié de zéro de zéro" arrondi (voir mon article explorkiny.com/... )


@Rickregan WOW, bel article! Merci pour la référence, j'ai ajouté votre commentaire à la réponse pour le rendre plus complet. Merci beaucoup pour votre aide!