Почему в Ruby не получается равенство на двух одинаковых числах? - PullRequest
5 голосов
/ 08 апреля 2010

У меня есть вычисление, которое генерирует то, что выглядит как Float 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?

Ответы [ 3 ]

9 голосов
/ 08 апреля 2010

Числа с плавающей точкой не могут точно представлять все десятичные числа в пределах их диапазона. Например, 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
6 голосов
/ 08 апреля 2010

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

1 голос
/ 08 апреля 2010

здесь происходит что-то еще. это от 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...