1

I am trying to make a basic power recursive function basicpower as a part of my university assignment. I tried to set the recursion limit to 100 using sys.setrecursionlimit(100). When I make a call to basicpower with any value between 98 and 100 if shows me a RecursionError: maximum recursion depth exceeded in comparison error. However, if I make a call to basicpower with any value between 1 and 97 it works perfectly fine. What causes this overhead in the call stack? Why I can not use the whole number specified by sys.setrecursionlimit ?

Code of basic power function:

import sys
sys.setrecursionlimit(100)


def basicpower(x, n):
    '''Compute the value x**n for integer n.''' 
    if n == 0:
        return 1 # base case without base case our recursive function will run forever
    else:
        return x  * basicpower(x, n-1) # our recursive call so we are calling the function on itself on a smaller problem space

print(basicpower(2,98))
  • 2
    Remember to read up on what [markdown](/markdown) is used here, because a single ` is for inline code, not entire codeblocks. Having said that: why are you using recursion for this, rather than a loop? (ignoring that `a**b` is of course already perfectly valid python). As for why: it's not the recursion limit "for a single function", it's "how many functions deep you can go". That `print(basicpower(...))` is two nestings already. – Mike 'Pomax' Kamermans Feb 10 '23 at 05:59
  • @Mike'Pomax'Kamermans Ok, I tried to remove the print function and still it works fine for 97, but it results in an error for 98. – Hossam Hamza Feb 10 '23 at 06:06
  • That ignores the far more important question. Why are you using a recursive function at all? – Mike 'Pomax' Kamermans Feb 10 '23 at 06:07
  • I know it can be done using the python operator or using a loop. But it is a university requirement to implement a recursive function as a practice for recursion. I want to know the reason behind not being able to use the limit. Why python reserves some of the stack frames? – Hossam Hamza Feb 10 '23 at 06:09
  • The origin of the problem related to another question, see [here](https://stackoverflow.com/questions/7081448/python-max-recursion-question-about-sys-setrecursionlimit). If you were to increase limit 102, it will work – Mert Kurttutan Feb 10 '23 at 06:10
  • In that case as comment on a university exercise: this is a good example of when _not_ to use recursion. There is nothing that recursion offers here that isn't strictly worse than using a normal loop. Instead, implement a recursive tree walk, or a combinatorial set expansion or the like. There, recursion _can_ offer benefits. – Mike 'Pomax' Kamermans Feb 10 '23 at 06:11

1 Answers1

1

So something to point out first, since you have your last check as n==0, your total stack for the recursive call will be n+1. an n of 98 is already 99 stacks.

After this, I'm not too sure about the details since it involves some underlying functionalities of python that I've never looked into. However, sys.setrecursionlimit is simply determining the total stack limit of the python interpreter. You can improve your recursion as

def basicpower(x, n):
    '''Compute the value x**n for integer n.''' 
    if n == 1:
        return x # base case without base case our recursive function will run forever
    else:
        return x  * basicpower(x, n-1) # our recursive call so we are calling the function on itself on a smaller problem space

This would reduce the amount of stacks required by the recursion call to complete by 1. If you are required to be able to get to 100 while the setrecursionlimit is also 100, you my be able to do this if its allowed by your course.

if n==2:
    return x*x

Of course, if you are trying to do this practically, simply doing x**n would be better.

You can actually check the existing stack for your functions.

import inspect
for item in inspect.stack():
    print(item)
print(len(inspect.stack()))

Running this in a python script or the python console, you get a stack length of 1 and a frame of

# for python console
[FrameInfo(frame=<frame at 0x000001803C38EC00, file '<stdin>', line 1, code <module>>, filename='<stdin>', lineno=1, function='<module>', code_context=None, index=None)]

Running the code in a .ipynb file gives a stack length of 22, and running it in google colab gave me a stack length of 28. Not sure if these numbers will vary, but this demonstrates how the initial point where you start your recursion won't be at 0, and can vary based on what type of python you are using.

Shorn
  • 718
  • 2
  • 13
  • Ok, so Why on Colab it prevents me from using 39 frames not only the two mentioned in your answer? Thanks in advance : ) Colab screenshot: https://ibb.co/BzTGwKg – Hossam Hamza Feb 10 '23 at 06:43
  • That seems to be something more specific towards the jupyter notebook handling of code blocks, and google colab files are ipynb which are jupyter notebook files. As mentioned, the setting of recursion limit is for the entire interpreter and as such, if there are already underlying stacks before you even get to where you are, you will be left with less stacks to use. Something to consider is why even specify the stack limit with `sys.setrecursionlimit`. If you need to set a limit, why not just enforce it within the function call? – Shorn Feb 10 '23 at 06:56
  • it set the recusive stack to n not n+2 – sahasrara62 Feb 10 '23 at 07:07
  • I am not trying to enforce a limit on my function, I am just curious of why it behaves like this. but thanks to you I got it. @Shorn – Hossam Hamza Feb 10 '23 at 07:19
  • @sahasrara62 I'm not sure what you mean. My reference of n+2 is regarding the total stack for the interpreter, not the recursion call. Even then, with the base case of the recursion being 0, the total stack of the recursion itself is n+1. If n was 2, the recursive stacks would be n=2, n=1, and n=0 making 3 stacks, therefore n+1. I've since found out the script itself is not part of the stack, but the print() method would be, thus causing the total stack to interpreter to be n+2, and will be reflecting this in the answer – Shorn Feb 10 '23 at 07:29
  • *"and the recursion is within a print function which adds another stack"* No, that's not true. Writing `print(basicpower(2,98))` doesn't mean `print` is a function that calls `basicpower`. First `basicpower` is run, then the result is given as argument to `print`. `print` is run after `basicpower`, not before. – Stef Feb 16 '23 at 10:10
  • 1
    @Stef edited to remove the wrong information, thank you. – Shorn Feb 16 '23 at 11:20