我正在客户的网站上工作,我正在ruby on rails上写一个摊销计划计算器。对于较长的贷款期限计算,当余额达到0
时,它似乎没有中断这是我的代码:
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循环无法正常工作
答案 0 :(得分:3)
在Ruby中,数值的默认值是Fixnum ......例如:
> 15 / 4
=> 3
如果您尝试使用Fixnum值并将它们分开,您将看到奇怪的舍入错误。
为确保使用Floats,计算中至少有一个数字需要为Float
> 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
答案 1 :(得分:2)
我认为它与浮点运算精度有关。这里已经讨论过:Ruby number precision with simple arithmetic并且最好将十进制格式用于财务目的。
答案可能是计算循环中的数字,但是具有预先计算的迭代次数和从头开始。