How to prevent Ruby money floating point errors

微笑、不失礼 提交于 2019-12-11 03:36:58

问题


I'm using Rails with the money-rails gem to handle money columns.

Is there any way to prevent floating point errors from occuring? (even a hack will do, I just want to make sure no such errors are presented to the end user)

Rspec example case:

  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

Result

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>

回答1:


You should use decimals for money amounts. See http://ruby-doc.org/stdlib-2.1.1/libdoc/bigdecimal/rdoc/BigDecimal.html for instance. It has arbitrary precision arithmetic.

EDIT: In your case you should probably change your Rspec to something like:

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: in this very case 1000/30 cannot be represented as a finite decimal number. You have to either use Rational class or do rounding. Example code:

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


来源:https://stackoverflow.com/questions/32201861/how-to-prevent-ruby-money-floating-point-errors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!