在 Rails 上比较 Ruby 中两个几乎相同的 BigDecimal 数字

Comparing two virtually identical BigDecimal numbers in 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完全一样。它将值 241.3 的 BigDecimal 除以数组的长度,即 6.

精度似乎有很小的差异。 我想知道这可能来自哪里? 有什么方法可以更准确地控制精度?

编辑 我正在使用 Mongoid。值得注意的是,Mongoid 提供 BigDecimal 作为字段类型,但它存储为字符串。但是,我不认为这是问题所在。我相信这是 Ruby 事情。

编辑 我进一步举了一个例子,它暗示这是一个 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> 

我向 Ruby 核心团队报告了 bug。但是,这不是您在拒绝响应中看到的错误。

BigDecimal 虽然提供了任意精度,但不能精确表示像 1/3 这样的数字。因此,在某些算术运算中,您可能会遇到不精确的情况。

您可以在 Ruby 中使用 Rational 以获得确切的数字。如果您希望结果准确,请在进行算术运算时谨慎行事。