Skip to content

Instantly share code, notes, and snippets.

@damonvjanis
Created October 17, 2018 19:12
Show Gist options
  • Save damonvjanis/917c524cd70beeedac27cb558feefb88 to your computer and use it in GitHub Desktop.
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
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