2 votes

bug de ruby to_f ou bug de l'opérateur de multiplication ?

Bonjour, je viens de rencontrer un problème où la fonction de ruby to_f me donne des résultats incohérents.

ruby-1.9.2-head :026 > 8.45.to_f * 100
 => 844.9999999999999 

ruby-1.9.2-head :027 > 4.45.to_f * 100
 => 445.0 

ruby-1.9.2-head :028 > 4.35.to_f * 100
 => 434.99999999999994 

Ma solution est d'arrondir le résultat de la façon suivante

ruby-1.9.2-head :029 > (4.35.to_f * 100).round
 => 435 

Après avoir joué un peu plus, je me suis rendu compte que le problème pouvait provenir de l'opérateur de multiplication. * 100

6voto

jer Points 15036

Bienvenue dans la dérive de la virgule flottante. Il s'agit d'un problème bien compris, et vous devriez le lire pour au moins le comprendre vous-même. Par exemple, jetez un coup d'œil à l'article suivant :

1voto

knut Points 10107

Les problèmes avec Float sont déjà mentionnés. Consultez les autres réponses.

Quelques remarques supplémentaires :

Vous avez écrit 4.35.to_f . Le site to_f n'est pas nécessaire dans ce cas. 4,35 est déjà une valeur flottante :

p 4.35.class #-> Float

Où avez-vous reconnu le problème. Quand vous imprimez le nombre, la valeur est déjà arrondi . Avec String#%, vous pouvez déterminer le niveau de détail de la sortie :

p 8.45.to_f * 100 #->845.0
p "%.12f" % (8.45.to_f * 100) # -> "845.000000000000"
p "%.13f" % (8.45.to_f * 100) # -> "844.9999999999999"
p "%.14f" % (8.45.to_f * 100) # -> "844.99999999999989"
p "%.16f" % (8.45.to_f * 100) # -> "844.9999999999998900"

0voto

Alex Peattie Points 8754

Hélas, cela fait partie de la malédiction des mathématiques à virgule flottante, et ce n'est pas seulement un problème en Ruby :

http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding

Si vous avez besoin d'une arithmétique exacte avec des décimales, utilisez BigDecimal :

require 'bigdecimal'

(BigDecimal('4.35') * 100).to_f
  #=> 435.0

0voto

DigitalRoss Points 80400

Le problème fondamental est que la fraction 45/100 n'a pas de représentation exacte comme une séquence de 1/2 n termes. En effet, le plus Les fractions écrites avec un petit nombre de chiffres en base 10 n'ont pas une représentation FP exacte.

Par conséquent, le nombre réel que vous obtenez est une approximation très proche mais non exacte de votre nombre en base 10. Les résultats de sortie dépendront de l'arrondi, mais seront corrects si vous faites tout ce qui est un tant soit peu raisonnable lors de l'arrondi.

Si vous n'arrondissez pas, le nombre exact que vous obtiendrez dépendra de l'endroit où la fraction sera coupée et du nombre de chiffres que vous tenterez de convertir. L'endroit où la fraction est coupée dépend du nombre de bits nécessaires pour représenter la mantisse. C'est pourquoi vous obtenez des résultats différents pour x .45 selon x.

Cette question revient tout le temps sur stack overflow. Je suppose que nous avons besoin d'une FAQ sur les points flottants.

Ironiquement, chaque valeur entière (dans l'intervalle) fait ont une représentation exacte en format à virgule flottante.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X