I am getting 11 or 12 of 15 correct in a Python course on edX.org each time I submit, but not getting much help from anyone in the discussions because no one can really post any code there (not really helpful) and there doesn't seem to be any available support staff to speak with from the course, which I would pay for, so I am posting here. I was about to pay someone to tutor me but no one is available right now, and I am under some pressure to get this course done by December for my job.
This is the assignment:
Now write a program that calculates the minimum fixed monthly payment needed in order pay off a credit card balance within 12 months. By a fixed monthly payment, we mean a single number which does not change each month, but instead is a constant amount that will be paid each month.
In this problem, we will not be dealing with a minimum monthly payment rate.
The following variables contain values as described below:
balance - the outstanding balance on the credit card
annualInterestRate - annual interest rate as a decimal
The program should print out one line: the lowest monthly payment that will pay off all debt in under 1 year, for example:
Lowest Payment: 180
Assume that the interest is compounded monthly according to the balance at the end of the month (after the payment for that month is made). The monthly payment must be a multiple of $10 and is the same for all months. Notice that it is possible for the balance to become negative using this payment scheme, which is okay. A summary of the required math is found below:Monthly interest rate = (Annual interest rate) / 12.0
Monthly unpaid balance = (Previous balance) - (Minimum fixed monthly payment)
Updated balance each month = (Monthly unpaid balance) + (Monthly interest rate x Monthly unpaid balance)
This is my code:
#! /usr/bin/python3.6
from math import ceil
def roundup(x):
return int(ceil(x / 10.0) * 10)
def getFixedPayment(balance,annualInterestRate,counter=12):
totalLoan = balance + (balance*annualInterestRate)
monthlyPayment = roundup(totalLoan/12.0)
newBalance = totalLoan - monthlyPayment
if counter < 12:
newPayment = newBalance / counter + 1
else:
newPayment = newBalance / counter
if counter == 1:
return roundup(newPayment/12)
else:
return getFixedPayment(balance,annualInterestRate,counter-1)
#balance = 3329
#annualInterestRate = 0.2
print('Lowest Payment: ' + str(getFixedPayment(balance,annualInterestRate)))
Here are the test results: (I have here all 15, so you might be able to identify a pattern I can't see. The ones marked "ERROR" are the ones I got incorrect)
Test Case 1
balance = 3329; annualInterestRate = 0.2
Output:
Lowest Payment: 310
Test Case 2
balance = 4773; annualInterestRate = 0.2
Output:
Lowest Payment: 440
Test Case 3
balance = 3926; annualInterestRate = 0.2
Output:
Lowest Payment: 360
Randomized Test Case 1
balance = 265; annualInterestRate = 0.18
Output:
Lowest Payment: 30
Randomized Test Case 2
balance = 263; annualInterestRate = 0.18
Output:
Lowest Payment: 30
Randomized Test Case 3
balance = 317; annualInterestRate = 0.25
Output:
Lowest Payment: 30
Randomized Test Case 4
balance = 720; annualInterestRate = 0.2
Output:
Lowest Payment: 70
Randomized Test Case 5
balance = 4284; annualInterestRate = 0.2
Output:
Lowest Payment: 400
Randomized Test Case 6
balance = 3834; annualInterestRate = 0.15
Your output:
Lowest Payment: 340
*** ERROR: Expected Lowest Payment: 350
, but got Lowest Payment: 340
***
Correct output:
Lowest Payment: 350
Randomized Test Case 7
balance = 3045; annualInterestRate = 0.18
Output:
Lowest Payment: 280
Randomized Test Case 8
balance = 4461; annualInterestRate = 0.2
Output:
Lowest Payment: 410
Randomized Test Case 9
balance = 4657; annualInterestRate = 0.04
Your output:
Lowest Payment: 370
*** ERROR: Expected Lowest Payment: 400
, but got Lowest Payment: 370
***
Correct output:
Lowest Payment: 400
Randomized Test Case 10
balance = 3395; annualInterestRate = 0.2
Your output:
Lowest Payment: 320
*** ERROR: Expected Lowest Payment: 310
, but got Lowest Payment: 320
***
Correct output:
Lowest Payment: 310
Randomized Test Case 11
balance = 4045; annualInterestRate = 0.15
Your output:
Lowest Payment: 360
*** ERROR: Expected Lowest Payment: 370
, but got Lowest Payment: 360
***
Correct output:
Lowest Payment: 370
Randomized Test Case 12
balance = 3963; annualInterestRate = 0.18
Output:
Lowest Payment: 360
Although the function is recursive (it calls itself), it does so in a pointless, ineffective way.
Consider what happens for any value of the counter
when greater than 1:
def getFixedPayment(balance, annualInterestRate, counter=12): totalLoan = balance + (balance*annualInterestRate) monthlyPayment = roundup(totalLoan/12.0) newBalance = totalLoan - monthlyPayment if counter < 12: newPayment = newBalance / counter + 1 else: newPayment = newBalance / counter if counter == 1: return roundup(newPayment/12) else: return getFixedPayment(balance,annualInterestRate,counter-1) # ^^^^^^^^^ # the only change!
When counter > 1
, the function "does some calculations",
but it doesn't matter, because in the end it just calls itself with counter - 1
.
So for a starting value of counter = 12
,
the function will repeatedly call itself 11 times for nothing.
As such it reduces to this:
def getFixedPayment(balance, annualInterestRate):
totalLoan = balance + (balance*annualInterestRate)
monthlyPayment = roundup(totalLoan/12.0)
newBalance = totalLoan - monthlyPayment
newPayment = newBalance / counter + 1
return roundup(newPayment/12)
Can this possibly give correct answer? Not likely.
Consider how the repayment works. Let's take a simpler example of repaying something in 3 steps, and consider this alternative notation so it's simpler to write:
T
the total amount to pay today
r
the multiplier of the annual interest rate, that is for a 4% annual interest rate, this value will be 1.04, so we can get the amount that needs to be paid by T * r
.x
the target fixed monthly paymentAfter we pay x
this month, how much will be left to repay?
(T - x) * r
That is, we pay x
this month, the remaining amount is T - x
,
and as per the description we need to multiply with the annual interest rate.
Next month, we pay x
again, so what's left to repay will be:
((T - x) * r - x) * r
In the third month we make the last payment of x
.
The target of the exercise is to find the x
such that:
((T - x) * r - x) * r - x <= 0
Let's reorganize this equation to find the value of x
:
((T - x) * r - x) * r <= x
(T - x) * r - x <= x / r
(T - x) * r <= x / r + x
T - x <= x / r / r + x / r
T <= x / r / r + x / r + x
T <= x * (1 / r / r + 1 / r + 1)
T / (1 / r / r + 1 / r + 1) <= x
In this example we repay in 3 months. You can see how this formula changes by adding one month:
T / (1 / r / r / r + 1 / r / r + 1 / r + 1) <= x
That is, given T / m
, adding one month means T / (m / r + 1)
.
Now that looks like a recursive logic we can use.
Without completely spoiling the exercise for you,
here's a template of the solution where you just need to figure out the correct values for the ...
. Good luck!
def getFixedPayment(balance, annual_interest_rate, counter=12, interest=...):
if counter == 1:
return roundup(balance / interest)
monthly_interest_rate = annual_interest_rate / 12
r = 1 + monthly_interest_rate
return getFixedPayment(balance, annual_interest_rate, counter - 1, ...)
And here are some doctests to verify your solution.
If your program is in a file called calc.py
,
you can run the doctests with python -mdoctest calc.py
.
It will print a summary of the failing test cases if any,
or it will print nothing if all good.
def getFixedPayment(balance, annual_interest_rate, counter=12, interest=...):
"""
>>> getFixedPayment(3329, 0.2)
310
>>> getFixedPayment(4773, 0.2)
440
>>> getFixedPayment(3926, 0.2)
360
>>> getFixedPayment(265, 0.18)
30
>>> getFixedPayment(263, 0.18)
30
>>> getFixedPayment(317, 0.25)
30
>>> getFixedPayment(720, 0.2)
70
>>> getFixedPayment(4284, 0.2)
400
>>> getFixedPayment(3834, 0.15)
350
>>> getFixedPayment(3045, 0.18)
280
>>> getFixedPayment(4461, 0.2)
410
>>> getFixedPayment(4657, 0.04)
400
>>> getFixedPayment(3395, 0.2)
310
>>> getFixedPayment(4045, 0.15)
370
>>> getFixedPayment(3963, 0.18)
360
"""
if counter == 1:
return roundup(balance / interest)
monthly_interest_rate = annual_interest_rate / 12
r = 1 + monthly_interest_rate
return getFixedPayment(balance, annual_interest_rate, counter - 1, ...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With