Python bisection search confusion - python

I'm trying to work on the MIT intro to CS with Python problem set 1.
Here's the problem (bottom of page 3):
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
Here's my code:
#best savings rate in 3 years
annual_salary = float(input("Enter your annual salary: "))
total_cost = 1000000
semi_annual_raise = 0.07
portion_down_payment = 0.25*total_cost
r = 0.04
low = 0
high = 10000
pre_saved = int((high+low)/2)
steps = 0
current_savings = 0
epsilon = 100
months = 0
salary_increase_months = 0
portion_saved = pre_saved/10000
print(portion_saved)
while abs(current_savings - portion_down_payment) >= epsilon:
#calculates savings after 36 months
while(months < 36):
#checks every 6th iteration to add the semi annual raise
if(salary_increase_months == 6):
annual_salary += annual_salary*semi_annual_raise
salary_increase_months = 0
current_savings += current_savings*(r/12) + portion_saved*(annual_salary/12)
salary_increase_months += 1
months += 1
#print(current_savings)
#bisection search portion
if current_savings < portion_down_payment - epsilon:
#print('1')
low = portion_saved*10000
current_savings = 0
elif current_savings > portion_down_payment + epsilon:
#print('2')
high = portion_saved*10000
current_savings = 0
elif current_savings < portion_down_payment + epsilon and current_savings > portion_down_payment - epsilon:
print('Best savings rate:', portion_saved)
print('Steps in bisection search:', steps)
break
else:
print('It is not possible to pay the down payment in three years.')
break
portion_saved = int((low + high)/2)
portion_saved = portion_saved/10000
steps += 1
months = 0
salary_increase_months = 0
When I put in a value for the salary, all I get is the original percentage saved (0.5) and the output doesn't end. Nothing else gets printed. I created three if statements that are supposed to check the value of portion saved and do a bisection search (if the value is higher than portion down payment plus epsilon, then high becomes the portion saved, and vice versa).

def curr_saving(salary, Semi_raise, saveP, month):
saving = 0
monthly_income = salary/12
# down_pay = 0.25*cost
for i in range(1, month):
if i % 6 == 0:
salary += salary*Semi_raise
monthly_income = salary/12
interest = saving*(1+0.04/12)
saving = monthly_income*saveP+interest
return saving
def Hunting_C(base, Semi_raise, cost):
# saving = 0
# salary = base
# monthly_income = salary/12
down_pay = 0.25*cost
No_month = 36
# saving_range = numpy.arange(0, 1, 0.0001)
step = 0
min_S = 0
max_S = 1
saveP = (min_S+max_S)/2
while (abs(curr_saving(base, Semi_raise, saveP, No_month)-down_pay)) >= 100:
step += 1
if curr_saving(base, Semi_raise, saveP, No_month) > down_pay:
max_S = saveP
else:
min_S = saveP
saveP = (min_S+max_S)/2
return f'saving rate: {saveP}, No of steps: {step}, current saving: {curr_saving(base, Semi_raise, saveP, No_month)}'
print(Hunting_C(150000, 0.07, 1000000))

Related

How to iterate code and save each output to a list

I'm just learning how to code and I've encountered a problem I can't seem to work around. I've built a strategy for a simple game of chance (similar to the Martingale strategy for those familiar) and I want to run the code n number of times and save the output of each iteration so I can aggregate the results. Note the current 'for' loop is part of my code, I tried using another 'for' loop to run the entire program n times to no avail. Thanks heaps in advance. Apologies if this is a silly question. Here is my code:
import math
import random
import heartrate
heartrate.trace(browser=True)
mult = 1.2
winChance = 0.8250
balance = 259
x = 0
for i in range (0,500):
bet1 = balance/259
balance = balance-bet1
print(balance)
n = random.random()
if n > winChance:
bet2 = (bet1*(1/(mult-1)))+bet1
balance = balance-bet2
n = random.random()
if n > winChance:
bet3 = ((bet1+bet2)*(1/(mult-1)))+bet1
balance = balance-bet3
n = random.random()
if n > winChance:
bet4 = ((bet1+bet2+bet3)*(1/(mult-1)))+bet1
balance = balance-bet4
n = random.random()
if n > winChance:
bet5 = ((bet1+bet2+bet3+bet4)*(1/(mult-1)))+bet1
balance = balance-bet5
print("end")
break
else:
balance = balance = bet4*mult
else:
balance = balance + bet3*mult
else:
balance = balance + bet2*mult
else:
balance = balance + bet1*mult
If I understand the question and code correctly (doubtful), this change would do what you ask for: Running your original code N times (with N = 10):
$ diff -u iterate.py.orig iterate.py
--- iterate.py.orig 2022-03-20 13:02:54.010642003 +0100
+++ iterate.py 2022-03-20 13:17:35.368615800 +0100
## -5,10 +5,12 ##
mult = 1.2
winChance = 0.8250
+end_balances = []
-balance = 259
-x = 0
-for i in range (0,500):
+for _ in range(10):
+ balance = 259
+ x = 0
+ for i in range (0,500):
bet1 = balance/259
balance = balance-bet1
print(balance)
## -35,7 +37,7 ##
break
else:
- balance = balance = bet4*mult
+ balance = balance + bet4*mult
else:
balance = balance + bet3*mult
## -47,3 +49,6 ##
else:
balance = balance + bet1*mult
+ end_balances.append(balance)
+
+print(end_balances)
Here is the full code:
import math
import random
import heartrate
heartrate.trace(browser=True)
mult = 1.2
winChance = 0.8250
end_balances = []
for _ in range(10):
balance = 259
x = 0
for i in range (0,500):
bet1 = balance/259
balance = balance-bet1
print(balance)
n = random.random()
if n > winChance:
bet2 = (bet1*(1/(mult-1)))+bet1
balance = balance-bet2
n = random.random()
if n > winChance:
bet3 = ((bet1+bet2)*(1/(mult-1)))+bet1
balance = balance-bet3
n = random.random()
if n > winChance:
bet4 = ((bet1+bet2+bet3)*(1/(mult-1)))+bet1
balance = balance-bet4
n = random.random()
if n > winChance:
bet5 = ((bet1+bet2+bet3+bet4)*(1/(mult-1)))+bet1
balance = balance-bet5
print("end")
break
else:
balance = balance + bet4*mult
else:
balance = balance + bet3*mult
else:
balance = balance + bet2*mult
else:
balance = balance + bet1*mult
end_balances.append(balance)
print(end_balances)
Note that you normally would extract the inner loop into a separate function.
Edit: Fixed the typo in the innermost else as well.
You can start by creating an empty list such as:
balance_end = []
And then appending the final balance after each iteration (I have fixed the first else which had a typo as well), such as:
else:
balance = balance + bet4*mult
balance_end.append(balance)
else:
balance = balance + bet3*mult
balance_end.append(balance)
else:
balance = balance + bet2*mult
balance_end.append(balance)
else:
balance = balance + bet1*mult
balance_end.append(balance)
Finally, you can safely assume that the balance_end index will match the number of iteration - 1 and the value, is the corresponding value of said iteration.
Here's my attempt to simplify things (to be honest, the code is quite convoluted and difficult to understand):
def bet(win_chance, previous_bets, mult):
if random.random() > win_chance:
this_bet = -1 * ((sum(previous_bets)*(1/(mult-1)))+previous_bets[0])
else:
this_bet = previous_bets[-1]*mult
return this_bet
# initialise variables
mult = 1.2
win_chance = 0.8250
balance = 259
for i in range(500):
previous_bets = []
previous_bets.append(balance/259)
balance -= previous_bets[0]
for i in range(5):
lost = bet(win_chance, previous_bets, mult)
balance += previous_bets[-1]
if not lost:
break
else:
# lost streak after 5 attempts
print('end')
print(balance)
create a list and append balance values to it
import math
import random
import heartrate
heartrate.trace(browser=True)
mult = 1.2
winChance = 0.8250
balance = 259
x = 0
values = list()
for i in range (0,500):
stop = False
bet1 = balance/259
balance = balance-bet1
print(balance)
n = random.random()
if n > winChance:
bet2 = (bet1*(1/(mult-1)))+bet1
balance = balance-bet2
n = random.random()
if n > winChance:
bet3 = ((bet1+bet2)*(1/(mult-1)))+bet1
balance = balance-bet3
n = random.random()
if n > winChance:
bet4 = ((bet1+bet2+bet3)*(1/(mult-1)))+bet1
balance = balance-bet4
n = random.random()
if n > winChance:
bet5 = ((bet1+bet2+bet3+bet4)*(1/(mult-1)))+bet1
balance = balance-bet5
print("end")
stop = True
else:
balance = balance = bet4*mult
else:
balance = balance + bet3*mult
else:
balance = balance + bet2*mult
else:
balance = balance + bet1*mult
values.append(balance)
if stop:
break

Why do I need to define variables in my while loop for my code to work?

This is a question from the 6.0001 MIT Intro to CS course PS1-C:
Why do I have to define certain variables twice - both inside and outside the while loop when the definition isn't changing? For example, diff_from_target or current_savings variable.
Full code below:
# User inputs
total_cost = 1000000
starting_annual_salary = 300000
semi_annual_raise = .07
# bisection search
low = 0
high = 10000
steps = 0
# Investments (investment = current_savings * monthly rate)
r = .04
monthly_rate = r/12
# Calculate down payment (target savings)
target_savings = .25 * total_cost
current_savings = 0
diff_from_target = target_savings - current_savings
savings_rate = (low+high)/2
while abs(diff_from_target) > 100 and steps < 100:
months = 0
current_savings = 0
annual_salary = starting_annual_salary
savings_rate = (low+high)/2
while months < 36:
current_savings += (annual_salary/12)*savings_rate + current_savings * monthly_rate
months += 1
if months % 6 == 0:
annual_salary += annual_salary * semi_annual_raise
diff_from_target = target_savings - current_savings
if diff_from_target > 0:
low = savings_rate
elif diff_from_target < 0:
high = savings_rate
steps +=1
else:
if abs(diff_from_target) <= 100:
print("%: {0:.4f}, steps: {1}".format(savings_rate, steps))
else:
print("Not possible to 36 months")
This is probably to make sure that the variable current_savings exists after the loop even if the loop didn't run a single time (for example if one of the conditions was False at the beginning)

Function not defined, although its been defined... Going Insane

So I am quite new to python and have been working on this assignment for a week now on and off and can't quite get it to run correctly. I am now getting errors that tell me the function get_in_code is not defined although I've defined it. Any help would be greatly appreciated!
SENTINEL = 'XXX'
DAY_CHARGE = 1500.00
#Define get_days
def get_days():
good_data = False
while not good_data:
try:
n_days = int(input("Please enter the number of days you stayed: "))
except ValueError:
print("Error, Bad Data")
else:
if n_days > 0:
good_data = True
else:
print("This is bad data, please re enter data")
return n_days
#define get_cost(p)
def get_cost():
cost = float(input("Please enter the cost for the procedures: "))
while cost < 0:
print("Procedure cost cant be negative: ")
cost = float(input("Please enter the cost for the procedures: "))
return cost
#define med cost
def med_cost():
med_cost = float(input("Enter the cost of your medicine: "))
while med_cost < 0:
print("Medicine cost cant be negative: ")
med_cost = float(input("Enter the cost of your medicine: "))
return med_cost
#Find day cost
def find_day_cost(in_code, n_days):
day_cost = n_days * DAY_CHARGE
if in_code == 'ZH':
p_day_cost = day_cost * 0.20
in_day_cost = day_cost *0.80
elif in_code == 'HH':
p_day_cost = day_cost * 0.10
in_day_cost = day_cost * 0.90
elif in_code == 'CH':
p_day_cost = day_cost * 0.25
in_day_cost = day_cost * 0.75
else:
p_day_cost = day_cost
in_day_cost = 0
return p_day_cost, in_day_cost
#find procedure cost
def find_proc_cost(in_code, cost):
if in_code == 'ZH':
p_proc_cost = 0
in_proc_cost = cost
elif in_code == 'HH':
p_proc_cost = cost * 0.10
in_proc_cost = cost * 0.90
elif in_code == 'CH':
p_proc_cost = cost * 0.50
in_proc_cost = cost * 0.50
else:
p_proc_cost = cost
in_proc_cost = 0
return p_proc_cost, in_proc_cost
#find medicine cost
def find_med_cost(in_code, med_cost):
if in_code == 'ZH':
p_med_cost = 0
in_med_cost = med_cost
elif in_code == 'HH':
p_med_cost = med_cost * 0.10
in_med_cost = med_cost * 0.90
elif in_code == 'CH':
p_med_cost = med_cost * 0.50
in_med_cost = med_cost * 0.50
else:
p_med_cost = med_cost
in_med_cost = 0
return p_med_cost, in_med_cost
#Display pat_info
def display_pat_info(pat_name, in_name):
print("City Hospital - Patient Invoice")
print("Patient Name: ", pat_name)
print("Insurance: ", in_name)
#display day cost
def display_day_cost(p_day_cost, in_day_cost):
print("Patient Day Cost: ", p_day_cost,"\tInsurance Day Cost: ", in_day_cost)
#display procedure cost
def display_proc_cost(p_proc_cost, in_proc_cost):
print("Patient Procedure Cost: ", p_proc_cost, "\tInsurance Procedure Cost: ", in_proc_cost)
#display medicine cost
def display_med_cost(p_med_cost, in_med_cost):
print("Patient Medicine Cost: ", p_med_cost, "\tInsurce Medicine Cost: ", in_med_cost)
#Display totals
def display_totals(total_pat, total_in):
print("Total Billed To Patient: ", total_pat, "\tTotal Billed To Insurance: ", total_in, "\tTotal Bill: ", (total_pat + total_in))
#display day_totals
def display_day_totals(total_zip, total_happy, total_cheap, total_pat):
print("City Hospital - End Of Day Billing Report")
print("Total Dollar Amount Billed Today: ", total_zip+total_happy+total_cheap+total_pat)
print("Total Billed To Zippy Healthcare: ", total_zip)
print("Total Billed To Happy Healthcare: ", total_happy)
print("Total Billed To Cheap Healthcare: ", total_cheap)
print("Total Billed To Uninsured: ", total_pat)
#display day_counts()
def display_day_counts(zip_count, happy_count, cheap_count, no_in_count):
print("The total amount of Zippy Healthcare patients is: ", zip_count)
print("The total amount of Happy Healthcare patients is: ", happy_count)
print("The total amount of Cheap Healthcare patients is: ", cheap_count)
print("The total amount of Uninsured patients is: ", no_in_count)
#def main
def main():
#Counters and accumulators
total_zip= 0.00
total_cheap= 0.00
total_happy= 0.00
total_pat= 0.00
zip_count= 0
cheap_count= 0
happy_count= 0
no_in_count= 0
total_in = 0
#Open file
try:
Pat_File = open('PatientBill.txt', 'w')
except ValueError:
print("*****ERROR***** - Corrupt File")
else:
file_exist = True
#Priming read
pat_name = input("Please enter the patients name: (XXX to stop program)")
#Processing loop
while pat_name != SENTINEL:
#Input data
in_code = get_in_code()
num_days = get_days()
proc_cost = get_cost()
med_cost = med_cost()
#find each cost
pat_day, insure_day = find_day_cost(in_code, num_days)
pat_proc, insure_proc = find_proc_cost(in_code, proc_cost)
pat_med, insure_med = find_med_cost(in_code, med_cost)
#update accumulators and totals
total_pat += pat_day + pat_proc + pat_med
if in_code == 'ZH':
zip_count += 1
total_zip += in_day_cost + in_proc_cost + in_med_cost
in_name = 'Zippy Healthcare'
elif in_code == 'HH':
happy_count += 1
total_happy += in_day_cost + in_proc_cost + in_med_cost
in_name = 'Happy Healthcare'
elif in_code == 'CH':
cheap_count += 1
total_cheap += in_day_cost + in_proc_cost + in_med_cost
in_name = 'Cheap Healthcare'
else:
no_in_count += 1
in_name = 'Uninsured'
total_in = total_zip + total_happy + total_cheap
#displays patients invoice
display_pat_info(pat_name,in_name)
display_day_cost(pat_day, insure_day)
display_proc_cost(pat_proc, insure_proc)
display_med_cost(pat_med, insure_med)
display_totals(pat_day + pat_proc + pat_med, insure_day + insure_proc + insure_med)
#Write output to file
if file_exist:
Pat_File.write(pat_name, pat_day+pat_med+pat_proc )
#Get next patients name
pat_name = input("Please enter the patients name: (XXX to stop program)")
#Close the output file
if file_exist:
Pat_File.close()
#display the accumlators and totals
display_day_totals(total_zip, total_happy, total_cheap, total_pat)
display_day_counts(zip_count,happy_count,cheap_count,no_in_count)
#define get_in_code
def get_in_code():
in_code = input("Please enter one of the insurance codes, ZH, CH, HH, XX")
while in_code not in ('ZH', 'HH', 'CH', 'XX'):
print("***Please enter a proper insurance code***")
in_code = input("Please enter one of the insurance codes, ZH, CH, HH, XX")
return in_code
main()
Python is a interpreted language. You need to define function prior to its usage. Just move a function definitions at the top of a file.
The problem is also with indentation. You're defining your methods inside while, just after a return statement. Actual functions aren't defined at all - interpreter doesn't reach those lines.
Besides, the code is "dirty". Split the code into separate classes/modules. Create well defined areas of responsibility, that would improve the code and it'll be easier to work with it.

pset2 Python Problem3-UsingBisectionSearch.py

I am completely new to Python, and I have lots of problems working out indentation, anyway I need someone to help me understand why my code not working...( The if condition is not recognizing the value from the inner while loop )
balance = 1000
annualInterestRate = 0.2
monthlyInterestRate = annualInterestRate /12
episilon = 0.01
numGuesses = 0
Low = balance / 12
High = (balance * (1 + monthlyInterestRate )**12) / 12.0
ans = (Low + High) / 2.0
newbalance = balance
monthlyPayment = ans
while newbalance > 0:
newbalance = balance
month = 0
while month < 12:
print('low = ' + str(Low) + ' high = ' + str(High) + ' ans = ' + str(ans))
newbalance -= monthlyPayment
interest = monthlyInterestRate * newbalance
newbalance += interest
month += 1
print month
if(newbalance > 0):
Low = ans
else:
High = ans
ans = (Low + High) / 2.0
print 'Lowest payment: ' + str(ans)
You should be deducting ans not monthlyPayment, setting monthlyPayment = ans outside the loop does not mean monthlyPayment will be updated when you set ans = (Low + High) / 2.0 inside the while loop each time, you are creating a new object each time:
while abs(newbalance) > 0.001: # check if we are withing +- .001 of clearing balance
newbalance = balance
month = 0
for month in range(12): # loop over 12 month range
print('low = ' + str(Low) + ' high = ' + str(High) + ' ans = ' + str(ans))
newbalance -= ans # deduct ans not the the original value set outside the while
interest = monthlyInterestRate * newbalance
newbalance += interest
print month
if newbalance > 0:
Low = ans
else:
High = ans
ans = (Low + High) / 2.0
print "Lowest Payment: {:.2f}".format(ans) # format to two decimal places
Also it is better to use for month in range(12), we know we only want to have 12 iterations so much simpler to use range.
Even if you were doing a ans += 2 your monthlyPayment would not be updated as ints are immutable so monthlyPayment would still only point to the original value of ans.
In [1]: ans = 10
In [2]: monthlyPayment = ans
In [3]: id(ans)
Out[3]: 9912448
In [4]: id(monthlyPayment) # still the same objects
Out[4]: 9912448
In [5]: ans += 10 # creates new object
In [6]: ans
Out[6]: 20
In [7]: monthlyPayment # still has original value
Out[7]: 10
In [8]: id(monthlyPayment) # same id as original ans
Out[8]: 9912448
In [9]: id(ans) # new id because it is a new object
Out[9]: 9912208

MIT opencourseware - stuck on a basic issue, credit card minimum payment over a year calculation

Basically I'm pretty stuck on this issue, I've linked the question below, it's part 'b' I'm stuck on, or the second question in the document:
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00sc-introduction-to-computer-science-and-programming-spring-2011/unit-1/lecture-4-machine-interpretation-of-a-program/MIT6_00SCS11_ps1.pdf
If I'm honest it's just got to the point where I'm totally confused! I've put my code below:
balance = float(raw_input('Vot is the outstanding balance? '))
InrAn = float(raw_input('Vot is the annual interest rate as a decimal? '))
month = 1
monthPay = 10
monthInr = InrAn/12.0
newBalance = balance
while balance > 0:
newBalance = newBalance * (1 + monthInr) - monthPay
month +=1
if month > 12:
month = 1
newBalance = balance
monthPay += 10
This does essentially nothing, I know, and it's not yet complete. If I add a 'print month' statement it just seems to show that the code just goes up to 12, then starts at 1 again. Any tips/prods in the right direction?
monthly_payment = 10.0
while True:
current_balance = start_balance
for month in range(1, 13):
current_balance = current_balance * (1. + monthly_rate) - monthly_payment
current_balance = round(current_balance, 2)
if current_balance <= 0.0:
break
if current_balance <= 0.0:
print("RESULT")
print("Monthly payment to pay off debt in 1 year: {}".format(int(monthly_payment)))
print("Number of months needed: {}".format(month))
print("Balance: {:0.2f}".format(current_balance))
break
monthly_payment += 10.0

Categories

Resources