2015-08-25 94 views
2

我正在使用Rails的錢軌寶石處理錢列。如何防止Ruby錢浮點錯誤

有什麼辦法可以防止發生浮點錯誤嗎? (即使一個黑客會做什麼,我只是想確保沒有這樣的錯誤呈現給最終用戶)

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> 

回答

4

您應該使用小數爲金錢金額。例如見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課程或做四捨五入。示例代碼:

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 
+0

如果你看看Ruby的錢寶石源,([鏈接](https://github.com/RubyMoney/money/blob/master/lib/money/money.rb# L251)),它已經在處理金額爲BigDecimals –

+0

沒有用,加上:'1000.to_d/30.to_d * 30.to_d#=>#' –

+3

1000/30不能用十進制有限制地表示。期。使用什麼十進制數據類型並不重要,除非您使用無限內存的計算機,1000/30 *必須四捨五入。但它可以用三元表示,但是:1020.1。 –