I am trying to build a cost model using mostly if statements but I keep getting the error:
NameError: name 'spread_1' is not defined.
I am a beginner with python so I don't know if I've done something incorrect. Please help.
#water depth of project site in metres
water_depth = 100
#platform wells require jackups
pl = 1
#1-2 complexity required LWIV
ss_simple = 1
#3-4 complexity requires rig
ss_complex = 0
#day rates
vjackup = 75000
jackup = 90000
vsemi = 170000
semi = 300000
lwiv = 200000
#determining vessel spread for platform wells
if pl >= 1:
if water_depth == range(0, 50):
spread_1 = vjackup * 24.1
elif water_depth == range(51, 150):
spread_1 = jackup * 24.1
elif pl == 0:
spread_1 = 0
You should replace the == with in at the
if water_depth == range(0, 50):
and
elif water_depth == range(51, 150):
making your block of code:
if pl >= 1:
if water_depth == range(0, 50):
spread_1 = vjackup * 24.1
elif water_depth == range(51, 150):
spread_1 = jackup * 24.1
elif pl == 0:
spread_1 = 0
into
if pl >= 1:
if water_depth in range(0, 50):
spread_1 = vjackup * 24.1
elif water_depth in range(51, 150):
spread_1 = jackup * 24.1
elif pl == 0:
spread_1 = 0
But it would be more practical to use extreme equality operators in your case:
if pl >= 1:
if 0 <= water_depth < 50:
spread_1 = vjackup * 24.1
elif 51 <= water_depth < 150:
spread_1 = jackup * 24.1
elif pl == 0:
spread_1 = 0
Do note that the range() function omits the end value, so range(0, 50)'s last value would be 49, not 50.
I am trying to find best savings rate per month using bisection search with given semi annual raise and rate of return on investment. The code runs on infinite loop.
# cost of the house
total_cost = 1000000
portion_down_payment = 0.25 * total_cost
current_savings = 0
annual_salary = int(input("enter your starting salary: "))
starting_salary = annual_salary / 12
semi_annual_raise = 0.07
# annual rate of return on investment is 4%
inv_rate = 0.04 / 12
months = 0
low = 0
high = 10000
number_steps = 0
# finding current savings using Bisection search
while abs((current_savings*36) - portion_down_payment) >= 100:
number_steps += 1
starting_salary = annual_salary / 12
for months in range(1, 37):
current_savings += (starting_salary * inv_rate)
# semi annual raise of 7 %
if months % 6 == 0:
starting_salary += starting_salary * 0.07
if current_savings * 36 < portion_down_payment:
low = current_savings
else:
high = current_savings
current_savings = (high + low) / 2
print("number of steps taken by bisection search is :", number_steps)
# printing savings rate
print(current_savings / starting_salary)
The following code is supposed to calcualte what the savings rate would be to pay off my down payment in exactly 36 months given certain factors like (salary raises and annual return rates. I am having trouble getting the output of the range function to interact with my bisection search method.
# Cost
total_cost = 1000000
portion_down_payment = .25 * total_cost
# Salary
annual_salary = 150000
semi_annual_raise = .07
annual_return_rate = .04
current_savings = 0
month = 0
# Bisection
epsilon = 100
num_guesses = 0
low = 0
high = 1
saving_rate = (high + low) / 2.0
portion_saved_monthly = annual_salary / 12 * saving_rate
# range()function
for x in range(36):
current_savings += (current_savings * annual_return_rate / 12) + portion_saved_monthly
month += 1
if month % 6 == 0:
annual_salary += annual_salary * semi_annual_raise
portion_saved_monthly = annual_salary / 12 * saving_rate
while abs(current_savings - portion_down_payment) >= epsilon:
if current_savings < portion_down_payment:
low = saving_rate
else:
high = saving_rate
saving_rate = (high + low) / 2.0
num_guesses += 1
print('Best savings rate: ', saving_rate)
print('Steps in bisection search: ', num_guesses)
I started with the while loop and nested the for loop inside. I also moved some variables inside the while loop which helped me get the right answer.
'''
# Cost of House
total_cost = 1000000
portion_down_payment = .25 * total_cost
# Salary
annual_salary_input = float(input('Enter the starting salary: '))
current_savings = 0
# Bisection
epsilon = 100
num_guesses = 0
low = 0
high = 1
saving_rate = (high + low) / 2.0
portion_saved_monthly = annual_salary_input / 12 * saving_rate
while abs(current_savings - portion_down_payment) >= epsilon:
annual_salary = annual_salary_input
semi_annual_raise = .07
annual_return_rate = .04
current_savings = 0
month = 0
portion_saved_monthly = annual_salary / 12 * saving_rate
saving_rate = (high + low) / 2.0
# Loop
for x in range(36):
current_savings += (current_savings * annual_return_rate / 12) + portion_saved_monthly
month += 1
if month % 6 == 0:
annual_salary += annual_salary * semi_annual_raise
portion_saved_monthly = annual_salary / 12 * saving_rate
if current_savings < portion_down_payment:
low = saving_rate
else:
high = saving_rate
saving_rate = (high + low) / 2.0
num_guesses += 1
if num_guesses > 1000:
break
if saving_rate < 1.0:
print('Best savings rate: ', "%.4f" % saving_rate)
print('Steps in bisection search: ', num_guesses)
else:
print('It is not possible to pay the down payment in three years.')
'''
My use-case is as follows:
I want to make an electric bill generator with different units having different prices. In below program, if the user enters units between 1-150 then for making price value it will do multiplication with 2.50 and make a price. If the user Units are between the 151-300 then it will multiply the first 150 units with 2.50 and left units will multiply with the 3.60 means to say If user entered 155 then for first 150 150 * 2.50 and for left units 5 it will do multiplication 5 * 3.60. like the above I said I'm making like this four variations given Below:-
if units lies between 1-150 then it will multiplies with the 2.50 and calculates the price.
if units lies between 151-300 then it will multiplies first 150 units with the price 2.50 and left units below the 300 will multiply with the 3.60 and calculates the price.
if units lies between 301-450 then it will multiplies first 150 units with the price 2.50 and other 150 units will multiplies with the 3.60 and left units are multiplies with the 4.75 and calculates the price.
if units lies between 451-600 then it will multiplies first 150 units with the price 2.50 and other 150 units will multiplies with the 3.60 and other 150 units are multiplies with the 4.75 and left units are multiplies with the 5 and calculates the price.
if units lies above 600 then it will multiplies first 150 units with the price 2.50 and other 150 units will multiplies with the 3.60 and other 150 units are multiplies with the 4.75 and next 150 units are multiplies with the 5 and left units are multiplies with the 6 and calculates the price.
Here is my code which is seek to optimize, i.e. shorten:
units = int(input("Enter the units"))
if(1<=units and 150>=units):
firstSum = units * 2.50
print("First sum:-", firstSum)
if(151<=units and 300>=units):
firstSum = 150 * 2.50
subUnits = units - 150
secondSum = firstSum + (subUnits * 3.60)
print(secondSum)
if(301<=units and 450>=units):
firstSum = 150 * 2.50
subUnits1 = units - 150
firstSum += 150 * 3.60
subUnits = subUnits1 - 150
secondSum = firstSum + subUnits * 4.75
print(secondSum)
if(451<=units and 600>= units):
firstSum = 150 * 2.50
subUnits1 = units - 150
firstSum += 150 * 3.60
subUnits1 -= 150
firstSum += subUnits1 * 4.75
subUnits = subUnits1 - 150
secondSum = firstSum + subUnits * 5
print(secondSum)
if(601<=units):
firstSum = 150 * 2.50
subUnits1 = units - 150
firstSum += 150 * 3.60
subUnits1 -= 150
firstSum += subUnits1 * 4.75
subUnits2 = subUnits1 - 150
firstSum += 150 * 5
subUnits = subUnits2 - 150
secondSum = firstSum + subUnits * 6
print(secondSum)
Can any one help me to make my program in short way.
Thank you for your precious time
If I understand well your problem, I don't think your code is doing the right thing for the two last cases. It looks like a wrong copy/paste of the previous cases ;)
I think that for the two last cases you should have :
if(451<=units and 600>= units):
firstSum = 150 * 2.50
subUnits1 = units - 150
firstSum += 150 * 3.60
subUnits1 -= 150
firstSum += 150 * 4.75
subUnits = subUnits1 - 150
secondSum = firstSum + subUnits * 5
print(secondSum)
if(601<=units):
firstSum = 150 * 2.50
subUnits1 = units - 150
firstSum += 150 * 3.60
subUnits1 -= 150
firstSum += 150 * 4.75
subUnits2 = subUnits1 - 150
firstSum += 150 * 5
subUnits = subUnits2 - 150
secondSum = firstSum + subUnits * 6
print(secondSum)
To answer your question, if I understood well, you can do something like :
units = int(input("Enter the units : "))
factor_list = [2.5, 3.6, 4.75, 5]
last_factor = 6
upper_bound = 600
step = 150
SUM = 0
if (units > upper_bound):
SUM += (units-upper_bound)*last_factor
units = upper_bound
nb150 = units/step
for i in range(0,int(nb150)):
SUM += step*factor_list[i]
if(int(nb150) < len(factor_list)):
SUM += (units-int(nb150)*step)*factor_list[int(nb150)]
print(SUM)
This solution simply avoid the multiple if statements by computing the euclidean division of units. That way you can easily change the coefficients or add others without needing to write other cases.
The first if statement takes care of all the units that are greater than the upper bound. It basically multiplies all the units above 600 with 6 and remove them from the units to be handled.
By the line nb150 = units/step and taking the integer part, I obtain the number of groups of 150 units. Then I can multiply them by their corresponding coefficient in the for loop.
Finally, if the number of units is lower than 600 but not a multiple of 150, the code needs to take care of the rest. So it removes the groups of 150 : (units-int(nb150)*step), then multiplies the rest with the corresponding factor factor_list[int(nb150)].
If you need further explanation, feel free to ask !
Talking about optimization, there's quite less you can do in order to optimize the code...
You can definitely optimize it by using if-elif-else conditional statements instead of using just if :
if(1<=units and 150>=units):
...
elif(151<=units and 300>=units):
...
:
:
else:
...
When you are doing so, you are making sure that the condition checking doesn't happen after the right condition is reached. Thereby, reducing the number of comparisons done and optimizing the program.
Special reason why you need it shortened? Anyway you might start by refactoring repeating code blocks into methods. For example
firstSum = 150 * 2.50
subUnits1 = units - 150
firstSum += 150 * 3.60
subUnits = subUnits1 - 150
Happens three times.
Also is there a special reasons for all the if statements instead of elif? Not that it would make the code shorter.
If you don't mind the unreadability here is your one-liner:
print(units * 2.5 + max(0, units - 150) * 1.1 + max(0, units - 300) * 1.15 + max(0, units - 450) * 0.25 + max(0, units - 600))
Also your example code is buggy on line 23 (firstSum += subUnits1 * 4.75), it should multiply with another 150 there.
Given your code (regardless your description); you can shorten your code by doing the math, e.g.:
def bill_generator(units):
firstSum = min(units, 150) * 2.5
if units <= 300:
secondSum = firstSum + units * 3.60 - 540.0
elif units <= 450:
firstSum += 540
secondSum = firstSum + units * 4.75 - 1425.0
elif units <= 600:
firstSum = 540 + units * 4.75 - 1425.0
secondSum = firstSum + units * 5.0 - 2250.0
else:
firstSum = 150.0 * 11.1 + units * 4.75 - 1425.0
secondSum = firstSum + units * 6.0 - 3600.0
print("FirstSum:-{}".format(firstSum))
if units > 150:
print(secondSum)
if __name__ == '__main__':
inp_units = int(input("Enter the units: "))
while inp_units < 1:
print("invalid input, units must be greater than zero")
inp_units = int(input("Enter the units"))
Tested the border cases:
def bill_generator(units):
firstSum = min(units, 150) * 2.5
if units <= 300:
secondSum = firstSum + units * 3.60 - 540.0
elif units <= 450:
firstSum += 540.0
secondSum = firstSum + units * 4.75 - 1425.0
elif units <= 600:
firstSum += 540.0 + units * 4.75 - 1425.0
secondSum = firstSum + units * 5.0 - 2250.0
else:
firstSum = 1665.0 + units * 4.75 - 1425.0
secondSum = firstSum + units * 6.0 - 3600.0
print("FirstSum:-{}".format(firstSum))
if units > 150:
print(secondSum)
if __name__ == '__main__':
for ii in [1, 150, 151, 300, 301, 450, 451, 600, 601, 1200]:
print('Testing for unit input "{}"'.format(ii))
bill_generator(ii)
'''
Testing for unit input "1"
FirstSum:-2.5
Testing for unit input "150"
FirstSum:-375.0
Testing for unit input "151"
FirstSum:-375.0
378.6
Testing for unit input "300"
FirstSum:-375.0
915.0
Testing for unit input "301"
FirstSum:-915.0
919.75
Testing for unit input "450"
FirstSum:-915.0
1627.5
Testing for unit input "451"
FirstSum:-1632.25
1637.25
Testing for unit input "600"
FirstSum:-2340.0
3090.0
Testing for unit input "601"
FirstSum:-3094.75
3100.75
Testing for unit input "1200"
FirstSum:-5940.0
9540.0
'''
You are adding your values to variables again and again in newlines rather than binding them up in a single line. Your shorted code can be as:
units = int(input("Enter the units: "))
if 1<=units and 150>=units:
print("First sum:-", units * 2.50)
elif 300>=units:
print((150 * 2.50) + ((units - 150) * 3.60))
elif 450>=units:
print(((150 * 2.50)+150 * 3.60) + ((units - 300) * 4.75))
elif 600>= units:
print((((150 * 2.50) + 150 * 3.60) + (units - 300) * 4.75) + ((units - 300) - 150 ) * 5)
else:
print(((((150 * 2.50) +150 * 3.60)+(units - 300) * 4.75)+150 * 5) + (((units - 300) - 150) - 150) * 6)
I'm currently running Python 3.5 on Mac and I can't seem to find a way to be more efficient with my code.
In all I'm currently making a wheel of fortune game (or basically hangman), and I have it so that when the user clicks on a letter it checks if the letter is in the word etc.
Is there a better way than writing 26 if statements and checking coordinates each time? Is there a more efficient way of checking for coordinates using if statements?
while True:
mouse = win.getMouse()
if 35 < mouse.x < 65 and 85 < mouse.y < 115:
ans = "a"
break
elif 65 < mouse.x < 95 and 85 < mouse.y < 115:
ans = "b"
break
elif 95 < mouse.x < 125 and 85 < mouse.y < 115:
ans = "c"
break
elif 125 < mouse.x < 155 and 85 < mouse.y < 115:
ans = "d"
break
elif 155 < mouse.x < 185 and 85 < mouse.y < 115:
ans = "e"
break
elif 185 < mouse.x < 215 and 85 < mouse.y < 115:
ans = "f"
break
elif 215 < mouse.x < 245 and 85 < mouse.y < 115:
ans = "g"
break
elif 245 < mouse.x < 275 and 85 < mouse.y < 115:
ans = "h"
break
elif 275 < mouse.x < 305 and 85 < mouse.y < 115:
ans = "i"
break
elif 305 < mouse.x < 335 and 85 < mouse.y < 115:
ans = "j"
break
elif 35 < mouse.x < 65 and 115 < mouse.y < 145:
ans = "k"
break
elif 65 < mouse.x < 95 and 115< mouse.y < 145:
ans = "l"
break
elif 95 < mouse.x < 125 and 115 < mouse.y < 145:
ans = "m"
break
elif 125 < mouse.x < 155 and 115 < mouse.y < 145:
ans = "n"
break
elif 155 < mouse.x < 185 and 115 < mouse.y < 145:
ans = "o"
break
elif 185 < mouse.x < 215 and 115 < mouse.y < 145:
ans = "p"
break
elif 215 < mouse.x < 245 and 115 < mouse.y < 145:
ans = "q"
break
elif 245 < mouse.x < 275 and 115 < mouse.y < 145:
ans = "r"
break
elif 275 < mouse.x < 305 and 115 < mouse.y < 145:
ans = "s"
break
elif 305 < mouse.x < 335 and 115 < mouse.y < 145:
ans = "t"
break
elif 35 < mouse.x < 65 and 145 < mouse.y < 175:
ans = "u"
break
elif 65 < mouse.x < 95 and 145 < mouse.y < 175:
ans = "v"
break
elif 95 < mouse.x < 125 and 145 < mouse.y < 175:
ans = "w"
break
elif 125 < mouse.x < 155 and 145 < mouse.y < 175:
ans = "x"
break
elif 155 < mouse.x < 185 and 145 < mouse.y < 175:
ans = "y"
break
elif 185 < mouse.x < 215 and 145 < mouse.y < 175:
ans = "z"
break
As simple solution using a calculation vs. multiple if statements:
import string
while True:
mouse = win.getMouse()
x, xr = divmod(mouse.x-35, 30)
y, yr = divmod(mouse.y-85, 30)
if not(0 <= x < 10 and 0 <= y < 3): # Guard values
continue
if xr == 0 or yr == 0: # Gridlines?
continue
try:
ans = string.ascii_lowercase[10*y+x]
break
except IndexError:
pass
e.g. mouse(x=102, y=143) would return 'm'
You could use the following code to avoid the big if statement.
def check_pos(x, y):
table = 'abcdefghijklmnopqrstuvwxyz'
idx = (x - (35-30)) / 30
idy = (y - (85-30)) / 30
# each row has 10 cells
offset = idx + (idy -1) * 10
if 1 <= offset <= 26:
return table[offset-1]
import string
alpha=string.ascii_lowercase
mouse = win.getMouse()
for idx,i in enumerate(range(35,335,30)):
if mouse.x>i and mouse.x<i+30:
if mouse.y>85 and mouse.y<115:
ans=alpha[idx]
break
elif mouse.y>115 and mouse.y<145:
ans=alpha[idx + 10]
break
elif mouse.y>145 and mouse.y<175:
ans=alpha[idx+20]
break