Replacing Iteration with Recursion Python [duplicate] - python

This question already has answers here:
Is this function recursive even though it doesn't call itself?
(3 answers)
Closed 5 years ago.
I'm just starting to learn about recursion for an EdX course, and I've written an iterative function to calculate the remaining balance after paying the minimum required payment for 12 months.
I was able to easily do it with iteration, but I can't seem to wrap my head around the recursive way.
Please point me in the right direction.
Here is my iterative function
def remaining_balance_iter(balance,annualInterestRate, monthlyPaymentRate ):
'''
This code will take any balance and annual interest rate and calculate the
balance after one year of making the minimum payments
'''
month = 1
monthly_interest_rate = annualInterestRate/12.0
while month <= 12:
minimum_monthly_payment = monthlyPaymentRate * balance
monthly_unpaid_balance = balance - minimum_monthly_payment
balance = monthly_unpaid_balance + monthly_interest_rate*monthly_unpaid_balance
print( "Month {} Remaining balance: ".format(month) + str(round(balance,2)))
month += 1
print ("Remaining balance " + str(round(balance,2)))
I've made an attempt at a recursive function, but it needs work, and I need tutoring haha
def remaining_balance_recur(balance,annualInterestRate, monthlyPaymentRate, month ):
'''
This code will take any balance and annual interest rate and calculate the
balance after one year of making the minimum payments
'''
month = 1
monthly_interest_rate = annualInterestRate/12.0
while month <= 12:
minimum_monthly_payment = monthlyPaymentRate * balance
monthly_unpaid_balance = balance - minimum_monthly_payment
interest = monthly_interest_rate*monthly_unpaid_balance
balance = remaining_balance_recur(monthly_unpaid_balance, annualInterestRate, monthlyPaymentRate, month + 1) + interest
print ("Remaining balance " + str(round(balance,2)))

The best way I've found to deal with recursion is to start by specifying a base case. What is the condition that tells you when you've finished your method? In your code, it looks like you run your method until `month > 12', so your base case would be:
if month > 12:
return 1 # 1 for the purpose of explanation
Your return value for your base case is some base value of your function. What would your script return if your month was 12? That's the value you would return.
Next is the hard part. You have to figure out what variable is being modified by subsequent calls to your method. I'm not exactly sure what your code is intended to do, but it looks like you have a few calculations on some variables. When you use recursion, it's almost as if you're saving the state of the current method call you are executing while you go and retrieve the value you need for your statement. (e.g. a_num = 1 + recurse(n - 1) - you need the value of recurse(n - 1) before you can continue with this statement. This is only an example, though). Look for the variable that is affected by your previous iterations and try to make that recursive. In your situation, it looks like balance is that variable:
balance = balance + remaining_balance_recur(annualInterestRate, monthlyPaymentRate, month + 1)
return balance
When you write a recursive method, you always need to return some value at the end of the method, so the statement that called the method actually gets a value. Here's a short, useless example:
def recurse(n)
if n == 0 # BASE CASE
return 1
some_sum = 0
some_sum += recurse(n - 1) # I need the value from recurse(n - 1)
return some_sum # This method was called somewhere, so it needs to return
Try to figure out a recursive solution for your code from these hints. I'm sorry, recursion is very hard to explain especially over SO. Youtube vids and Google would also be a big help to understand recursion in general. Hope this gave you some ideas.

By putting "month = 1" before the while statement, you are resetting it so that while month <= 12 will run forever. This creates a "RecursionError: maximum recursion depth exceeded in comparison."
The output of your function is currently "NoneType" because its output is a print statement rather than returning an int or a float. This produces a "TypeError" because you have tried to add a float (the interest rate) to a NoneType (the printed statement) in your recursion.

Related

Looping problem Elden ring runes per level calculation

This code is currently showing the total amount needed to reach the next level, but what I would like it to do is show the complete total amount so for example if you pick 50 the total amount needed from level 1 to 50. Looping through the calculation from 50 to 1 and only showing the sum of that total. and hereby I mean only showing the total amount of runes needed to reach level 50 for example, but I seem to get the entire list for each level. I, unfortunately, can't seem to find the right way to do this online, so I would try my luck here. any help is appreciated.
def total_runes_per_lvl(lvl):
list = []
for i in range(lvl):
runes = 0.02*(lvl)**3 + 3.06*(lvl)**2 + 105.6*(lvl) - 895
list.append(runes)
lvl -= 1
print(sum(list))
total_runes_per_lvl(50)
15102.68
14535.0
28514.440000000002
41950.32
54854.520000000004
67238.8
etc`
should only be one number: 277.571
Your identation is incorrect, and you're decrementing lvl even though there's already an iterator on it.
def total_runes_per_lvl(lvl):
total = 9381
for i in range(13,lvl+1):
runes = 0.02*(i+1)**3 + 3.06*(i+1)**2 + 105.6*(i+1) - 895
total += int(runes)
print(total)
total_runes_per_lvl(16) # 15605
total_runes_per_lvl(50) # 277574
Edit: since the formula works accurately after level 12, I've hardcoded the value for the total of first 12 levels. The formula works as expected, though it still isn't accurate.

How to make my program start at 1 and double that amount and also print the total

My problem is that my code starts 1 day at 2 pennies, it should start at 1. I also would like to know how to print the total amount of pennies. Here is the code I have so far:
daysworked = int(input("Enter the amount of days you worked: "))
pay = 1
print("Day\tPay")
print("-----------------")
for daysworked in range (1, daysworked+1):
endpay = pay * 2
print(daysworked, "\t", endpay)
pay = endpay
If you want to print out the total amount of money the user has earned over the course of the days they worked, you can create a variable: total, which is the sum of all the payments earned per day.
Also, since on the first day, you don't want to double your value, we can simply print out the first value before the loop (skipping an iteration of your loop, hence the -1), or start our variable pay at 0.5.
To integrate this into your code, we can utilize the for loop you implemented and simply add up all the endpay values.
Other minor changes you could make: As #S3DEV mentioned, it is unnecessary to create a secondary variable to store updated payment, you can simply update the variable pay! We could also edit the for loop to just take in one parameter, the daysworked, instead of a starting and ending value. In Python, it is also recommended that if your variable names are multiple words long, separate them with an underscore.
With these changes included, your code could look something like this:
days_worked = int(input("Enter the amount of days you worked: "))
pay = 1
total = 1
print("Day\tPay")
print("-----------------")
print(1,pay)
for days_worked in range (days_worked - 1):
pay *= 2
total += pay
print(days_worked + 1, "\t", pay)
print("Total Payment:" , total)
Different Solution: (This solution will result in float answers since pay starts at .5, so you can cast to an int):
days_worked = int(input("Enter the amount of days you worked: "))
pay = .5
total = 0
print("Day\tPay")
print("-----------------")
for days_worked in range (days_worked):
pay *= 2
total += pay
print(days_worked, "\t", int(pay))
print("Total Payment:" , int(total))
I hope this helped with your problem! Let me know if you need any further clarification or details :)
I'm guessing you don't want to print in every iteration, and that's what you are asking. Just unindent that print line so it executes at the end of the loop. Also I removed superfluous variable.
daysworked = int(input("Enter the amount of days you worked: "))
pay = 1
print("Day\tPay")
print("-----------------")
for daysworked in range (1, daysworked+1):
pay = pay * 2
print(daysworked, "\t", pay)
daysworked = int(input("Enter the amount of days you worked: "))
pay = 1
endpay = 0
print("Day\tPay")
print("-----------------")
for dayworked in range (1, daysworked+1):
pay *= 2
print(dayworked, "\t", endpay)
endpay += pay
print(endpay)
Have a look at two things here.
First, you need to add one more variable to keep track of the sum, endpay in this case, which you have to print at the end. Although, in this case, endpay will always be the double of the last value of pay less two. ;) The last line could as well have been written print(2 * pay - 2) and get rid of the lines using 'endpay'.
Second the difference between daysworked and dayworked (you could have used i or any other variable name here as well).

Coffee Machine - invalid syntax and End of Statement expected in new function

So I'm trying to create a coffee machine program (you choose a drink, the machine checks the ingredients, the resources and the money you insert, then it dispenses the drink.) and it went okay until I got to the part where the program processes the coins and, if sufficient, adds them to the amount of money in the machine.
I'm not really good with return statements and global vs local scopes, so I assume they are the issue. I tried googling, but nothing came up that actually solves the specific problem I have.
This is the code for the function in question:
def process_coins(order, money):
print("Please insert coins.")
quarters = float(input("Quarters: ")) * quarters_value
dimes = float(input("Dimes: ")) * dimes_value
nickles = float(input("Nickles: ")) * nickles_value
pennies = float(input("Pennies: ")) * pennies_value
total = quarters + dimes + nickles + pennies
if total < MENU[order]["cost"]:
total = 0
return print("Sorry, that's not enough money. Money refunded.")
else:
return money += total
PyCharm tells me "End of Statement expected" and "invalid Syntax" for the last line.
When I remove "return" it runs but doesn't actually add the total to the money in the machine. I also tried putting brackets around money += total, which turns both problems into "unexpected expression syntax".
I honestly don't understand why this doesn't work. I just want pycharm to add "total" (local scope) to "money"(global scope) and to return it so I can use it in the rest of the code.
I also don't understand why this function wasn't able to work with the variable "money" before I added it as an argument in the brackets, but it was able to work with the variables "dimes_value" etc. just fine, even though those are mentioned just one line before "money" at the start of the code and aren't part of the arguments in the bracket of the function.
What am I missing?
The problem is that return can only return expressions, but an augmented assignment is a statement. This is why you get a syntax error.
For Python >= 3.8, you can use an assignment expression to overcome this:
return (money := money + total)
* Note the necessary parenthesis.
This will both assign to money and return the value assigned to it.
But this will create a new problem: money will now be considered a local variable (because you assign to it inside the function) and you'll get a different error.
To overcome this, you will need to declare
global money
At the start of the function.
But really the best solution here is not to use global variables at all, simply return money + total, and assign the returned value in the global scope, where you call the function.
if total < MENU[order]["cost"]:
total = 0
return print("Sorry, that's not enough money. Money refunded.")
else:
money += total
return money

What's the problem in this short user-defined function?

It says that "salary" is not defined or that i can't multiply this.
I want to have it with the def command so please just let it in this form just correct the mistakes, im completely new to it so just let it as easy as it is. Thank you very much :)
def computepay(Hours,RatePerHour):
if float(Hours)-40<0:
salary=float(Hours)*float(RatePerHour)
else:
salary=40.0*float(RatePerHour)+(float(Hours)-40.0)*float(RatePerHour*1.5)
Hours=input("Hours:\n")
RatePerHour=input("RatePerHour:\n")
computepay(Hours,RatePerHour)
print("Salary:")
print(salary)
I expect that someone could help me how this little program works correct
You need to return salary and then assign this to a variable. Here's an improved version of your code:
def compute_pay(hours: float, rate_per_hour: float) -> float:
if hours - 40 < 0:
salary = hours * rate_per_hour
else:
salary = 40 * rate_per_hour + (hours - 40.0)* rate_per_hour * 1.5
return salary # This is the line you are missing!
hours = input("Hours:\n")
rate_per_hour=input("RatePerHour:\n")
computer_salary = computepay(float(hours), float(rate_per_hour)) # You also need to assign the output of a function to a variable, I've given it a different name from salary just to show you that this is a different variable from the one inside your function. Also, cast to float here so you don't have to do it all over your function.
print(f"Salary: {computer_salary}")
The concept you need to learn here is called scope.
You needed to return the calculated salary.
Also, simpler if you performed the float conversion on input.
def computepay(Hours,RatePerHour):
if float(Hours)-40<0:
salary=Hours*RatePerHour
else:
salary=40.0*RatePerHour+ (Hours-40.0)*(RatePerHour*1.5)
return salary # return value
Hours = float(input("Hours:\n")) # float conversion
RatePerHour = float(input("RatePerHour:\n")) # float conversion
salary = computepay(Hours,RatePerHour)
print("Salary:")
print(salary)
Here is the correction, and some explications follow.
def computepay(Hours,RatePerHour):
salary = 0
if float(Hours)-40<0:
salary=float(Hours)*float(RatePerHour)
else:
salary=40.0*float(RatePerHour)+(float(Hours)-40.0)*float(RatePerHour) *1.5) #<=== here you multiply with out turning rateperhour as float
return salary
Hours=input("Hours:\n") RatePerHour=input("RatePerHour:\n")
salary = computepay(Hours,RatePerHour)
print("Salary:")
print(salary)
First, salary is a variable enclosed inside your function, it's not a avaliable outside of it.
Second, you get an error because you multiply a string by an integer. Convert it to float before.
float(RatePerHour*1.5) #wrong
float(RatePerHour) *1.5 # correct

how to re-initiate iteration after changing a variable

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

Categories

Resources