MIT 6.0001 Pset 1c Bisectional Search question - python

Link to pset 1(https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/assignments/MIT6_0001F16_ps1.pdf)
Hello,
I've been working through the bisectional search problem for the MIT 6.0001 course's pset1. I feel like I have all components down, but it keeps giving me the same answer for savings rate and steps in bisectional search no matter what input I give. Could anyone tell me what I have done wrong here?
# User input
annual_salary = float(input('Enter the starting salary: ' ))
# Given sets of assumption
total_cost = 1000000
semi_annual_raise = 0.07
portion_down_payment = 0.25
current_savings = 0
r = 0.04 # Annual investment interest rate of current savings
down_payment = portion_down_payment * total_cost
num_guess = 0 # Bisectional search guess count starts at 0
# Lowest and highest integer savings rate in intial bisection search
low = 0
high = 10000
guess = (high + low)//2.0
while abs(down_payment - current_savings) >= 100:
current_savings = 0
rate = guess/10000
for month in range(36):
if month%6 == 0 and month > 0:
annual_salary += annual_salary * semi_annual_raise
monthly_salary = annual_salary/12
current_savings += (rate * monthly_salary) + current_savings*(r/12)
# Bisectional search introduced
if current_savings < down_payment:
low = guess
else:
high = guess
guess = (high + low)//2.0
num_guess += 1
if num_guess > 13:
break
print('Best savings rate:', rate)
print('Steps in bisection search:', num_guess)

You should reset the annual_salary variable to its original value (value from the input) each time before going through the [for loop] because each iteration tries a different saving rate guessing with the same starting salary.
I suggest you use a different variable (e.g. updated_annual_salary) and assign the starting salary to it to be able to reset it over and over.
Another thing is that when the annual salary gets updated, the monthly salary gets updated too and so does the saved portion. So, your [while loop] should start like this:
while abs(down_payment - current_savings) >= 100:
updated_annual_salary = annual_salary
current_savings = 0
rate = guess / 10000
for month in range(36):
if month % 6 == 0 and month > 0:
updated_annual_salary += updated_annual_salary * semi_annual_raise
monthly_salary = updated_annual_salary / 12
current_savings += (rate * monthly_salary) + current_savings * (r / 12)

Related

Why does changing how a bisection search is implemented make a runtime difference between two solutions to the same problem?

while going through a python programming problem from an MIT course, I got stuck trying to figure out the difference between two solutions, or more specifically, the reason behind why changing a part of the code made it run faster, while the original solution took so long that it kept on running (no infinite loop) and never delivered an output.
My solution that ran forever and did not give an output:
def bisection(i: int, j: int):
"""
Inputs: Integers, 'i' and 'j', representing the lower limit and the upper limit of the search.
Returns: Bisects the number of possibilites and returns the middle value.
"""
high = j
low = i
return (high+low)/2
semiannualraise = .07
rmonthly = 0.04/12
cost = 1_000_000
downpayment = cost*0.25
epsilon = 100
savings = 0
nummonths = 0
startingsalary = float(input("Enter Salary: "))
high = 10000
low = 0
portion_salary= 0
step = 0
salary = startingsalary
monthly_salary=salary/12
while True:
nummonths = 0
salary = startingsalary
while nummonths<36:
portion_of_salary = (bisection(low,high))/10000
step += 1
savings = ((salary/12)*portion_of_salary)+(savings*rmonthly)
nummonths +=1
if nummonths % 6 == 0:
salary = salary + (semiannualraise*salary)
if downpayment-savings < 100 and downpayment-savings >= 0:
break
elif downpayment-savings>= 100:
low = portion_of_salary*10000
else:
high = portion_of_salary*10000
print(f"Best savings rate: {portion_of_salary*100}%")
Solution by Linus
annual_salary = float(input('Enter the starting salary: '))
constant = annual_salary
semi_annual_rate = 0.07
r = 0.04
down_payment = 0.25
total_cost = 1000000
current_savings = 0
months = 0
bisection_count = 0
min = 0
max = 1
portion_saved = (max/2.0)/1000
if(annual_salary*3<down_payment*total_cost):
print('It is not possible to pay the down payment in three years.')
while(True):
while(months<36):
current_savings += (current_savings*r/12)+(portion_saved*(annual_salary/12))
months+=1
if(months % 6 == 0):
annual_salary += annual_salary*semi_annual_rate
if(current_savings >= down_payment*total_cost+100):
max = portion_saved
portion_saved = max/2.0
bisection_count+=1
months = 0
current_savings = 0
annual_salary = constant
elif(current_savings >= down_payment*total_cost-100 and current_savings <= down_payment*total_cost+100):
break
else:
min = portion_saved
portion_saved = (max+min)/2.0
bisection_count+=1
months = 0
current_savings = 0
annual_salary = constant
print('Best savings rate: ', portion_saved)
print('Steps in bisection search: ', bisection_count)
In my opinion, the difference is made only by the way we define our limits for the bisection search, and I am unable to quite get my head around what's happening there.
Note: Though I have been using stackoverflow for about a year to look for solutions, this would be my first ever post on here and its possible that I failed to ask a great question in accordance with How to ask a good question- StackOverflow. If so, please bear with me and also let me know what mistakes I made. Thank you.
I tried the following implementation for the bisection search:
def bisection(i: int, j: int):
"""
Inputs: Integers, 'i' and 'j', representing the lower limit and the upper limit of the search.
Returns: Bisects the number of possibilities and returns the middle value.
"""
high = j
low = i
return (high+low)/2
and later:
high = 10000
low = 0
and then:
elif downpayment-savings>= 100:
low = portion_of_salary*10000
else:
high = portion_of_salary*10000
and expected the same outputs as the other solution, but the code kept on running forever.
After some debugging, I found out the reason the first code does not give an output is not that it runs slow, but in fact enters an infinite loop in this part:
while nummonths<36:
portion_of_salary = (bisection(low,high))/10000
step += 1
savings = ((salary/12)*portion_of_salary)+(savings*rmonthly)
nummonths +=1
if nummonths % 6 == 0:
salary = salary + (semiannualraise*salary)
if downpayment-savings < 100 and downpayment-savings >= 0:
break
elif downpayment-savings>= 100:
low = portion_of_salary*10000
else:
high = portion_of_salary*10000
The program never exits this while loop because it never gets to the break condition, i.e, variable savings never exceeds variable downpayment.
The part causing this issue is at:
savings = ((salary/12)*portion_of_salary)+(savings*rmonthly)
Here, instead of incrementing the savings every month, the program assigns it to a new value every iteration and the savings never accumulates.
The fix is to simply add the missing '+' before '=':
savings += ((salary/12)*portion_of_salary)+(savings*rmonthly)

Can someone explain to me why doesn't this piece of code work?

annual_salary = int(input("Your annual salary "))
semi_annual_raise = 0.07
r = 0.04
down_payment = 250000
epsilon = 100
low = 0
high = 10000
guess = (high + low)//2
best_saving_rate = (guess/10000)
months = 0
current_savings = 0
steps = 0
while abs(current_savings - down_payment) >= 100:
for i in range(36):
current_savings += best_saving_rate*(annual_salary/12) + (current_savings*r)/12
months +=1
if months%6 == 0:
annual_salary = annual_salary + semi_annual_raise*annual_salary
if current_savings < down_payment:
low = guess
else:
high = guess
steps += 1
guess = (high + low)//2
best_saving_rate = float(guess/10000)
print(steps)
print(best_saving_rate)
print(current_savings)
This code is supposed to find the best saving rate for someone who is trying to have enough money for a payment of 250000 dollars in 36 months. I use bisection search and I think I'm in the right track but it won't work. I think the problem is that the variable current savings is not reinitializing with every iteration and I do not know how to make it do that. PLEASE HELP.
Why are you expecting the current_savings to be reset to 0 with every iteration? You do not do that in the code, so what would cause that to happen? Also by the looks of the code, you should be resetting months to 0 as well (though it appears that the for loop index variable i should actually be the month).
This fixes the obvious errors that I could see:
while abs(current_savings - down_payment) >= 100:
current_savings = 0 # add this
for month in range(36): # Change this
current_savings += best_saving_rate * (annual_salary / 12) + (current_savings * r) / 12
# months += 1 <-- remove this
if months % 6 == 0:

Python - I've been trying to Increment a semi annual raise (from PSet_1b of MIT 6.0001) but the results are the same

PSet_1a - Baseline
This prompts the user for the cost of their dream house, their salary, the portion of their monthly salary that they are willing to save, and returns the number of months it would take for them to have a down payment (25% of the cost of their dream house)
total_cost = float(input('How much is the dream house? '))
portion_down_payment = 0.25
current_savings = 0
r = 0.04
annual_salary = float(input('What is your salary? '))
portion_saved = float(input('What is the amount saved per month? '))
monthly_salary = annual_salary / 12.0
amount_down_payment = total_cost * portion_down_payment
portion_amount = monthly_salary * portion_saved
months = 0
while current_savings <= amount_down_payment:
current_savings += portion_amount + (current_savings * (r / 12))
months += 1
print(current_savings, months)
PSet_1b - Adjusted for Semi-Annual Raise
Prompts the user as the same above but this one asks for a semi annual rate, turns it into a number to add to the annual raise.
total_cost = float(input('How much is the dream house? '))
portion_down_payment = 0.25
current_savings = 0
r = 0.04
annual_salary = float(input('What is your salary? '))
portion_saved = float(input('What is the amount saved per month? '))
semi_annual_rate = float(input('What is the rate of your semi-annual_raise? '))
monthly_salary = annual_salary / 12.0
semi_annual_raise = monthly_salary * semi_annual_rate
amount_down_payment = total_cost * portion_down_payment
portion_amount = monthly_salary * portion_saved
months = 0
while current_savings <= amount_down_payment:
months += 1
if months % 6 == 0:
annual_salary += semi_annual_raise
current_savings += portion_amount + (current_savings * (r / 12))
print(current_savings, months)
Both programs return the same results when I run them and I have been trying to figure out why and how on my own for a few hours now without much improvement.
The answer is to update portion_amount per 6 months through if statement and not to go through it semi_annual_raise on the annual_salary.
Thanks to Randy from the comments.

I'm not sure how to account for the 36 month period in my bisection search

Forewarning, I have just started learning python so please bear with me on my beginner code.
So in the MIT6_0001 course on python. You are given a problem where you are supposed to find the "optimal monthly saving rate" for a 25% downpayment on a 1 million dollar house in a 36 month time period using a bisection search algorithm, where you're starting salary is 150,000 and a semi-annual raise of 7%. You must also account for an annual ROI 4% on your savings.
I have been working on this for a week. at first, I tried it without the for loop and that pretty much returned best savings rate as 100% which is where my main problem lies, I can't get around the fact that each time I bisect the value it will always be low so it just keeps trying to get closer and closer to 1 until the epsilon value is reached in the while loop. I have seriously been losing sleep over this please help
total_cost = 1000000
annual_salary =150000
current_savings = 0
epsilon = 100
low = 0
high = 10000
savings_rate= (low + high)/2
down_payment = .25 * total_cost
raise_rate = .07
month_count = 0
r = .04/12
step_count = 0
while current_savings-down_payment <= epsilon :
for i in range(36):
if month_count != 0 and month_count % 6 == 0:
annual_salary += annual_salary * raise_rate
current_savings += current_savings * r + (annual_salary/12) * (savings_rate/10000)
if current_savings < down_payment:
low = savings_rate
print("low =",low)
else:
high = savings_rate
print("high =",high)
month_count += 1
savings_rate= (low + high)/2
step_count += 1
print("Best savings rate:​ ",savings_rate/10000)
print("Steps in bisection sear: ",step_count)
expected output
Best savings rate:​ 0.4411
Steps in bisection search:​ 12
actual
Best savings rate:​ 0.5
Steps in bisection search:​ 1
Remember our goal is to take a continuous function and find the approximate points where it is zero in our graph. Our function in this case is abs(current_savings-down_payment)-epsilon = 0.I think the problem your having is that the absolute value of current savings minus down payment has to be less than epsilon and you are testing whether it is greater than epsilon instead.
I figured out the solution.
total_cost = 1000000
annual_salary = 150000
current_savings = 0
epsilon = 100
low = 0
high = 10000
down_payment = .25 * total_cost
raise_rate = .07
r = .04/12
step_count = 0
while abs(current_savings - down_payment) >= epsilon:
savings_rate = float(low + high) / 2.0 #take care of integer division
current_savings = 0 # reset for next itteration
annual_salary = 150000 #reset for next itteration
# print("savings_rate = %f " % (savings_rate/10000)) #4debugging
# print("current_savings= ", current_savings) #4debugging
for i in range(1,36): #initiate range at 1, easier to handle 6 month raise
if i != 1 and i % 6 == 0:
annual_salary += annual_salary * raise_rate
current_savings += current_savings * r + (annual_salary/12) * (savings_rate/10000)
# print("count =",i) #4debugging
# print("annual_salary: ", annual_salary) #4debugging
print ("current_savings=%f, down_payment=%f" % (current_savings, down_payment) )
print ("diff = %f " % abs(current_savings - down_payment) )
if (step_count > 20):
print('**********ERROR**********: inf loop')
break # exit infinite loop
elif current_savings < down_payment:
low = savings_rate #update range low if less than down payment
print("new range: %f -> %f" % (low, high) )
elif current_savings > down_payment:
high = savings_rate #update range high if greater than down payment
print("new range: %f -> %f" % (low, high) )
print("")
step_count += 1
print ("current_savings=%f, down_payment=%f" % (current_savings, down_payment) )
print ("diff = %f " % abs(current_savings - down_payment) )
print("best savings rate: ",savings_rate/10000)
print("number of bisection steps: ",step_count)

How to fix infinite loop during bisection search

My code passes test cases but if anything about ~949,000 is input it enters an infinite loop.
I need to calculate the best rate at which to save a portion of a monthly income to save in order to afford a down payment in 36 months with 2 significant digits. I'm thinking this has something to do with me not quite understanding how epsilon is calculated - I've tried calculating epsilon as 0.0001 * total_cost, 0.0004 * portion_down_payment, and 0.0001 * annual_income all to no avail.
#House Hunting ps1c
low = int(0)
high = int(10000)
percent_saved = (low + high)/2.0
current_savings = 0
annual_salary = int(input("What is your starting anual salary? "))
total_cost = 1000000
semi_annual_raise = 0.07
portion_down_payment = total_cost * 0.25
epsilon = 100
r = 0.04
total_months = 0
steps = 0
while True:
current_savings = 0
monthly_salary = annual_salary/12
for i in range(1,37):
current_savings += (current_savings*r/12)
current_savings += (monthly_salary * (percent_saved / 10000))
total_months += 1
if total_months % 6 == 0:
monthly_salary += monthly_salary * semi_annual_raise
steps +=1
if abs(current_savings - portion_down_payment) <= epsilon:
print("Steps in bisectional search: ", steps)
best_savings_rate = str(percent_saved / 100)
print("Best savings rate: ", (best_savings_rate + "%"))
break
elif (portion_down_payment - 100) - current_savings > 0:
low = percent_saved
percent_saved = int((low + high) / 2.0)
else:
high = percent_saved
percent_saved = int((low + high) / 2.0)
if percent_saved >= 9999:
print("It is not possible to afford this in 3 years")
break
Test Case 1
Enter the starting salary: 150000
Best savings rate: 0.4411
Steps in bisection search: 12
Test Case 2
Enter the starting salary: 300000
Best savings rate: 0.2206
Steps in bisection search: 9
Test Case 3
Enter the starting salary: 10000
It is not possible to pay the down payment in three years
My code passes all test cases but when the input is too high it enters an infinite loop that I don't know how to reconcile.
Essentially when annual salary becomes higher the optimal savings rates becomes smaller. When the optimal savings rate becomes smaller then the level of precision you require for
abs(current_savings - portion_down_payment) <= epsilon
becomes higher.
When you cast percent_saved to an int in
percent_saved = int((low + high) / 2.0)
it artificially limits the precision and then code enters an infinite loop.
Remove the cast and the code will work always.

Categories

Resources