Подтвердить что ты не робот

Почему мои объекты BigDecimal инициализируются неожиданными ошибками округления?

В Ruby 2.2.0 почему:

BigDecimal.new(34.13985572755337, 9)

равно 34.0, но

BigDecimal.new(34.13985572755338, 9)

равно 34.1398557?

Обратите внимание, что я запускаю это на 64-битной машине.

4b9b3361

Ответ 1

Инициализировать с помощью строк вместо плавающих

В общем, вы не можете получить надежное поведение с помощью Floats. Вы делаете ошибку, инициализируя свои BigDecimals значениями Float вместо значений String, что в начале вводит некоторую неточность. Например, на моей 64-битной системе:

float1 = 34.13985572755337
float2 = 34.13985572755338

# You can use string literals here, too, if your Float can't be properly
# represented. For example:
#
#    BigDecimal.new("34.13985572755337", 9)
#
# would be safer, but Float#to_s works fine with the provided corpus.
bd1 = BigDecimal.new(float1.to_s, 9)
bd2 = BigDecimal.new(float2.to_s, 9)

bd1.to_s
#=> "0.3413985572755337E2"
bd2.to_s
#=> "0.3413985572755338E2"

bd1.to_f == float1
#=> true
bd2.to_f == float2
#=> true

Это один из тех случаев, когда внутреннее представление аргументов имеет значение. Поэтому ваш пробег будет зависеть от того, как вы инициализируете свой объект.