Following is the problem set from MIT opencourseware
Part C: Finding the right amount to save away
Your semiannual raise is .07 (7%)
Your investments have an annual return of 0.04 (4%)
The down payment is 0.25 (25%) of the cost of the house
The cost of the house that you are saving for is $1M.
I am now going to try to find the best rate of savings to achieve a down payment on a $1M house in 36 months. And I want your savings to be within $100 of the required down payment.I am stuck with the bisection search and 'It is not possible to pay the down payment in three years.' this output. I am new to programmers and English.Any help is appreciated.
And here is my code:
starting_salary = float(input("Enter your starting salary: "))
months_salary = starting_salary/12
total_cost = 1000000.0
semi_annual_rate = .07
investment_return = 0.04
down_payment = total_cost * 0.25
r = 0.04
current_savings = 0.0
#months = 36
tolerance = 100
steps = 0
high = 1.0
low = 0.0
guess = (high+low)/2.0
total_salaries = 0.0
def calSavings(current_savings,months_salary,guess,month):
for months in range(0,37):
if months%6==1 and months >1:
months_salary=months_salary*(1+semi_annual_rate)
current_savings = current_savings + months_salary * guess
current_savings = current_savings * (1+0.04/12)
return(current_savings)
current_savings = calSavings(current_savings,months_salary,guess,1)
while abs(current_savings-down_payment)>=100:
if current_savings < down_payment:
low = guess
elif current_savings > down_payment:
high = guess
else:
print("It is not possible to pay the down payment in three years.")
break
guess = (low+high)/2
steps = steps +1
print("Best saving rate: ", guess)
When I run this code, it will be stuck. I don't know why.
And I don't know how to determine which is the condition of output this "It is not possible to pay the down payment in three years."
I have seen Similar questions on stackoverflow like this and this but I am not quite followed.
# user input
annual_salary = float(input('Enter your annual salary: '))
semi_annual_raise = 0.07
r = 0.04
portion_down_payment = 0.25
total_cost = 1000000
steps = 0
current_savings = 0
low = 0
high = 10000
guess_rate = (high + low)//2
# Use a while loop since we check UNTIL something happens.
while abs(current_savings - total_cost*portion_down_payment) >= 100:
# Reset current_savings at the beginning of the loop
current_savings = 0
# Create a new variable for use within the for loop.
for_annual_salary = annual_salary
# convert guess_rate into a float
rate = guess_rate/10000
# Since we have a finite number of months, use a for loop to calculate
# amount saved in that time.`enter code here`
for month in range(36):
# With indexing starting a zero, we need to calculate at the beginning
# of the loop.
if month % 6 == 0 and month > 0:
for_annual_salary += for_annual_salary*semi_annual_raise
# Set monthly_salary inside loop where annual_salary is modified
monthly_salary = for_annual_salary/12
# Calculate current savings
current_savings += monthly_salary*rate+current_savings*r/12
# The statement that makes this a bisection search
if current_savings < total_cost*portion_down_payment:
low = guess_rate
else:
high = guess_rate
guess_rate = (high + low)//2
steps += 1
# The max amount of guesses needed is log base 2 of 10000 which is slightly
# above 13. Once it gets to the 14th guess it breaks out of the while loop.
if steps > 13:
break
# output
if steps > 13:
print('It is not possible to pay the down payment in three years.')
else:
print('Best savings rate:', rate)
print('Steps in bisection search:', steps)
I've already addressed most of my points in the comments, but I will recap:
You are trying to solve a problem using a method called recursive solving, in this case using the bisection method.
The steps are as follows:
start with an initial guess you chose 0.5
Perform your calculations in a loop and iterate the initial guess, in this case you must account for the following:
Maximum number of steps before failure, remember we can always add 2 values and divide by 2, your result will tend to 0.999999.. otherwise
A certain tolerance, if your step size is not small enough 25% of 1 M is 250 000 and you might never hit that number exactly, that' why you make a tolerance interval, for example: anything between 250 000 and 251 000 --> break loop, show result.
Your if statements for changing low and high to adjust guess are correct, but you forget to re-initialize savings to 0 which means savings was going to infinity.
Now that's all said, here's a working version of your code:
starting_salary = 100000 # Assuming Annual Salary of 100k
months_salary = starting_salary/12
total_cost = 1000000.0
semi_annual_rate = .07
investment_return = 0.04
down_payment = total_cost * 0.25
print("down payment: ", down_payment)
r = 0.04
current_savings = 0.0
#months = 36
tolerance = 100
steps = 0
high = 1.0
low = 0.0
guess = (high+low)/2.0
total_salaries = 0.0
tolerance = down_payment/100 # I chose this tolerance to say if my savings are between [down_payment - (downpayment + down_payment/100)] result is admissible. (this is quite a high tolerance but you can change at leisure)
def calSavings(current_savings,months_salary,guess,month):
for months in range(0,37):
if months%6==1 and months >1:
months_salary=months_salary*(1+semi_annual_rate)
current_savings = current_savings + months_salary * guess
current_savings = current_savings * (1+0.04)
return(current_savings)
while abs(current_savings-down_payment)>=100:
current_savings = calSavings(current_savings,months_salary,guess,1)
if current_savings < down_payment:
low = guess
current_savings = 0.
elif current_savings > down_payment + tolerance:
high = guess
current_savings = 0.
if (steps > 100): # I chose a maximum step number of 100 because my tolerance is high
print("It is not possible to pay the down payment in three years.")
break
guess = (low+high)/2
steps = steps +1
print("Best saving rate: ", guess)
print("With current savings: ", current_savings)
Output:
down payment: 250000.0
Best saving rate: 0.656982421875
With current savings: 250072.3339667072
[Finished in 0.08s]
For answer visit the GitHub link - MIT has added Problem set solutions
Part C: Finding the right amount to save away
In Part B, you had a chance to explore how both the percentage of your salary that you save each month and your annual raise affect how long it takes you to save for a down payment. This is nice, but suppose you want to set a particular goal, e.g. to be able to afford the down payment in three years. How much should you save each month to achieve this? In this problem, you are going to write a program to answer that question. To simplify things, assume:
Your semiannual raise is .07 (7%)
Your investments have an annual return of 0.04 (4%)
The down payment is 0.25 (25%) of the cost of the house
The cost of the house that you are saving for is $1M.
You are now going to try to find the best rate of savings to achieve a down payment on a $1M house in 36 months. Since hitting this exactly is a challenge, we simply want your savings to be within $100 of the required down payment.
In ps1c.py, write a program to calculate the best savings rate, as a function of your starting salary.
You should use bisection search to help you do this efficiently. You should keep track of the number of steps it takes your bisections search to finish. You should be able to reuse some of the code you wrote for part B in this problem.
Because we are searching for a value that is in principle a float, we are going to limit ourselves to two decimals of accuracy (i.e., we may want to save at 7.04% or 0.0704 in decimal – but we are not going to worry about the difference between 7.041% and 7.039%). This means we can search for an integer between 0 and 10000 (using integer division), and then convert it to a decimal percentage (using float division) to use when we are calculating the current_savings after 36 months. By using this range, there are only a finite number of numbers that we are searching over, as opposed to the infinite number of decimals between 0 and 1. This range will help prevent infinite loops. The reason we use 0 to 10000 is to account for two additional decimal places in the range 0% to 100%. Your code should print out a decimal (e.g. 0.0704 for 7.04%).
Try different inputs for your starting salary, and see how the percentage you need to save changes to reach your desired down payment. Also keep in mind it may not be possible for to save a down payment in a year and a half for some salaries. In this case your function should notify the user that it is not possible to save for the down payment in 36 months with a print statement. Please make your program print results in the format shown in the test cases below.
Note: There are multiple right ways to implement bisection search/number of steps so your results may not perfectly match those of the test case.
Hints:
● There may be multiple savings rates that yield a savings amount that is within $100 of the required down payment on a $1M house. In this case, you can just return any of the possible values.
● Depending on your stopping condition and how you compute a trial value for bisection search, your number of steps may vary slightly from the example test cases.
● Watch out for integer division when calculating if a percentage saved is appropriate and when calculating final decimal percentage savings rate.
● Remember to reset the appropriate variable(s) to their initial values for each iteration of bisection search.
Related
I just picked up coding for the first time and started with the MIT free intro to python course. I am on the first problem of the second homework and I am having a hard time figuring out how to solve. I saw some other posts about this but I think it would be way easier to learn if someone could show me how to do it with my code rather than anothers.
This is the problem:
You have graduated from MIT and now have a great job! You move to the
San Francisco Bay Area and decide that you want to start saving to buy
a house. As housing prices are very high in the Bay Area, you realize
you are going to have to save for several years before you can afford
to make the down payment on a house. In Part A, we are going to
determine how long it will take you to save enough money to make the
down payment given the following assumptions:
Call the cost of your dream home total_cost.
Call the portion of the cost needed for a down payment portion_down_payment. For simplicity, assume that portion_down_payment
= 0.25 (25%).
Call the amount that you have saved thus far current_savings. You start with a current savings of $0.
Assume that you invest your current savings wisely, with an annual return of r (in other words, at the end of each month, you receive an
additional current_savings*r/12 funds to put into your savings – the
12 is because r is an annual rate). Assume that your investments earn
a return of r = 0.04 (4%).
Assume your annual salary is annual_salary.
Assume you are going to dedicate a certain amount of your salary each month to saving for the down payment. Call that portion_saved.
This variable should be in decimal form (i.e. 0.1 for 10%).
At the end of each month, your savings will be increased by the return on your investment, plus a percentage of your monthly salary
(annual salary / 12). Write a program to calculate how many months it
will take you to save up enough money for a down payment. You will
want your main variables to be floats, so you should cast user inputs
to floats.
Here is my code so far:
total_cost = float(input("What is the cost of the home? "))
annual_salary = float(input("What is your annual salary? "))
portion_saved = float(input("How much would you like to save per year? "))
portion_down = (total_cost*.25)
current_savings = 0
monthly_salary = (annual_salary/12)
interest_rate = .04
#goal is to loop up until I have enough for the down payment
print (total_cost)
print (annual_salary)
print (portion_saved)
print ("The downpayment required for this house is", portion_down)
#need to use +=, otherwise you would have to do current saving = current savings + 1
months = 1
while current_savings < portion_down:
current_savings += current_savings*(.4/12) #monthly interest
current_savings += portion_saved #monthly savings
months += months + 1
print ("It will take", months, "months to save the needed down payment of", portion_down)
You did a pretty good job.
The biggest problem I see in your code is:
months += months + 1
You need to change it to:
months +=1
I also made some tweaks in your code, but essentially I kept the same idea:
total_cost = float(input("What is the cost of the home? "))
monthly_salary = float(input("What is your monthly salary? "))
#portion_saved = float(input("How much would you like to save per year? "))
portion_down = (total_cost*.25)
current_savings = 0
interest_rate = 0.04
months = 1
portion_saved = 0.1
print ("The downpayment required for this house is", portion_down)
while current_savings < portion_down:
current_savings += current_savings(interest_rate/12)+portion_saved*monthly_salary
months +=1
print ("It will take", months, "months to save the needed down payment of",portion_down)
IRS informants are paid cash rewards based on the value of the money recovered. If the information was specific enough to lead to a recovery, the informant receives
10% of the first $75,000 plus
5% of the next $25,000 plus
1% of the remainder up to a maximum reward of $50,000.
The following function accepts the amount of money recovered and returns the reward.
to run tests: python3 -m doctest irs_reward.py -v
'''def irs_reward(money_recovered):
IRS informants are paid cash rewards based on the value of the money recovered
calculate reward amount from money recovered
args:
money_recovered (float): dollar value of money recovered
returns:
the dollar value of the reward (float)
formula:
10% of the first $75k
+ 5% of the next $25k
+ 1% of the rest, up to max total reward of $50k
examples/doctests:
no money recovered
>>> round(irs_reward(0), 2)
0.0
$75k recovered
>>> round(irs_reward(75000), 2)
7500.0
$95k recovered
>>> round(irs_reward(95000), 2)
8500.0
$200,000 recovered
>>> round(irs_reward(200000), 2)
9750.0
$42 milliion recovered, max out at $50k reward
>>> round(irs_reward(42000000), 2)
50000.0
# TO DO: Add your code here #
# ========================= #
return
Can someone help me with the code. I have tried 5 to 6 times and finally closed out the program and did not save it.
You should learn how this works, not just get people to do your homework for you, but here goes:
def calculate_reward(money_recovered):
reward = 0
if money_recovered >= 4125000:
reward = 50000
elif money_recovered >= 100000:
reward = (money_recovered - 100000)/100 + 8750
elif money_recovered >= 75000:
reward = (money_recovered - 75000)/20 + 7500
else:
reward = money_recovered/10
return reward
The reason for the number 4125000 is because thats the number needed to make the total reward 50k. It is 10% of 75k + 5% of 25k + 1% of the rest, which makes the remaining 41.25k.
The next barrier is 100k since that is 25k + 75k, so things above that but below 4125000 get taxed 1%, and each time we check for the money being over a barrier we add the max they received from lower amounts.
So currently this code is returning an infinite loop. The assignment is to calculate a fixed monthly payment. My biggest pain is with epsilon and trying to get my newly calculated balance within it's range. The code takes the balance and calculates the theoretical most and least amount we can pay monthly and be at 0 new_balance. MonthlyIR is monthly interest rate
def bisection(balance,annualinterestRate):
monthlyIR = annualinterestRate/12.0
new_balance = balance
monthly_lower = balance/12
monthly_upper = (balance * (1 + monthlyIR)**12)/12.0
epsilon = 0.01
print(monthly_lower,monthly_upper)
while abs(new_balance) >= epsilon:
new_balance = balance
print(monthly_lower,monthly_upper)
payment = (monthly_upper + monthly_lower)/2
for i in range(12):
new_balance -= payment
new_balance *= monthlyIR
if new_balance > 0:
monthly_lower = payment
else:
monthly_upper = payment
return round(payment,2)
So pretty much when I go through the monthly payments, and the new balance is still bigger than epsilon then set either the max or the min = to payments. However when It runs the max or min don't update and I can't figure out why.
I would like someone to solve that particular issue and I would like insight on a cleaner way to do this. Whether it's more specialization of functions or a different approach other than iterative.
Ran 2 tests
annualinterestRate >= 12
No infinite loop, and returns results
annualinterestRate < 12 :
Infinite loop
Good luck :)
First, the monthly interest is incorrectly calculated. On one hand the algorithm treats it as non-compound interest:
monthlyIR = annualinterestRate/12.0
but earlier:
monthly_lower = balance/12
and later, in the loop:
new_balance *= monthlyIR
which implies that it is a compound interest. But the code does not converge for another reasons. You are calculating the impact of interest on the debt incorrectly. It should be:
new_balance *= monthlyIR + 1
The problem is that new_balance should be increased by monthly interest rate. For example, if the monthly IR is 0.005, then the original code lowers the balance to 0.005 of its previous size. Unfortunately for us, borrowers, our debt does not shrinks to 1/200 of its original value every month, but rather it increases by extra 1/200 of the original debt. A debt of 1000$ becomes 1005$, i.e., the debt should be multiplied by 1.005 instead of 0.005.
The original code will converge (incorrectly) only with annual interest rates of 12 and above (1200%), since it makes monthly IR >= 1 (100%). This way, the multiplication does not lower the debt in the original code.
The full code is:
def bisection(balance,annualinterestRate):
# This is most likely an incorrect monthly IR
# I suspect it should be:
# monthlyIR = pow(1+annualinterestRate, 1/12.0) - 1
monthlyIR = annualinterestRate/12.0
new_balance = balance
monthly_lower = balance/12
monthly_upper = (balance * (1 + monthlyIR)**12)/12.0
epsilon = 0.01
print(monthly_lower,monthly_upper)
while abs(new_balance) >= epsilon:
new_balance = balance
print(monthly_lower,monthly_upper)
payment = (monthly_upper + monthly_lower)/2
for i in range(12):
new_balance -= payment
new_balance *= monthlyIR + 1
if new_balance > 0:
monthly_lower = payment
else:
monthly_upper = payment
return round(payment,2)
Besides, there is a trivial formula to calculate this in one line, instead of using bisection. Look it up, or derive it.
For example, read here
I'm learning the Python 2.5.4 programming language using the MIT OCW Scholar course 6.00.
I have written a program, but with the same input, my program's output differs from the output that the MIT people have shown the program to produce.
I wish to write a Python 2.5.4 program that will get current outstanding balance and annual interest rate as input from the user, and then uses the bisection search method to find the minimum fixed minimum monthly payment that would cause the balance to fall below zero within 12 months. Then the program displays the right monthly amount, the number of months needed to claer the outstanding amount, and the final balance.
Here's my code:
# Start of code
balance = float(raw_input('Enter the outstanding balance on your credit card: '))
interestRate = float(raw_input('Enter the annual credit card interest rate as a decimal: '))
lower = balance / 12.0
upper = ( balance * ( 1 + interestRate / 12.0 ) ** 12.0 ) / 12.0
payment = ( lower + upper ) / 2.0
currentBalance = balance
while currentBalance > 0:
for months in range(1, 13):
currentBalance = currentBalance * ( 1 + interestRate / 12.0 ) - payment
if currentBalance <= 0:
break
if currentBalance <= 0:
break
else:
lower = payment
payment = ( lower + upper ) / 2.0
currentBalance = balance
print 'RESULT'
print 'Monthly payment to pay off debt in 1 year:', '$' + str(round(payment, 2))
print 'Number of months needed:', months
print 'Balance:', '$' + str(round(currentBalance, 2))
#End of code
Does my code do the desired job? If not, where lies the problem? And, how to fix it? Even if the program is right, in what ways can it be improved?
Please do bear in mind that I'm a only a beginner.
Regards.
You have a couple of typos (which may have been introduced when copying into your posting):
you split balance on your credit / card: across a line-ending, which will give a SyntaxError
currentBalance = currentBalance * ( 1 + interestRate / 12.0 ) payment is missing a - operator before payment
The first logical error is
if currentBalance <= 0:
break
... you stop as soon as you find a higher than needed payment; you only ever increase possible payment values (lower = payment), never decrease it (you should have a clause leading to upper = payment, otherwise your bisection search will be lopsided).
Once you do that, you will have to add a new test to know when to stop looping. What is your target accuracy - payment to the nearest cent? How will you know when you have found it?
My only other suggestion would be to improve your code organization by defining some operations as functions - get_float(prompt) and final_balance(current_balance, interest_rate, num_payments) are obvious candidates.
I am learning python and CS via the MIT OCW material. Doing this for fun btw because I think its interesting. I am trying to tackle a problem set where for a given credit card balance (ex. $1200) and interest rate (18%), what would minimum monthly payment need to be pay it off completely in 12 months or less. Start with $100 and if more or less is needed, change it increments of $10. In my code below, if the initial start of $100 doesnt work, i dont know how to increase it by 10 and THEN start iterating again. Im not even sure starting with a "While" is the best approach. Im sure the pros could code this up in like 2 lines but I would appreciate if anyone were to help, they do it the long way so a novice like myself could follow it.
balance = float(input("Enter the outstanding balance on your credit card:"))
annual_rate = float(input("Enter the annual credit card interest rate as a decimal:"))
monthly_interest_rate = annual_rate / 12.0
minimum_monthly_payment = 100
updated_balance_each_month = balance * (1 + monthly_interest_rate) - minimum_monthly_payment
month = 1
while month <= 12:
month += 1
updated_balance_each_month = updated_balance_each_month * (1 + monthly_interest_rate) - minimum_monthly_payment
if updated_balance_each_month <= 0:
print ("Monthly payment to pay off debt in 1 year:", minimum_monthly_payment)
print ("Number of months needed:",month)
print (round(updated_balance_each_month,2))
break
else:
minimum_monthly_payment += 10
So in programming you can create functions. These are blocks of code that you can call from elsewhere that will execute what you put in them. For python the syntax looks like...
def function_name(parameter1, parameter2, parameterN):
#function code here
#optional return statement
return parameter1 + parameter2
So what you could try is putting your while loop inside a function and if the while loop is successful, return true, and if it fails return false. Then in your main you can choose to redo the function if it returns false. So here is an example of how you could fix your problem.
def try_to_pay_off(payment, interest_rate, start_balance):
month = 0
updated_balance = start_balance
while month <= 12:
month += 1
updated_balance = updated_balance * (1 + interest_rate) - payment
if updated_balance <= 0:
return True
# will return false if it goes through 12 months and debt not payed off
return False
def Main():
balance = float(input("Enter the outstanding balance on your credit card:"))
annual_rate = float(input("Enter the annual credit card interest rate as a decimal:"))
done = False
monthly_payment = 100
while not done:
if try_to_pay_off(monthly_payment,annual_rate,balance):
done = True
else:
monthly_payment += 10
# after finding the monthly payment required
print ("Monthly payment to pay off debt in 1 year:", monthly_payment)
This way you keep running your function with new values until it finds a monthly payment that can pay off your balance with interest rate in one year.
First off, welcome to StackOverflow, and I hope you enjoy the world of programming. I have heard MIT OCW is a great resource, so best of luck to you and whatever you're going to do.
If I understand the question correctly, you must find the smallest minimum payment (which is the same across all twelve months) that will pay off the debt. (I currently don't have commenting privileges, so if I misunderstand the question, I'd appreciate it if you clarified.)
To answer your question in the title, to "re-initiate iteration," you would create a second loop outside the first. Here's some example code.
# given balance and annual_rate
monthly_interest_rate = annual_rate / 12.0
minimum_monthly_payment = 100
# debt_is_paid_off is a use for a variable called a one-way flag
debt_is_paid_off = False
while not debt_is_paid_off:
updated_balance_each_month = balance
# range is a neat little python trick to go from 1 to 12 easily
for month in range(1, 13):
# update the balance
updated_balance_each_month *= (1 + monthly_interest_rate)
updated_balance_each_month -= minimum_monthly_payment
# check if it's paid off
if updated_balance_each_month <= 0:
debt_is_paid_off = True
print ("Monthly payment to pay off debt in 1 year:",
minimum_monthly_payment)
print ("Number of months needed:",month)
print (round(updated_balance_each_month,2))
# note that this only breaks out of the for-loop.
# so we need debt_is_paid_off to exit out.
break
minimum_monthly_payment += 10
Note how there are two loops in the code. The outer loop keeps increasing which minimum payment to try until the debt is paid off, and the inner loop simulates paying off the debt by repeating twelve times.
However, the standard approach - just using the "break" keyword, as you did - doesn't work in Python if there are two loops. It only breaks out of the first. So we use this new variable, debt_is_paid_off, to get us out of that second loop.
ok thanks guys for the help but I ended up coming up with a solution myself (!!!). I figured out that in the code I originally posted, it would do the calculation for month 1 then check to see if updated_balance_each_month was less than 0 and if not increase monthly minimum by 10 for each month after that until balance was equal to or below 0 instead of running through all 12 months and then increasing monthly minimum by 10. so you can see that I added another IF statement so that monthly minimum only increased if month == 12 and balance was above 0 and it worked! Now, can anyone tell me how I can add code here so that it shows up properly? I click on the {} and then paste my code where it says so but it always comes up jumbled...
balance = float(input("Enter the outstanding balance on your credit card:"))
annual_rate = float(input("Enter the annual credit card interest rate as a decimal:"))
monthly_interest_rate = annual_rate / 12.0
minimum_monthly_payment = 100
updated_balance_each_month = balance * (1 + monthly_interest_rate) - minimum_monthly_payment
month = 1
while month <= 12:
month += 1
updated_balance_each_month = updated_balance_each_month * (1 + monthly_interest_rate) - minimum_monthly_payment
if updated_balance_each_month <= 0:
print ("Monthly payment to pay off debt in 1 year:", minimum_monthly_payment)
print ("Number of months needed:",month)
print (round(updated_balance_each_month,2))
break
if month == 12 and updated_balance_each_month > 0:
minimum_monthly_payment += 10
month = 0
updated_balance_each_month = balance