2010-10-29 9 views
9

Quelqu'un peut-il expliquer pourquoi multiplier par 100 ici donne un résultat moins précis mais multiplier par 10 deux fois donne un résultat plus précis?erreurs à virgule flottante ruby ​​

± % sc 
Loading development environment (Rails 3.0.1) 
>> 129.95 * 100 
12994.999999999998 
>> 129.95*10 
1299.5 
>> 129.95*10*10 
12995.0 
+1

Très probablement en raison de la représentation binaire des nombres à virgule flottante. Vous ne pouvez pas écrire 129.95 en base 2, je suppose. –

+10

Lien obligatoire: [Ce que tout scientifique informatique devrait savoir à propos de l'arithmétique en virgule flottante] (http://docs.sun.com/source/806-3568/ncg_goldberg.html) –

+0

Des indices sur les raisons pour lesquelles cela ne se produirait pas pour moi? J'essaie de le démontrer, et j'entre 129.95 * 100 comme ci-dessus dans IRB et je reçois de manière inattendue la bonne réponse. – Joel

Répondre

22

Si vous faites les calculs à la main en binaire double précision, qui est limitée à 53 bits significatifs, vous verrez ce qui se passe:

129,95 = 1,0000001111100110011001100110011001100110011001100110 x 2^7

129,95 * 100 = 1.1001011000010111111111111111111111111111111111111111011 x 2^13

Ceci est de 56 bits de poids fort longtemps, alors arrondi à 53 bits, il est

1,10010110000101111111111111111111111111111111111111 11 x 2^13, ce qui équivaut à

12994,999999999998181010596454143524169921875

Maintenant 129,95 * 10 = 1.01000100110111111111111111111111111111111111111111111 x 2^10

C'est de 54 bits significatifs à long, donc arrondi à 53 bits c'est 1,01000100111 x 2^10 = 1299,5

maintenant 1299,5 * 10 = 1,1001011000011 x 2^13 = 12995.

3

Tout d'abord, vous regardez la représentation sous forme de chaîne du résultat, pas le résultat lui-même. Si vous vraiment voulez comparer les deux résultats, vous devez mettre en forme les deux résultats explicitement, en utilisant String#% et vous devriez formater les deux résultats de la même manière.

Deuxièmement, c'est ainsi que fonctionnent les nombres à virgule flottante binaires. Ils sont inexacts, ils sont finis et ils sont binaires. Tous les trois signifient que vous obtenez des erreurs d'arrondi, qui semblent généralement totalement aléatoires, sauf si vous avez mémorisé l'intégralité de IEEE754 et pouvez le réciter à l'envers dans votre sommeil.

2

Il n'y a pas de nombre à virgule flottante exactement égal à 129.95. Votre langue utilise donc une valeur proche de celle-ci. Lorsque cette valeur est multipliée par 100, le résultat est proche de 12995, mais il est égal à 12995. (Il n'est pas exactement égal à 100 fois la valeur d'origine utilisée à la place de 129.95.) Votre interprète imprime donc un nombre décimal qui est proche de (mais pas égal à) la valeur de 129.95 * 100 et qui vous montre que ce n'est pas exactement 12995. Il arrive aussi que le résultat 129.95 * 10 soit exactement égal à 1299.5. C'est surtout de la chance.

La ligne de fond est, n'attendez jamais l'égalité de toute arithmétique en virgule flottante, seulement "proximité".