I am a python/programming beginner. I was assigned a problem on MIT open courseware to:
Write a program that calculates the minimum fixed monthly payment in order to pay off a credit card balance within 12 months.
Take as raw_input() the following floating point numbers:
1) the outstanding balance on the credit card
2) the annual interest rate as a decimal
Print out the fixed minimum payment, number of months(at most 12 and possibly less than 12) it takes to pay off the debt, and the balance (likely to be a negative number).
Assume the interest is compounded monthly according to the balance at the start of the month(before 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.
THE ANSWER IS:
balance = float(raw_input('Enter the outstanding balance on your credit card: '))
interest = float(raw_input('Enter the annual credit card interest rate as a decimal: '))
minPay = 10
newBalance = balance
while balance > 0:
for month in range(1,13):
newBalance = newBalance*(1+(interest/12))-minPay
if newBalance <=0:
break
if newBalance <= 0:
balance = newBalance
else:
newBalance = balance
minPay = minPay+10
print 'RESULT'
print 'Monthly payment to pay off debt in 1 year: ' + str(minPay)
print 'Number of months needed: ' + str(month)
print 'Balance: ' + str(round(balance,2))
MY QUESTIONS:
1) Using 1200 as the raw input balance, and .18 as the interest rate. Could someone explain in words how you would arrive at minPay = 120, month = 11, and balance = - 10.05?
I am confused by the newBalance = newBalance* (1 +(interest/12)) - minPay.
Using 1200 as the balance would make newBalance = 1200 * (1 +(.18/12)) - 10 = 1218 - 10 = 1208.
2) Since newBalance is not <= 0 the program would then proceed to the else statement. What is happening with the newBalance = balance part of the else statement. Does that assign newBalance back to 1200(original balance input).
I am having some trouble understanding this problem. Any insight whatsoever would be appreciated.
I would strongly recommend going through each line of the code as a python interpreter would and then seeing, why the program does perform as expected.
If you are lazy for that, try to put a print statement within the loop itself to see what the values of each variable are at every step. This always helps me figure out, what the code is doing.
As for your questions,
Yes, New balance does have the value that you expect it to have
Yes, it does get reassigned to balance, in the else part. You might want to change this.
As, I do not understand what the code is actually trying to do, I cannot help you with what the correct approach is, but try to add print statements, and it should help. Good Luck!
What is happening with the newBalance = balance part of the else statement? Does that assign newBalance back to 1200(original balance input).
Yes that's it. Then the minPay is increased and the loop starts again.
As minPay increases at each iteration, newBalance will end being negative.
balance = 3329
annualInterestRate = 0.2
minimum_fixed_payment = 10
unpaid_balance = balance
MonthlyInterestRate = annualInterestRate / 12
month_count = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
while balance > 0:
for month in month_count:
unpaid_balance = unpaid_balance - minimum_fixed_payment
interest = MonthlyInterestRate * unpaid_balance
unpaid_balance = unpaid_balance + interest
if unpaid_balance <= 0:
break
if unpaid_balance <= 0:
balance = unpaid_balance
else:
unpaid_balance = balance
minimum_fixed_payment = minimum_fixed_payment + 10
print "Lowest Payment: %s" % (minimum_fixed_payment)
The easiest way to answer this question would be to see it from this angle and that is, using the minimum fixed payment, we subtract the minimum fixed payment from the unpaid balance every month and check if the value left is lesser than 0. if it is not we increase the minimum fixed payment by 10 and repeat the process until we have a balance that is lesser than or equal to zero.
That is the modification I made to the code.
Related
My program is supposed to tell users how many months it will take to double the money in their investment account. I am able to do the calculations correctly, but I'm unable to break out of the loop and print the statement that tells the user the final sentence "It will take x months to double your investment with a y% return".
balance = int(input("Enter an initial Roth IRA deposit amount:"))
apr = int(input("Enter an annual percent rate of return:"))
month = 0
while balance != 2*balance:
added_interest = balance * (apr / 100) / 12
balance = balance + added_interest
month +=1
formatted_balance = "${:.2f}".format(balance)
print("Value after month", month,":", formatted_balance)
if balance == 2*balance:
break
print("It will take", month, "months to double your investment with a", apr, "% return")
Your problem is that testing balance against 2*balance is always testing the current balance, not double the initial balance. Just store off the computed doubled balance initially, and test if the current balance is still less than that (no need for separate if/break, your while condition will handle it):
balance = int(input("Enter an initial Roth IRA deposit amount:"))
apr = int(input("Enter an annual percent rate of return:"))
month = 0
doubled_balance = 2 * balance # Store off doubled initial balance
while balance < doubled_balance: # Check current balance against doubled initial,
# and use <, not !=, so you stop when you exceed it,
# not just when you're exactly equal
added_interest = balance * (apr / 100) / 12
balance = balance + added_interest
month +=1
formatted_balance = "${:.2f}".format(balance)
print("Value after month", month,":", formatted_balance)
# No need for if/break
print("It will take", month, "months to double your investment with a", apr, "% return")
All that said, this doesn't need a loop at all. The initial balance doesn't matter (it takes just as long to double $1 as to double $1000 with a fixed rate of return, ignoring rounding errors), so this reduces to a simple conversion for APR to APY to account for monthly compounding, followed by a logarithm computation to figure out what power of the APY is necessary to reach 2 (a doubling), then convert from months to years and round up (since you won't double until the end of that month):
import math
apr = int(input("Enter an annual percent rate of return:"))
apr_decimal = apr / 100
apy = (1 + (apr_decimal / 12)) ** 12 # Standard APR to APY computation for monthly compounding
months = math.ceil(math.log(2, apy) * 12) # Compute the power (years) of APY to double the investment
# then multiply by 12 and round up to a full month
print("It will take", months, "months to double your investment with a", apr, "% return")
In your comparison you compared balance with 2*balance. Obviously balance == 2*balance will always be false, if balance > 0. So your code is stuck there forever if someone plans to invest anything more than $0.
You need a new variable to store the updated balance with rate of return:
# assuming you have balance and apr set
newBalance = balance # balance + returned amount
month = 0
while newBalance < 2*balance:
# replace ! with <, so that loop breaks when newBalance >= 2*balance
added_interest = newBalance * (apr / 100) / 12
newBalance = newBalance + added_interest
month +=1
formatted_balance = "${:.2f}".format(newBalance)
print("Value after month", month,":", formatted_balance)
The code above assumes that the added interest is calculated based on newBalance value. Please tell me if this does not work for you. I will debug it later.
Perhaps a little bit simpler solution.
from math import log, ceil
apr = int(input("Enter an annual percent rate of return: "))
rate = apr/12/100 # monthly rate
months = ceil(log(2)/rate)
print("It will take", months, "months to double your investment with a", apr, "% return")
prints:
Enter an annual percent rate of return: 10
It will take 84 months to double your investment with a 10 % return
This was calculated using the formula for continuous compounding. With a FV (future value) = PV (present value) * e**(rate * periods).
FV = PV * e**(rate*periods)
FV/PV = e**(rate*periods)
log(FV/PV) = log(e**(rate*periods))
log(FV/PV) = (rate*periods) * log(e)
log(FV/PV) = (rate*periods) * 1
log(FV/PV)/rate = periods
Since you want to find the months to double your initial investment, FV/PV will equal 2, so:
log(2)/rate = periods. (The log(e) == 1 above)
e and compound interest is defined here.
My homework problem: Find the smallest monthly payment required pay off a given loan principal within a year. One-twelfth of the original balance is a good lower bound; a good upper bound is one-twelfth of the balance, after having its interest compounded monthly for an entire year.
In short:
Monthly interest rate = (Annual interest rate) / 12.0
Monthly payment lower bound = Balance / 12
Monthly payment upper bound = (Balance * (1 + Monthly interest rate)**12) / 12.0
I have to write a bisection search to find that smallest monthly payment to the cent.
Every time I run this code I get the lowest payment to be a value a couple hundred off from the correct solution.
balance = 414866
annualInterestRate = 0.22
month = 0
monthlyinterest = (annualInterestRate) / 12.0
updatedbalance = balance
monlowbound = balance / 12
monupbound = (balance * (1 + monthlyinterest)**12) / 12.0
mid = (monlowbound + monupbound) /2
minpay = 0
while balance > 0 and month <= 12:
balance = updatedbalance
updatedbalance = ((monthlyinterest * balance) + balance) - minpay
month += 1
if updatedbalance > 0:
minpay = (mid + monupbound)/2
mid = monlowbound
if updatedbalance < 0:
minpay = (monlowbound + mid)/2
monupbound = mid
else:
print("Lowest payment:" + " " + str(round(minpay,2)))
This is what I get as the output:
Lowest payment: 40888.41
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
Lowest payment: 38783.0
The major problem is that you apply your feedback adjustment logic (adjusting the monthly payment) every month. You need to wait until the end of the year, and then adjust the payment. All of that should be wrapped inside a while loop that continues until you get "close enough" ... say, within a full penny of the previous payment. Something like this:
last_pay = -1000 # Ridiculous value to start the process
while abs(last_pay - minpay) > 0.01:
# use your current logic for paying off one year, including
...
for month in range(12):
....
# HERE is where you check the final balance
# to see whether you're high or low.
# Then adjust your monthly payment (minpay)
Does this get you going?
Your algorithm does not work.
What you want is :
A function f that gives you the final balance for any fixed payment
An algorithm to find the root of this function, i.e. the monthly fixed payment that needs to be paid for the final balance to be as close as zero as possible. With a given f function, a recursive approach would be something like :
You seem to be doing both at the same time, i.e. you change your "mid" value while you're still computing. I suggest you write down your algorithm before you try to code it to realize the flow you probably want :
def finalbalance(fixedpayment):
#code that determines the balance status
def solvebisection(lowbound,highbound,function=finalbalance,tofind=0):
#Recursive coding to "find the root"
This is a module in part of a larger "vending machine" I am working on. I have ran into some issues, though. If they do not pay enough ($1.75) they are asked to enter an additional amount of money. Part of my problem is that I don't know what operations I should do to change the deficit inside of a loop. All of the things I've tried has resulted in errors like "input expected at most 1 arguments, got 3" and so forth.
selection = 5
loopCount = 0
deposit = 0
cost = 1.75
print("It costs $",cost,".")
deposit = float(input("Enter your money amount (e.g. 1.5 for $1.50, .50 for $0.50, etc.):\n--\n"))
deficit = cost - deposit
change = deposit - cost
if deposit < cost:
while deficit > 0 and loopCount < 1:
??? = float(input("Please enter an additional $",deficit,"."))
loopCount += 1
if deposit >= cost:
print("Thank you for purchasing item#",selection,". Your change is $",change,".")
This works for me. Do make sure to increase the loopCount, as right now, it will not loop more than once.
selection = 5
loopCount = 0
deposit = 0
cost = 1.75
print("It costs $",cost,".")
deposit = float(input("Enter your money amount (e.g. 1.5 for $1.50, .50 for $0.50, etc.):\n--\n"))
deficit = cost - deposit
change = deposit - cost
if deposit < cost:
while deficit > 0 and loopCount < 1:
deficit -= float(input("Please enter an additional ${}.".format(deficit)))
loopCount += 1
if deposit >= cost:
print("Thank you for purchasing item#",selection,". Your change is $",change,".")
Assuming you don't want to break from the loop until they pay enough money you could do this:
while abs(deficit) < cost:
added = float(input("Please enter an additional $",deficit,"."))
deficit = cost - deposit - added
The abs function will output the absolute value so you can compare it directly to cost.
Somethings to note though, you might want to do error checking on your inputs.
Also, if you do want to be able provide a mechanism for the user to break from the loop, you could add a boolean true or false (instead of loop count) that is attached to some other input like "Do you want to insert more money? y or n"
I am currently participating in a free online course through MIT OCW. I was given a certain problem and I am trying to understand the solution. I am not sure what the "2" is doing. it is the two in the (minMonthlyPaymentRate * balance, 2) Here is the solution:
# 6.00 PS1-A Solution
# Determines remaining credit card balance after a year of making the minimum payment each month
balance = float(raw_input("Enter the outstanding balance on your credit card: "))
annualInterestRate = float(raw_input("Enter the annual credit card interest rate as a decimal: "))
minMonthlyPaymentRate = float(raw_input("Enter the minimum monthly payment rate as a decimal: "))
# Monthly Interest Rate
monthlyInterestRate = annualInterestRate/12
# Initialize state variables
numMonths = 1
totalAmtPaid = 0
while numMonths <= 12:
# Minimum monthly payment of balance at start of the month
minPayment = round(minMonthlyPaymentRate * balance,2)**This Two!?**
totalAmtPaid += minPayment
# Amt of monthly payment that goes to interest
interestPaid = round(monthlyInterestRate * balance,2)
# Amt of principal paid off
principalPaid = minPayment - interestPaid
# Subtract monthly payment from outstanding balance
balance -= principalPaid
print "Month:", numMonths
print "Minimum monthly payment:", minPayment
print "Remaining balance:", balance
# Count this as a new month
numMonths += 1
print "RESULT"
print "Total amount paid:",totalAmtPaid
print "Remaining balance:",balance
round() which rounds off to the given number of digits and returns the floating point number.
Example code:
val=2.665
print(round(val, 2);
output:
6.67
As seen in the python documentation of the function round() it states "rounded to ndigits digits after the decimal point". So it means the result will be rounded to two digits after the decimal point.
One picture is worth a thousand words.
Suppose you have an investment plan where you invest a certain fixed amount at the beginning of every year. Compute the total value of the investment at the end of the last year. The inputs will be the amount to invest each year, the interest rate, and the number of years of the investment.
This program calculates the future value
of a constant yearly investment.
Enter the yearly investment: 200
Enter the annual interest rate: .06
Enter the number of years: 12
The value in 12 years is: 3576.427533818945
I've tried a few different things, like below, but it doesn't give me that 3576.42, it gives me only $400. Any ideas?
principal = eval(input("Enter the yearly investment: "))
apr = eval(input("Enter the annual interest rate: "))
years = eval(input("Enter the number of years: "))
for i in range(years):
principal = principal * (1+apr)
print("The value in 12 years is: ", principal)
If it's a yearly investment, you should add it every year:
yearly = float(input("Enter the yearly investment: "))
apr = float(input("Enter the annual interest rate: "))
years = int(input("Enter the number of years: "))
total = 0
for i in range(years):
total += yearly
total *= 1 + apr
print("The value in 12 years is: ", total)
With your inputs, this outputs
('The value in 12 years is: ', 3576.427533818945)
Update: Responding to your questions from the comments, to clarify what's going on:
1) You can use int() for yearly and get the same answer, which is fine if you always invest a whole number of currency. Using a float works just as well but also allows the amount to be 199.99, for example.
2) += and *= are convenient shorthand: total += yearly means total = total + yearly. It's a little easier to type, but more important, it more clearly expresses the meaning. I read it like this
for i in range(years): # For each year
total += yearly # Grow the total by adding the yearly investment to it
total *= 1 + apr # Grow the total by multiplying it by (1 + apr)
The longer form just isn't as clear:
for i in range(years): # For each year
total = total + yearly # Add total and yearly and assign that to total
total = total * (1 + apr) # Multiply total by (1 + apr) and assign that to total
It can be done analytically:
"""
pmt = investment per period
r = interest rate per period
n = number of periods
v0 = initial value
"""
fv = lambda pmt, r, n, v0=0: pmt * ((1.0+r)**n-1)/r + v0*(1+r)**n
fv(200, 0.09, 10, 2000)
Similarly, if you are trying to figure out the amount you need to invest so you get to a certain number, you can do:
pmt = lambda fv, r, n, v0=0: (fv - v0*(1+r)**n) * r/((1.0+r)**n-1)
pmt(1000000, 0.09, 20, 0)
As suggested in the comments, you shouldn't use eval() here. (More info on eval can be found in the Python Docs). -- Instead, change your code to use float() or int() where applicable, as shown below.
Also, your print() statement printed out the parenthesis and comma, which I expect you didn't want. I cleaned it up in the code below, but if what you wanted is what you had feel free to put it back.
principal = float(input("Enter the yearly investment: "))
apr = float(input("Enter the annual interest rate: "))
# Note that years has to be int() because of range()
years = int(input("Enter the number of years: "))
for i in range(years):
principal = principal * (1+apr)
print "The value in 12 years is: %f" % principal