Почему Ruby привел бы равенство к сбою на 2 плаваниях, которые появляются то же?

У меня есть вычисление, которое генерирует то, что, кажется, Плавание 22.23 и литеральные 22.23 как так:

some_object.total => 22.23
some_object.total.class => Float

22.23 => 22.23
22.23.class => Float

Но по некоторым причинам, следующее является ложью:

some_object.total == 22.23 ? true : false

Дурацкий, правильно?

Там некоторый механизм точности использует, который, возможно, не абсолютно прозрачен через вызов some_object.total?

5
задан btelles 7 April 2010 в 20:26
поделиться

3 ответа

Числа с плавающей запятой не могут точно представить все десятичные числа в пределах их диапазона. Например, 0,9 - это не совсем 0,9, это число, действительно близкое к 0,9, которое в итоге печатается так же, как и в большинстве случаев. По мере того, как вы выполняете вычисления с плавающей запятой, эти ошибки могут накапливаться, и вы получите что-то очень близкое к правильному, но не совсем равное ему. Например, 0,3 * 3 == 0,9 вернет false . Так обстоит дело с каждым компьютерным языком, который вы когда-либо будете использовать - именно так работает двоичная математика с плавающей запятой. См., Например, этот вопрос о Haskell .

Чтобы проверить равенство с плавающей запятой, вы обычно хотите проверить, находится ли число в каком-то крошечном диапазоне от целевого значения. Так, например:

def float_equal(a, b)
  if a + 0.00001 > b and a - 0.00001 < b
    true
  else
    false
  end
end

Вы также можете использовать класс BigDecimal в Ruby для представления произвольных десятичных чисел.

Если это тестовый пример, вы можете использовать assert_in_delta :

def test_some_object_total_is_calculated_correctly
  assert_in_delta 22.23, some_object.total, 0.01
end
9
ответ дан 18 December 2019 в 10:43
поделиться

Float # to_s и Float # inspect раунд. Попробуйте "%. 30f"% some_object.total , и вы увидите, что это не совсем 22.23.

6
ответ дан 18 December 2019 в 10:43
поделиться

здесь происходит что-то еще. это из 1.8.7 irb

irb(main):001:0> class Test
irb(main):002:1> attr_accessor :thing
irb(main):003:1> end
=> nil
irb(main):004:0> t = Test.new
=> #<Test:0x480ab78>
irb(main):005:0> t.thing = 22.5
=> 22.5
irb(main):006:0> t.thing == 22.5
=> true
1
ответ дан 18 December 2019 в 10:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: