Сравнение двух практически идентичных чисел BigDecimal в Ruby on Rails

У меня возникла небольшая проблема, которую я действительно хотел бы понять. Я использую assert_equal для сравнения двух BigDecimal чисел, которые должны быть идентичными. На самом деле они представляют собой очень маленькую крошечную фракцию, см. Ниже:

-#<BigDecimal:7f4b40e8de78,'0.4021666666 6666666666 666666667E2',36(45)>
+#<BigDecimal:7f4b40e85db8,'0.4021666666 6666666666 6666668E2',36(63)>

Я использую assert_in_delta, чтобы не провалить тестовые случаи. Так что я нашел разумное обходное решение. Я все же задаюсь вопросом, возможно ли, чтобы он был равен:

assert_equal (241.30.to_d/6), model.division_function

division_function модели делает то же самое. Он делит BigDecimal значения 241.3 на длину массива, равную 6.

Кажется, разница в точности очень мала. Я хотел бы знать, откуда это могло взяться? Есть ли способ более точно контролировать точность?

ИЗМЕНИТЬ Я использую Mongoid. Стоит отметить, что Mongoid предлагает BigDecimal в качестве типа поля, но он хранится в виде строки. Однако я не думаю, что это проблема. Я считаю, что это вещь Рубина.

РЕДАКТИРОВАТЬ. Я пошел немного дальше с примером, который намекает, что это проблема Ruby и не имеет прямого отношения к Rails. См. Ниже:

irb(main):041:0* amount1 = BigDecimal("241.3")
=> #<BigDecimal:7f49bcb03558,'0.2413E3',18(18)>
irb(main):042:0> amount2 = BigDecimal("1800")
=> #<BigDecimal:7f49bcaf3400,'0.18E4',9(18)>
irb(main):043:0> rate = amount1 / amount2
=> #<BigDecimal:7f49bcae8398,'0.1340555555 5555555555 5555556E0',27(45)>
irb(main):044:0> rate * amount2 #should return amount1 = 241.3, but it does not :-(
=> #<BigDecimal:7f49bcad6a30,'0.2413000000 0000000000 00000008E3',36(45)>
irb(main):045:0> 

person Ely    schedule 13.02.2015    source источник
comment
Вы можете выполнять математические вычисления, используя методы из класса Rational.   -  person Cary Swoveland    schedule 13.02.2015
comment
Как я упоминал в своем посте, функция Division_function просто выполняет разделение двух атрибутов так же, как первый аргумент в вызове метода assert_equal. Одно поле - BigDecimal, а другое - целочисленный размер массива. Я постараюсь привести простой пример.   -  person Ely    schedule 13.02.2015
comment
@CarySwoveland: Спасибо за подсказку. Не знал об этом. Хорошо знать. Однако я полагаюсь на BigDecimal, поскольку, к сожалению, Rational не является поддерживаемым типом данных в структуре Rails. Поэтому в данном конкретном случае я не могу использовать Rational.   -  person Ely    schedule 13.02.2015
comment
Я голосую за то, чтобы закрыть этот вопрос как не по теме, потому что это не ошибка, и ответ не помогает решить проблему.   -  person Ely    schedule 14.05.2015


Ответы (1)


Я сообщил об ошибке основной команде Ruby. Однако это не ошибка, как вы можете видеть в ответе с отказом.

BigDecimal, хотя и предлагает произвольную точность, не может представлять числа вроде 1/3 точно. Таким образом, при выполнении некоторых арифметических операций вы можете столкнуться с неточностями.

Вы можете использовать Rational в Ruby для получения точных чисел. Будьте осторожны при выполнении арифметических операций, если хотите, чтобы результат был точным.

person Ely    schedule 13.02.2015