Ruby / Rails, когда цикл не работает правильно? - PullRequest
0 голосов
/ 06 октября 2011

Я работаю на сайте клиента и пишу калькулятор графика амортизации в рубине на рельсах.Для более длинных расчетов по ссуде он, кажется, не нарушается, когда баланс достигает 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, но это не так.Есть идеи, что я сделал не так?

Калькулятор здесь .Кажется, что он хорошо работает для более коротких сроков, например, 5 лет, но более длительные сроки вызывают вышеуказанную ошибку.

Редактировать:

Изменение цикла while на n.times do

изатем изменение вида баланса на

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

Обходной путь, но я хотел бы знать, почему цикл while не будет работать правильно

Ответы [ 2 ]

3 голосов
/ 06 октября 2011

в Ruby по умолчанию для числовых значений - Fixnum ... например:

> 15 / 4
 => 3 

Вы увидите странные ошибки округления, если попытаетесь использовать значения Fixnum и разделить их.

Дляубедитесь, что вы используете Float, хотя бы одно из чисел в расчете должно быть Float

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

Вы делаете два сравнения с 0, что должно быть в порядке, если вы уверены, что p является Float.

Как следует из другого ответа, для представления валюты следует использовать тип «десятичный» в вашей базе данных.

Пожалуйста, попробуйте, если это будет работать:

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
2 голосов
/ 06 октября 2011

Я думаю, что это как-то связано с точностью операций с плавающей запятой.Это уже обсуждалось здесь: Точность числа в Ruby с простой арифметикой , и было бы лучше использовать десятичный формат для финансовых целей.

Ответом может быть вычисление чисел в цикле, нос предварительно вычисленным количеством итераций и с нуля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...