2011-10-05 136 views
0

我正在一個客戶的網站上工作,我正在寫一個攤鋪計劃計算器在軌道上的紅寶石。對於較長的貸款期限計算,它似乎並沒有被打破,當餘額達到0Ruby/Rails while循環不正確?

這裏是我的代碼:

def calculate_amortization_results 
    p = params[:price].to_i 
    i = params[:rate].to_d 
    l = params[:term].to_i 
    j = i/(12*100) 
    n = l * 12 
    m = p * (j/(1 - (1 + j) ** (-1 * n))) 
    @loanAmount = p 
    @rateAmount = i 
    @monthlyAmount = m 
    @amort = [] 
    @interestAmount = 0 
    while p > 0 
     line = Hash.new 
     h = p*j 
     c = m-h 
     p = p-c 
     line["interest"] = h 
     line["principal"] = c 
     if p <= 0 
      line["balance"] = 0 
     else 
      line["balance"] = p 
     end 
     line["payment"] = h+c 
     @amort.push(line) 
     @interestAmount += h 
    end 
end 

這裏是視圖:

- @amort.each_with_index do |a, i| 
    %li 
     .m 
      = i+1 
     .i 
      = number_to_currency(a["interest"], :unit => "$") 
     .p 
      = number_to_currency(a["principal"], :unit => "$") 
     .pp 
      = number_to_currency(a["payment"], :unit => "$") 
     .b 
      = number_to_currency(a["balance"], :unit => "$") 

我我看到的是,代替最終付款餘額0.00美元,它顯示「 - $ - inf」,迭代一個循環,然後顯示$ 0.00,但顯示「 - $ - inf」感興趣。它應該循環,直到p變爲0,然後停止並將餘額設置爲0,但不是。任何想法我做錯了什麼?

該計算器是here。對於較短的條件(如5年)似乎工作正常,但較長的條款導致上述錯誤。

編輯:

更改while循環n.times do

,然後改變平衡以

= number_to_currency(a["balance"], :unit => "$", :negative_format => "$0.00") 

是一個解決辦法,但我想知道爲什麼while循環止跌不能正常工作

回答

3

在Ruby中的默認數值是Fixnum對象...例如: -

> 15/4 
=> 3 

你會看到奇怪的舍入誤差,如果您嘗試使用Fixnum對象的價值觀和他們分開。

爲了確保您在計算中使用花車的號碼中至少一個必須是一個浮動

> 15.0/4 
=> 3.75 
> 15/4.0 
=> 3.75 

你做兩個比較反對:0,這應該是確定的,如果你確定是p是一個浮動。

正如其他答案所示,您應該在數據庫中使用「十進制」類型來表示貨幣。

請嘗試,如果這將工作:

def calculate_amortization_results 
    p = params[:price].to_f  # instead of to_i 
    i = params[:rate].to_f  # <-- what is to_d ? use to_f 
    l = params[:term].to_i 
    j = i/(12*100.0)   # instead of 100 
    n = l * 12 
    m = p * (j/(1 - (1 + j) ** (-1 * n))) # division by zero if i==0 ==> j==0 
    @loanAmount = p 
    @rateAmount = i 
    @monthlyAmount = m 
    @amort = [] 
    @interestAmount = 0.0  # instead of 0 
    while p > 0 
     line = Hash.new 
     h = p*j 
     c = m-h 
     p = p-c 
     line["interest"] = h 
     line["principal"] = c 
     if p <= 0 
      line["balance"] = 0 
     else 
      line["balance"] = p 
     end 
     line["payment"] = h+c 
     @amort.push(line) 
     @interestAmount += h 
    end 
end 

如果你看到在輸出「INF」,會以零做除法的地方..更好地檢查你的計算邏輯,反對分裂後衛通過零。


根據維基百科的計算公式爲: http://en.wikipedia.org/wiki/Amortization_calculator

,以提高舍入誤差,它可能會更好重新構造這樣的公式:

m = (p * j)/(1 - (1 + j) ** (-1 * n) # these are two divisions! x**-1 == 1/x 

等於:

m = (p * j) + (p * j)/((1 + j) ** n) - 1.0) 

它等於:(使用這一個)

q = p * j # this is much larger than 1 , so fewer rounding errors when dividing it by something 
m = q + q/((1 + j) ** n) - 1.0) # only one division 
+0

to_d是BigDecimal,但使用浮動工作,謝謝。 – aperture

+0

不錯的看點:+1 :) – apneadiving

+0

謝謝,apneadiving :) – Tilo

2

我認爲它與浮點運算精度有關。這裏已經討論過了:Ruby number precision with simple arithmetic,爲了財務目的使用小數格式會更好。

答案可能是計算循環中的數字,但是需要預先計算迭代次數並從頭開始計算。