如何防止Ruby钱浮点错误

Spy*_*kis 2 ruby currency ruby-on-rails money-rails

我正在使用带有money-rails gem的Rails来处理钱列.

有没有办法防止出现浮点错误?(即使是黑客也会这样做,我只是想确保没有这样的错误呈现给最终用户)

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
Run Code Online (Sandbox Code Playgroud)

结果

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>
Run Code Online (Sandbox Code Playgroud)

Dan*_*nov 5

你应该使用小数来赚钱.例如,请参见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
Run Code Online (Sandbox Code Playgroud)

EDIT2:在这种情况下,1000/30不能表示为有限的十进制数.您必须使用Rational课程或进行四舍五入.示例代码:

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
Run Code Online (Sandbox Code Playgroud)

  • 1000/30不能以十进制有限地表示.期.使用十进制数据类型并不重要,除非您使用具有无限内存的计算机,1000/30*必须*舍入.它*可以*以三元表示,但是:1020.1. (3认同)