Last active
December 14, 2015 06:29
-
-
Save lukeredpath/5043351 to your computer and use it in GitHub Desktop.
Find the lowest possible monthly payment to pay off balance in full with compound interest, recursive solution.
This file contains hidden or 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
EPISILON = 0.01 # calculate to the nearest cent | |
def calculate_balance_remaining_after_year(starting_balance, monthly_payment, annual_interest_rate) | |
12.times.reduce(starting_balance) do |balance| | |
balance -= monthly_payment | |
balance += (annual_interest_rate / 12) * balance | |
end | |
end | |
def calculate_lowest_payment_within_bounds(starting_balance, annual_interest_rate, lower_bound, upper_bound) | |
median_payment = (lower_bound + upper_bound) / 2.0 | |
balance = calculate_balance_remaining_after_year(starting_balance, median_payment, annual_interest_rate) | |
if balance > EPISILON | |
calculate_lowest_payment_within_bounds(starting_balance, annual_interest_rate, median_payment, upper_bound) | |
elsif balance < -EPISILON | |
calculate_lowest_payment_within_bounds(starting_balance, annual_interest_rate, lower_bound, median_payment) | |
else | |
median_payment | |
end | |
end | |
def find_lowest_monthly_payment(starting_balance, annual_interest_rate) | |
minimum_monthly_payment = starting_balance / 12.0 | |
maximum_monthly_payment = calculate_balance_remaining_after_year(starting_balance, 0, annual_interest_rate) / 12.0 | |
calculate_lowest_payment_within_bounds( | |
starting_balance, annual_interest_rate, minimum_monthly_payment, maximum_monthly_payment | |
) | |
end | |
if __FILE__ == $0 # this just means run this block if we run the file directly | |
require 'test/unit' | |
class BalanceCalculatorTest < Test::Unit::TestCase | |
def test_equal_monthly_payments_with_no_interest | |
balance = calculate_balance_remaining_after_year(1200.0, 100.0, 0) | |
assert_equal 0, balance | |
end | |
def test_no_monthly_payments_with_no_interest | |
balance = calculate_balance_remaining_after_year(1200.0, 0, 0) | |
assert_equal 1200.0, balance | |
end | |
def test_no_monthly_payments_with_interest | |
balance = calculate_balance_remaining_after_year(1200.0, 0, 0.12) | |
assert_in_delta 1352.19, balance, 0.01 | |
end | |
def test_equal_monthly_payments_with_interest | |
balance = calculate_balance_remaining_after_year(1200.0, 100.0, 0.12) | |
assert_in_delta 71.26, balance, 0.01 | |
end | |
def test_overpayment_with_no_interest | |
balance = calculate_balance_remaining_after_year(1200.0, 110.0, 0) | |
assert_equal -120.0, balance | |
end | |
def test_calculated_lowest_monthly_payment_actually_pays_off_balance_in_full_to_nearest_cent | |
starting_balance = 1200.0 | |
interest_rate = 0.12 | |
lowest_monthly_payment = find_lowest_monthly_payment(starting_balance, interest_rate) | |
balance = calculate_balance_remaining_after_year(starting_balance, lowest_monthly_payment, interest_rate) | |
assert_in_delta 0, balance, 0.01 | |
end | |
def test_calculated_lowest_monthly_payment_for_large_values | |
starting_balance = 320000.0 | |
interest_rate = 0.2 | |
lowest_monthly_payment = find_lowest_monthly_payment(starting_balance, interest_rate) | |
balance = calculate_balance_remaining_after_year(starting_balance, lowest_monthly_payment, interest_rate) | |
assert_in_delta 0, balance, 0.01 | |
end | |
def test_calculated_lowest_monthly_payment_for_katies_inputs_matches_python_result | |
starting_balance = 320000.0 | |
interest_rate = 0.2 | |
lowest_monthly_payment = find_lowest_monthly_payment(starting_balance, interest_rate) | |
balance = calculate_balance_remaining_after_year(starting_balance, lowest_monthly_payment, interest_rate) | |
assert_in_delta 0, balance, 0.01 | |
assert_in_delta 29157.09, lowest_monthly_payment, 0.01 | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment