ошибка ruby ​​to_f или ошибка оператора умножения? - PullRequest
2 голосов
/ 24 октября 2011

Привет, я только что столкнулся с проблемой, когда функция to_f в ruby ​​дает мне противоречивые результаты.

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 

Мой обходной путь - просто округлить результат таким образом

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

После дополнительной игры я понял, что проблема может быть в операторе умножения * 100

Ответы [ 4 ]

5 голосов
/ 24 октября 2011

Добро пожаловать в дрейф с плавающей запятой.Это хорошо понимаемая проблема, и вы должны прочитать, чтобы вы, по крайней мере, поняли это сами.Например, взгляните на следующую статью:

1 голос
/ 24 октября 2011

Проблемы с Float уже упоминались. Смотрите другие ответы.

Еще несколько замечаний:

Вы написали 4.35.to_f. to_f не требуется в этом случае. 4.35 уже является Float:

p 4.35.class #-> Float

Где вы узнали проблему. Когда вы печатаете число, значение уже округлено . С помощью String #% вы можете определить уровень детализации вывода:

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"
0 голосов
/ 24 октября 2011

Основная проблема заключается в том, что дробь 45/100 не имеет точного представления в виде последовательности 1/2 n членов. Фактически, большинство фракций, написанных с небольшим количеством цифр от 10 до 10, не имеют точного представления FP.

В результате фактическое число, которое вы получаете, очень близко, но не является точным приближением к вашему числу 10. Выходные результаты будут зависеть от того, куда вы округлите, но будут правильными, если при округлении вы сделаете что-нибудь менее разумное.

Если вы не округлите, точное число, которое вы получите, будет зависеть от того, где дробь отрублена, и от того, сколько цифр вы пытаетесь преобразовать. То, где дробится дробь, будет зависеть от того, сколько битов необходимо для представления мантиссы. Вот почему вы получаете разные результаты для x .45 в зависимости от x.

Этот вопрос постоянно возникает при переполнении стека. Я думаю, нам нужен faq с плавающей точкой.

Как ни странно, каждое (в диапазоне) целочисленное значение имеет точное представление в формате с плавающей запятой.

0 голосов
/ 24 октября 2011

Увы, это часть проклятия математики с плавающей запятой, а не просто проблема в Ruby:

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

Если вам нужна точная арифметика с десятичными числами, используйте BigDecimal:

require 'bigdecimal'

(BigDecimal('4.35') * 100).to_f
  #=> 435.0 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...