Number of recursive function calls - python

I'm a total beginner at Python and I was wondering how to get the number of recursive function calls ?
is it 2^n (if n is the argument given)

The amount of calls completely depends on the algorithm. Sometimes it is 2**n, but other times it could be n! or a quadratic, or anything else.
To work out how many it is, you can you use my method. This might get shunned by some other users, but using a global counter is a quick and easy way to count the amount of function calls.
function_calls = 0
def fibonacci_recursive(n):
global function_calls
function_calls += 1
if n == 0:
return 1
elif n == 1:
return 1
else:
return fibonacci_recursive(n-1) + fibonacci_recursive(n-2)
ans = fibonacci_recursive(20)
print("There were",function_calls,"function calls.")

Related

local variable 'i' referenced before assignment

Trying out some recursion based questions, came across this error.
'i' is the number of digits, which increments by 1. Where have I gone wrong?
determine no. of digits by repeated div by 10
i = 0
def dig(n):
if n < 10:
i += 1
return
else:
i += 1
dig(n//10)
print(i)
dig(123)
Your code has several issues. You define i outside your function, but only use it inside the function, that's causing the main issue. However, your function also has several logic errors.
It looks like you were going for:
def dig(n):
if n < 10:
return 1
else:
return 1 + dig(n//10)
print(dig(123))
But if you really want to use a global variable to 'count' the digits:
digits = 0
def dig(n):
global digits
digits += 1
if n > 10:
dig(n//10)
return digits
print(dig(123))
Note that this has the problem that it only works once. If you call it again, you'll have to reset digits to 0 again first. It's not the best way to go and avoiding globals is generally a good idea.
If you need your function to include the call to print() instead of printing the result, you can modify the first solution like this:
def dig(n, c=1):
if n < 10:
print(c)
else:
dig(n//10, c+1)
dig(123)
But generally it tends to be more useful to have a function that returns a result, so it can be used in other places, instead of just printing a result once.
You indicated you need to store the count in a variable, which makes little sense if you were also asked to write a recursive function. Without recursion, it would look more like:
def dig(n):
digits = 1
while n > 10:
n = n // 10
digits += 1
return digits
print(dig(123))
Here is the correct recursive function:
def dig(n, i = 0):
#base case
if n < 10:
return i + 1
#recursion
return dig(n//10, i + 1)
print(dig(123))
#output: 3

Finding multiples using recursion

Given 1 to 100 numbers, for multiples of 3 it should print "he" ,for multiples of 5 it should print "llo" ,for both multiples of 3 and 5 it should print "hello".
This is what I have:
for i in range (1,100):
if(i%3==0):
print("he")
elif(i%5==0):
print("llo")
elif(i%3==0 and i%5==0):
print("hello")
How would I do this recursively?
How about the code below?
def find_multiples(current, last_num=100):
# Base Case
if current > last_num:
return
result = ""
if current % 3 == 0:
result += "he"
if current % 5 == 0:
result += "llo"
if result:
print(f"{current}: {result}")
find_multiples(current+1, last_num)
find_multiples(1)
Base case is if current reaches last_num or the maximum number you'd like to check.
Here is a general outline for doing simple recursive things in python:
BASE_CASE = 1 #TODO
def f(current_case):
if current_case == BASE_CASE:
return #TODO: program logic here
new_case = current_case - 2 #TODO: program logic here ("decrement" the current_case somehow)
#TODO: even more program logic here
return f(new_case) + 1 #TODO: program logic here
Of course, this doesn't handle all possible recursive programs. However, it fits your case, and many others. You would call f(100), 100 would be current_value, you check to see if you've gotten to the bottom yet, and if so, return the appropriate value up the call stack. If not, you create a new case, which, in your case, is the "decrement" logic normally handled by the "loop" construct. You then do things for the current case, and then call the function again on the new case. This repeated function calling is what makes it "recursive". If you don't have an "if then" at the beginning of the function to handle the base case, and somewhere in the function recall the function on a "smaller" value, you're probably going to have a bad time with recursion.
This recursive function prints multiples of a number! hope it helps
def multi(n,x):
if x == 12:
print(n*x)
else :
print(n*x,end =",")
multi(n,x+1)
print(multi(4,1));

recursive function to sum of first odd numbers python

I'm trying to convert below code to recursive function but seems i'm quite confusing how could i write below in recursive function. could help me to give some thoughts?
Basically, what I'm generating below is the sum of the first n odd numbers.
def sum_odd_n(n):
total=0
j=2*n-1
i=1
if i>j:
return 1
else:
total =((j+1)/2)**2
i+=2
return total
> >>> sum_odd_n(5)
> 25.0
> >>> sum_odd_n(4)
> 16.0
> >>> sum_odd_n(1)
> 1.0
This smells somewhat like homework so I'm going to offer some advice instead of a solution.
Recursion is about expressing a problem in terms of itself.
Suppose you know the sum of the odd numbers from N to N - 2.
Can you write the total sum in terms of this sum and the function itself (or a related helper function)?
Recursive functions have at least one base case and at least one recursive call. Here are some hints:
def f(n):
# Base case - for which
# n do we already know the answer
# and can return it without
# more function calls? (Clearly,
# this must also terminate any
# recursive sequence.)
if n == ???:
return ???
# Otherwise, lets say we know the answer
# to f(n - 1) and assign it to
# the variable, 'rest'
rest = f(n - 1)
# What do we need to do with 'rest'
# to return the complete result
return rest + ???
Fill out the question marks and you'll have the answer.
Try:
def sum_of_odd(n):
if n>0:
x=(n*2)-1
return x+sum_of_odd(n-1)
else:
return 0
The answer of this:
sum_of_odd(5)
will be:
25
Try :
def sum_odd_n(n):
if n>0:
if n==1:
return 1
else:
return 2*n-1 + sum_odd_n(n-1)

Variable Scope Issue in Python

I am new to Python and I have been working with it for a bit, but I am stuck on a problem. Here is my code:
def collatz(num,ctr):
if(num != 1):
ctr+=1
if(num%2==0):
collatz(num/2,ctr)
else:
collatz(num*3+1,ctr)
return ctr
test=collatz(9,0)
For any number I put in for num, let's say 9 for instance, and 0 for ctr, ctr always comes out as 1. Am I using the ctr variable wrong?
EDIT:
I am trying to print out how many times the function is recursed. So ctr would be a counter for each recursion.
The variable ctr in your example will always be 1 because of the order of the recursive call stack. As one value of ctr is returned, then the call stack will start returning the previous values of ctr. Basically, at the very last recursive call, the highest value of ctr will be returned. But since the method call at the bottom of the call stack returns the very last value aka the value that will be stored in test, test will always be 1. Let's say I input parameters into collatz that would result in five total calls of the method. The call stack would look like this coming down,
collatz returns ctr --> 5
collatz returns ctr --> 4
collatz returns ctr --> 3
collatz returns ctr --> 2
collatz returns ctr --> 1 //what matters because ctr is being returned with every method call
As you can see, no matter how many times collatz is called, 1 will always be returned because the call at the bottom of the call stack has ctr equaling 1.
The solution can be a lot of things, but it really depends on the purpose of what you're trying to accomplish which isn't clearly stated in your question.
EDIT: If you want ctr to end up being the number of times a recursive call is made, then just assign ctr to the value of the method call. It should look like this,
def collatz(num,ctr):
if(num != 1):
ctr+=1
if(num%2==0):
ctr = collatz(num/2,ctr)
else:
ttr = collatz(num*3+1,ctr)
return ctr
test=collatz(9,0)
I changed your recursive calls to set the value received back from the recursive calls into ctr. The way you wrote it, you were discarding the values you got back from recursing.
def collatz(num,ctr):
if(num != 1):
ctr+=1
if(num%2==0):
ctr=collatz(num/2,ctr)
else:
ctr=collatz(num*3+1,ctr)
return ctr
test=collatz(9,0)
An example:
def collatz(number):
if number % 2 == 0:
print(number // 2)
return number // 2
elif number % 2 == 1:
result = 3 * number + 1
print(result)
return result
n = input("Give me a number: ")
while n != 1:
n = collatz(int(n))
Function parameters in Python are passed by value, not by reference. If you pass a number to a function, the function receives a copy of that number. If the function modifies its parameter, that change will not be visible outside the function:
def foo(y):
y += 1
print("y=", y) # prints 11
x = 10
foo(x)
print("x=", x) # Still 10
In your case, the most direct fix is to make ctr into a global variable. Its very ugly because you need to reset the global back to 0 if you want to call the collatz function again but I'm showing this alternative just to show that your logic is correct except for the pass-by-reference bit. (Note that the collatz function doesn't return anything now, the answer is in the global variable).
ctr = 0
def collatz(num):
global ctr
if(num != 1):
ctr+=1
if(num%2==0):
collatz(num/2)
else:
collatz(num*3+1)
ctr = 0
collatz(9)
print(ctr)
Since Python doesn't have tail-call-optimization, your current recursive code will crash with a stack overflow if the collatz sequence is longer than 1000 steps (this is Pythons default stack limit). You can avoid this problem by using a loop instead of recursion. This also lets use get rid of that troublesome global variable. The final result is a bit more idiomatic Python, in my opinion:
def collats(num):
ctr = 0
while num != 1:
ctr += 1
if num % 2 == 0:
num = num/2
else:
num = 3*num + 1
return ctr
print(collatz(9))
If you want to stick with using recursive functions, its usually cleaner to avoid using mutable assignment like you are trying to do. Instead of functions being "subroutines" that modify state, make them into something closer to mathematical functions, which receive a value and return a result that depends only on the inputs. It can be much easier to reason about recursion if you do this. I will leave this as an exercise but the typical "skeleton" of a recursive function is to have an if statement that checks for the base case and the recursive cases:
def collatz(n):
if n == 1:
return 0
else if n % 2 == 0:
# tip: something involving collatz(n/2)
return #???
else:
# tip: something involving collatz(3*n+1)
return #???
The variable will return the final number of the collatz sequence starting from whatever number you put in. The collatz conjecture says this will always be 1

python scooping and recursion

I am struck in a small recursive code. I have printed output and it prints fine but when I try to put a counter to actually count my answers, it gives me scooping errors.
total = 0
def foo(me, t):
if t<0:
return
if t==0:
total = total+1
return
for i in range(1, me+1):
total = total+1
return foo(i, t-i)
it says local variable referenced before assignment, well, I am trying to refer total in the first line.... Its not about global variables, I have tried to use global as well but in vain.
This is pure scooping issue, any ideas?
As mentioned by others, you need the global statement for total. Also, as noted by Svante, the for loop is unnecessary as coded since i is always 1. So, with an equivalent version of your code:
total = 0
def foo(me, t):
global total
if t < 0:
return
total = total + 1
if t == 0:
return
return foo(1, t-1)
foo(99, 100)
print total
It should be easier to see that foo(99, 100) will indeed be 101 since you're essentially counting down from 100 to 0. I'm not sure why you think otherwise?
You forgot to make sure to set total as a global in your function. You said "I have tried to use global as well but in vain." but when I try it below it doesn't throw any error:
total = 0
def foo(me, t):
global total
if t<0:
return
if t==0:
total = total+1
return
for i in range(1, me+1):
total = total+1
return foo(i, t-i)
I'm not sure you really know what you are trying to do...
(at least if you say that adding the global keyword gives incorrect results, but silences the errors)
you do need the statement "global total" if you are going to to try to reference total (which you are doing)
(what are you expecting when you execute foo(99, 100)?)
maybe your boundary conditions are wrong?
'cause with the arguments (99, 100)
foo will skip the two if statements
loop in the following loop:
for i in range(1, 100):
total += 1
return foo(i, 100-i)
which really is equivalent to
else:
total += 1
return foo(1, 99)
(like Svante was saying)
based on your two if conditions
foo(1,99) will correctly generate total += 100
(99 times it will execute your "else" statement bringing the total to 100, and then finally it will reach t == 0 and execute the last final if where it will push the total to your "incorrect" 101)
you should also use elif for your second case
As a generic advice, recursion should always use return values, and not global variables. Recursion has already its own load of complexity, increasing it with side-effects and not clear interfaces will make it even worse.
You should try something in the lines of this:
def foo(me, t):
if t<0:
return 0
if t==0:
return foo(me, t+1)
return foo(me-1, t)
for i in range(1, me+1):
tot = foo(i, t-i)
return tot
Note: this code is wrong, it will not solve your problem and it will not even work on its own; I put it just to give a kind of idea of how to design a recursion that is easier to manage.
Thanks people, thanks youarf, Liffredo.
I was wrong, I didnt notice that I was returning before adding-up things, loop was only running once, I have fixed the code. It is like this:
def foo(me, t):
if t<0:
return 0
if t==0:
return 1
toreturn = 0
for i in range(1, me+1):
toreturn = toreturn + foo(i, t-i)
return toreturn
This snippet is for this problem at http://projecteuler.net/index.php?section=problems&id=76

Categories

Resources