Created
October 17, 2018 19:12
-
-
Save damonvjanis/917c524cd70beeedac27cb558feefb88 to your computer and use it in GitHub Desktop.
Elixir function to calculate APR (Annual Percentage Rate) on a simple installment loan
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule APR do | |
@moduledoc """ | |
This module has a single function, `calc_apr`, for calculating an APR on a simple installment loan. | |
This code was a conversion of a Groovy implementation of the algorithim in this answer on Stack Overflow: https://stackoverflow.com/a/3190428/7223229 | |
""" | |
@doc """ | |
Takes three arguments: the number of payments (in months), monthly payments, and the amount being financed not including interest. | |
## Examples | |
iex> calc_apr(11, 1325 / 11, 975) | |
65.94841323032557 | |
In the example, the loan lasts 11 months, the total amount of the loan is 1325, and the finance charge is 350 so the last argument is 1325 - 350 = 975. | |
The margin of error is 1.0e-5, the inital guess is an APR of 1%, and the output is in percentage format. | |
The output of the example is 65.95% APR. | |
""" | |
def calc_apr(num_pay, payment, amount) do | |
error = :math.pow(10, -5) | |
guess = 0.01 / 12 | |
approx = do_calc_apr(num_pay, payment, amount, error, guess, 0) | |
approx * 12 * 100 | |
end | |
defp do_calc_apr(_num_pay, _payment, _amount, _error, prev_approx, 20) do | |
prev_approx | |
end | |
defp do_calc_apr(num_pay, payment, amount, error, prev_approx, counter) do | |
f_result = f(prev_approx, amount, num_pay, payment) | |
f_1_result = f_1(prev_approx, amount, num_pay) | |
approx = prev_approx - f_result / f_1_result | |
diff = abs(approx - prev_approx) | |
case diff < error do | |
true -> approx | |
false -> do_calc_apr(num_pay, payment, amount, error, approx, counter + 1) | |
end | |
end | |
defp f(x, amount, num_pay, payment) do | |
amount * x * :math.pow(1 + x, num_pay) / (:math.pow(1 + x, num_pay) - 1) - payment | |
end | |
defp f_1(x, amount, num_pay) do | |
amount * | |
(:math.pow(1 + x, num_pay) / (-1 + :math.pow(1 + x, num_pay)) - | |
num_pay * x * :math.pow(1 + x, -1 + 2 * num_pay) / | |
:math.pow(-1 + :math.pow(1 + x, num_pay), 2) + | |
num_pay * x * :math.pow(1 + x, -1 + num_pay) / (-1 + :math.pow(1 + x, num_pay))) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment