如何防止 Ruby 货币浮点数错误
How to prevent Ruby money floating point errors
我正在使用 Rails 和货币-rails gem 来处理货币列。
有什么办法可以防止出现浮点数错误吗? (即使是 hack 也行,我只是想确保不会向最终用户显示此类错误)
Rspec 示例:
it "correctly manipulates simple money calculations" do
# Money.infinite_precision = false or true i've tried both
start_val = Money.new("1000", "EUR")
expect(start_val / 30 * 30).to eq start_val
end
结果
Failure/Error: expect(start_val / 30 * 30).to eq start_val
expected: #<Money fractional:1000.0 currency:EUR>
got: #<Money fractional:999.99999999999999999 currency:EUR>
(compared using ==)
Diff:
@@ -1,2 +1,2 @@
-#<Money fractional:1000.0 currency:EUR>
+#<Money fractional:999.99999999999999999 currency:EUR>
您应该使用小数表示金额。例如,参见 http://ruby-doc.org/stdlib-2.1.1/libdoc/bigdecimal/rdoc/BigDecimal.html。它具有任意精度算法。
编辑:在您的情况下,您可能应该将 Rspec 更改为:
it "correctly manipulates simple money calculations" do
# Money.infinite_precision = false or true i've tried both
start_val = Money.new("1000", "EUR")
thirty = BigDecimal.new("30")
expect(start_val / thirty * thirty).to eq start_val
end
EDIT2:在这种情况下,1000/30 不能表示为有限十进制数。您必须使用 Rational
class 或进行舍入。示例代码:
it "correctly manipulates simple money calculations" do
# Money.infinite_precision = false or true i've tried both
start_val = Money.new("1000", "EUR")
expect(start_val.amount.to_r / 30.to_r * 30.to_r).to eq start_val.amount.to_r
end
我正在使用 Rails 和货币-rails gem 来处理货币列。
有什么办法可以防止出现浮点数错误吗? (即使是 hack 也行,我只是想确保不会向最终用户显示此类错误)
Rspec 示例:
it "correctly manipulates simple money calculations" do
# Money.infinite_precision = false or true i've tried both
start_val = Money.new("1000", "EUR")
expect(start_val / 30 * 30).to eq start_val
end
结果
Failure/Error: expect(start_val / 30 * 30).to eq start_val
expected: #<Money fractional:1000.0 currency:EUR>
got: #<Money fractional:999.99999999999999999 currency:EUR>
(compared using ==)
Diff:
@@ -1,2 +1,2 @@
-#<Money fractional:1000.0 currency:EUR>
+#<Money fractional:999.99999999999999999 currency:EUR>
您应该使用小数表示金额。例如,参见 http://ruby-doc.org/stdlib-2.1.1/libdoc/bigdecimal/rdoc/BigDecimal.html。它具有任意精度算法。
编辑:在您的情况下,您可能应该将 Rspec 更改为:
it "correctly manipulates simple money calculations" do
# Money.infinite_precision = false or true i've tried both
start_val = Money.new("1000", "EUR")
thirty = BigDecimal.new("30")
expect(start_val / thirty * thirty).to eq start_val
end
EDIT2:在这种情况下,1000/30 不能表示为有限十进制数。您必须使用 Rational
class 或进行舍入。示例代码:
it "correctly manipulates simple money calculations" do
# Money.infinite_precision = false or true i've tried both
start_val = Money.new("1000", "EUR")
expect(start_val.amount.to_r / 30.to_r * 30.to_r).to eq start_val.amount.to_r
end