685

I have this tail recursive function here:

def recursive_function(n, sum):
    if n < 1:
        return sum
    else:
        return recursive_function(n-1, sum+n)

c = 998
print(recursive_function(c, 0))

It works up to n=997, then it just breaks and spits out a RecursionError: maximum recursion depth exceeded in comparison. Is this just a stack overflow? Is there a way to get around it?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
quantumSoup
  • 27,197
  • 9
  • 43
  • 57
  • 4
    See also http://stackoverflow.com/questions/5061582/setting-stacksize-in-a-python-script – Thomas Ahle Apr 28 '14 at 19:09
  • 20
    [memoization](https://en.wikipedia.org/wiki/Memoization) could speed up your function and increase its effective recursive depth by making previously calculated values terminate instead of increasing the stack size. – Cyoce Jan 11 '16 at 18:47
  • 6
    The recursion limit is usually 1000. – Boris Verkhovskiy Apr 24 '19 at 07:29
  • @Boris Why does it stuck on `997` then? Is it because Python interpreter occupies the first 3 levels of the stack? – tonix Dec 15 '19 at 15:29
  • 4
    @tonix the interpreter adds a stack frame (the `line , in ` in stack traces) and this code takes 2 stack frames for `n=1` (because the base case is `n < 1`, so for `n=1` it still recurses). And I guess the recursion limit is not inclusive, as in it's "error when you hit 1000" not "error if you exceed 1000 (1001)". `997 + 2` is less than 1000 so it works `998 + 2` doesn't because it hits the limit. – Boris Verkhovskiy Dec 15 '19 at 19:00
  • @Boris So `997` stack frames are occupied by `recursive_function` and the last `2` are occupied by the intepreter itself (builtin allocation)? Did I got it right? – tonix Dec 15 '19 at 19:42
  • 6
    @tonix no. `recursive_function(997)` works, it breaks at `998`. When you call `recursive_function(998)` it uses 999 stack frames and 1 frame is added by the interpreter (because your code is always run as if it's part of top level module), which makes it hit the 1000 limit. – Boris Verkhovskiy Dec 15 '19 at 19:49
  • The way this function is written makes it take `n+1` frames to calculate the result for `n`. – Boris Verkhovskiy Dec 15 '19 at 19:50
  • @tonix I asked your question here https://stackoverflow.com/questions/59347491/is-the-recursion-limit-inclusive-or-exclusive-and-where-do-extra-stack-frames-co – Boris Verkhovskiy Dec 15 '19 at 19:59
  • @Boris I checked again and in my case with `recursion limit = 1000`, `recursive_function(995, 0)` works while `recursive_function(996, 0)` doesn't... So I guess there must be additional stack frames being used (I am using Python 3.6). – tonix Dec 15 '19 at 23:10
  • @tonix I just tried it on Python 3.6.9 through the REPL and I still get the same behavior, 997 works, 998 doesn't. How are you running this function? You must be doing it in some way that is adding 2 stack frames. Are you're doing it from a `main()` function or importing a file where you're defining the function? If you're running it with IPython, I wouldn't be surprised if that adds a few frames as well. – Boris Verkhovskiy Dec 15 '19 at 23:14
  • I am using the python CLI directly. I run `python` and then write and execute the code on the interpreter's `>>>` prompt. – tonix Dec 16 '19 at 00:29
  • @tonix are you using Python 2 or 3. If you're just typing `python` and not `python3` it's probably 2 – Boris Verkhovskiy Dec 17 '19 at 04:13
  • @Boris I can confirm you that I am using Python 3, because I see this output if I type `python` on the CLI: `Python 3.6.5 (default, Mar 30 2018, 06:42:10) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> ` – tonix Dec 17 '19 at 09:03

19 Answers19

786

It is a guard against a stack overflow, yes. Python (or rather, the CPython implementation) doesn't optimize tail recursion, and unbridled recursion causes stack overflows. You can check the recursion limit with sys.getrecursionlimit:

import sys
print(sys.getrecursionlimit())

and change the recursion limit with sys.setrecursionlimit:

sys.setrecursionlimit(1500)

but doing so is dangerous -- the standard limit is a little conservative, but Python stackframes can be quite big.

Python isn't a functional language and tail recursion is not a particularly efficient technique. Rewriting the algorithm iteratively, if possible, is generally a better idea.

Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
Thomas Wouters
  • 130,178
  • 23
  • 148
  • 122
  • 15
    From my experience, you need to increase the limit both in the `sys` and the `resource` modules: http://stackoverflow.com/a/16248113/205521 – Thomas Ahle Apr 28 '14 at 19:10
  • 5
    as a tactic to convert it to an iterative version, [a tail call optimization decorator could be used](https://github.com/lihaoyi/macropy#tail-call-optimization) – jfs Oct 14 '14 at 18:28
  • 5
    you can use http://svn.python.org/projects/python/trunk/Tools/scripts/find_recursionlimit.py to find out your OS upper limit – Ullullu Sep 16 '15 at 13:55
  • 12
    For those interested in the source, the default recursion limit is set to 1000 https://hg.python.org/cpython/file/tip/Python/ceval.c#l691 and it can be changed using the API at https://hg.python.org/cpython/file/tip/Python/sysmodule.c#l643 which in turn sets the limit to the new value at https://hg.python.org/cpython/file/tip/Python/ceval.c#l703 – Pramod Oct 07 '15 at 18:51
  • 1
    @ThomasAhle Why is it not enough to set `sys.setrecursionlimit`? What exactly would happen if I only set `sys.setrecusionlimit`, but not touch `resource`? – max Oct 08 '16 at 07:07
  • 41
    Tail recursion is a perfectly efficient technique in a programming language optimized for it. For the right sort of problem, it may be considerably more expressive an an iterative implementation. The answer probably means "in Python specifically" but that isn't what it says – Peter R Mar 06 '17 at 15:04
  • i got the same error but have no idea how i could make [this script](https://codepen.io/tOkyO1/pen/rqmppz?editors=0010) iterative instead of recursive... any ideas? the script had only crawled 34/54 pages... :/ – oldboy Oct 10 '18 at 22:27
  • i guess i could first retrieve all the diff page links and then iterate through those – oldboy Oct 10 '18 at 22:31
  • Is there an environment variable that can accomplish the same thing? I would like to increase the recursion limit when running Python code I am not the author of, but I can't find something like `PYTHONRECURSIONLIMIT=9999 python file.py` – BallpointBen Mar 06 '20 at 18:11
  • This sometimes helps. Especially in competitive programming. – pankaj Aug 20 '20 at 14:26
  • fantastic! thanks! I needed increase both `sys` and `resource` as mentioned by @ThomasAhle – neonwatty Mar 01 '23 at 22:37
  • I have a recursive function `fetch_instances()` and a configuration key `max_crawl_depths`. I used `max(config["max_crawl_depths"], sys.getrecursionlimit() - 50)` to make sure it won't exceed maximum minus a few for just being safe. – Roland Jul 12 '23 at 09:20
180

Looks like you just need to set a higher recursion depth:

import sys
sys.setrecursionlimit(1500)
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
David Young
  • 4,643
  • 2
  • 21
  • 18
  • 1
    In my case i forgot the return statement in the base case and it went on to exceed 1000. Python started throwing this exception and i was amazed, because i was sure about the no. of stacks its going to create to run it. – vijayraj34 May 19 '19 at 08:07
  • 8
    sys.setrecursionlimit(50) or a small amount is useful if your program is entering recursion and you would like the error message to NOT be pages and pages of the same text. I found this very helpful while debugging (my) bad recursive code. – peawormsworth Feb 22 '20 at 00:38
  • Note that this is subject to platform dependent limits – Soid Feb 19 '23 at 20:36
75

If you often need to change the recursion limit (e.g. while solving programming puzzles) you can define a simple context manager like this:

import sys

class recursionlimit:
    def __init__(self, limit):
        self.limit = limit

    def __enter__(self):
        self.old_limit = sys.getrecursionlimit()
        sys.setrecursionlimit(self.limit)

    def __exit__(self, type, value, tb):
        sys.setrecursionlimit(self.old_limit)

Then to call a function with a custom limit you can do:

with recursionlimit(1500):
    print(fib(1000, 0))

On exit from the body of the with statement the recursion limit will be restored to the default value.

P.S. You may also want to increase the stack size of the Python process for big values of the recursion limit. That can be done via the ulimit shell builtin or limits.conf(5) file, for example.

Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
  • 3
    You also want to [up the process' recursion limit with `resource`](https://stackoverflow.com/q/5061582). Without it, you'll get a Segmentation Fault and the whole Python process will crash if you `setrecursionlimit` too high and try to use the new limit (about 8 megabytes of stack frames, which translates to ~30,000 stack frames with the simple function above, on my laptop). – Boris Verkhovskiy Dec 28 '19 at 19:35
  • @Boris: that could be added to the context manager, however raising the stack size limit will only work for root (superuser). – Eugene Yarmash Nov 09 '21 at 21:41
68

It's to avoid a stack overflow. The Python interpreter limits the depths of recursion to help you avoid infinite recursions, resulting in stack overflows. Try increasing the recursion limit (sys.setrecursionlimit) or re-writing your code without recursion.

From the Python documentation:

sys.getrecursionlimit()

Return the current value of the recursion limit, the maximum depth of the Python interpreter stack. This limit prevents infinite recursion from causing an overflow of the C stack and crashing Python. It can be set by setrecursionlimit().

Community
  • 1
  • 1
Scharron
  • 17,233
  • 6
  • 44
  • 63
25

resource.setrlimit must also be used to increase the stack size and prevent segfault

The Linux kernel limits the stack of processes.

Python stores local variables on the stack of the interpreter, and so recursion takes up stack space of the interpreter.

If the Python interpreter tries to go over the stack limit, the Linux kernel makes it segmentation fault.

The stack limit size is controlled with the getrlimit and setrlimit system calls.

Python offers access to those system calls through the resource module.

sys.setrecursionlimit mentioned e.g. at https://stackoverflow.com/a/3323013/895245 only increases the limit that the Python interpreter self imposes on its own stack size, but it does not touch the limit imposed by the Linux kernel on the Python process.

Example program:

main.py

import resource
import sys

print resource.getrlimit(resource.RLIMIT_STACK)
print sys.getrecursionlimit()
print

# Will segfault without this line.
resource.setrlimit(resource.RLIMIT_STACK, [0x10000000, resource.RLIM_INFINITY])
sys.setrecursionlimit(0x100000)

def f(i):
    print i
    sys.stdout.flush()
    f(i + 1)
f(0)

Of course, if you keep increasing setrlimit, your RAM will eventually run out, which will either slow your computer to a halt due to swap madness, or kill Python via the OOM Killer.

From bash, you can see and set the stack limit (in kb) with:

ulimit -s
ulimit -s 10000

The default value for me is 8Mb.

See also:

Tested on Ubuntu 16.10, Python 2.7.12.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 2
    Attempting to set `rlimit_stack` after [Stack Clash](http://www.openwall.com/lists/oss-security/2017/06/19/1) remediations may result in failure or related problems. Also see Red Hat [Issue 1463241](https://bugzilla.redhat.com/show_bug.cgi?id=1463241) – jww Jun 21 '17 at 16:35
  • 1
    I used this (the Python resource part) to help my implementation of Kosaraju's algorithm on professor Tim Roughgarden's mean (huge) dataset. My implementation worked on small sets, certainly the issue with a large dataset was the recursion/stack limit... Or was it? Well, yes it was! Thanks! – nilo Jan 28 '19 at 08:04
  • 1
    Thank Ciro great details answer! – X0-user-0X Jun 26 '22 at 15:23
12

I realize this is an old question but for those reading, I would recommend against using recursion for problems such as this - lists are much faster and avoid recursion entirely. I would implement this as:

def fibonacci(n):
    f = [0,1,1]
    for i in xrange(3,n):
        f.append(f[i-1] + f[i-2])
    return 'The %.0fth fibonacci number is: %.0f' % (n,f[-1])

(Use n+1 in xrange if you start counting your fibonacci sequence from 0 instead of 1.)

Daniel
  • 3,344
  • 5
  • 27
  • 35
  • 20
    why use O(n) space when you can use O(1)? – Janus Troelsen Mar 12 '14 at 09:11
  • 15
    Just in case the O(n) space comment was confusing: don't use a list. List will keep all the values when all you need is the nth value. A simple algorithm would be to keep the last two fibonacci numbers and add them until you get to the one you need. There are better algorithms too. – Milimetric Jul 14 '14 at 19:12
  • 4
    @Mathime: `xrange` is called simply `range`, in Python 3. – Eric O. Lebigot Aug 03 '16 at 09:50
  • 2
    @EOL I'm aware of this – Mathime Aug 03 '16 at 09:51
  • 8
    @Mathime I was making things explicit for those reading these comments. – Eric O. Lebigot Aug 03 '16 at 09:54
  • Regarding O(1): One can get the n-th Fibonacci number without computing all the previous ones by using matrix powers via diagonalization. See [pages 2 and 3 in here](https://ocw.mit.edu/courses/mathematics/18-06sc-linear-algebra-fall-2011/least-squares-determinants-and-eigenvalues/diagonalization-and-powers-of-a/MIT18_06SCF11_Ses2.9sum.pdf). – Martin Ueding Sep 29 '16 at 19:27
12

I had a similar issue with the error "Max recursion depth exceeded". I discovered the error was being triggered by a corrupt file in the directory I was looping over with os.walk. If you have trouble solving this issue and you are working with file paths, be sure to narrow it down, as it might be a corrupt file.

Ru Chern Chong
  • 3,692
  • 13
  • 33
  • 43
Tyler
  • 201
  • 2
  • 6
  • 3
    The OP does give his code, and his experiment is reproducible at will. It does not involve corrupt files. – T. Verron Mar 01 '15 at 19:25
  • 8
    You're right, but my answer isn't geared towards the OP, since this was over four years ago. My answer is aimed to help those with MRD errors indirectly caused by corrupt files - since this is one of the first search results. It helped someone, since it was up voted. Thanks for the down vote. – Tyler Mar 02 '15 at 20:36
  • 5
    This was the only thing I found anywhere when searching for my issue that connected a "max recursion depth" traceback to a corrupted file. Thanks! – Jeff Jul 18 '17 at 17:23
12

Use a language that guarantees tail-call optimisation. Or use iteration. Alternatively, get cute with decorators.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
9

Of course Fibonacci numbers can be computed in O(n) by applying the Binet formula:

from math import floor, sqrt

def fib(n):                                                     
    return int(floor(((1+sqrt(5))**n-(1-sqrt(5))**n)/(2**n*sqrt(5))+0.5))

As the commenters note it's not O(1) but O(n) because of 2**n. Also a difference is that you only get one value, while with recursion you get all values of Fibonacci(n) up to that value.

rwst
  • 2,515
  • 2
  • 30
  • 36
  • 9
    There is no maximum size of a long in python. – pppery Nov 21 '15 at 18:14
  • 14
    It's worth noting that this fails for larger `n` because of floating point imprecision - the difference between `(1+sqrt(5))**n` and `(1+sqrt(5))**(n+1)` becomes less than 1 ulp, so you start getting incorrect results. –  Jul 07 '16 at 14:02
  • 3
    There are actually no big integers in NumPy… – Eric O. Lebigot Aug 03 '16 at 09:52
  • @Mego What? It's the difference between `(1+sqrt(5))**n` and `((1+sqrt(5))**n)+1` that becomes less than 1 ulp! (small typo) Also, {@}rwst That's not O(1)! Calculating `2**n` takes at least O(n) time. – user202729 Jan 05 '18 at 01:43
  • 4
    @user202729 That's not true, calculating `2**n` is effectively O(log(n)) using [Exponentiattion by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring). – Sam Feb 18 '18 at 18:02
  • @Sam log(n) multiplications, but each multiplication takes more than O(n log n) (often O(n^2) in practice) time as each number has O(n) digits long. You need at least O(n) memory to store the result. – user202729 Feb 19 '18 at 01:40
  • 2
    @user202729 Any number is O(log(n)) digits long unless it's represented in unary. For instance "1" is 1 digit long in binary, and 1,000,000 is 10 digits long in binary. – Sam Feb 25 '18 at 01:22
  • @Sam But `fib(n)` is `O(n)` digits long. – user202729 Feb 25 '18 at 03:37
  • 1
    Guys, in practice, in most machines, fast exponentiation is O(log n). Since latency of integer multiplication is usualy a fixed number, the cost of each multiplication is irrelevant. The problem of Binet formula is that it doesn't work for little larger ns due to rounding errors in floating point types. The rounding error becomes a big problem much earlier than the cost of the multiplications shows up and the exponentiation becomes O(n). – mentatkgs Jun 09 '18 at 01:45
8

If you want to get only few Fibonacci numbers, you can use matrix method.

from numpy import matrix

def fib(n):
    return (matrix('0 1; 1 1', dtype='object') ** n).item(1)

It's fast as numpy uses fast exponentiation algorithm. You get answer in O(log n). And it's better than Binet's formula because it uses only integers. But if you want all Fibonacci numbers up to n, then it's better to do it by memorisation.

bebidek
  • 592
  • 3
  • 8
  • 2
    Sadly you can't use numpy in most competitive programming judges. But yes sir, your solution is my favorite. I've used the matrix soluction for some problems. It is the best solution when you need a very large fibonacci number and you can't use a modulus. If you are allowed to use a modulus, the pisano period the better way to do it. – mentatkgs Jun 09 '18 at 01:49
6

RecursionError: maximum recursion depth exceeded in comparison

Solution :

First it’s better to know when you execute a recursive function in Python on a large input ( > 10^4), you might encounter a “maximum recursion depth exceeded error”.

The sys module in Python have a function getrecursionlimit() can show the recursion limit in your Python version.

import sys
print("Python Recursive Limitation = ", sys.getrecursionlimit())

The default in some version of Python is 1000 and in some other it was 1500

You can change this limitation but it’s very important to know if you increase it very much you will have memory overflow error.

So be careful before increase it. You can use setrecursionlimit() to increase this limitation in Python.

import sys
sys.setrecursionlimit(3000)

Please follow this link for more information about somethings cause this issue :

https://elvand.com/quick-sort-binary-search/

Masoud.Ebrahimi
  • 309
  • 3
  • 4
5

Edit: 6 years later I realized my "Use generators" was flippant and didn't answer the question. My apologies.

I guess my first question would be: do you really need to change the recursion limit? If not, then perhaps my or any of the other answers that don't deal with changing the recursion limit will apply. Otherwise, as noted, override the recursion limit using sys.getrecursionlimit(n).

Use generators?

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fibs = fib() #seems to be the only way to get the following line to work is to
             #assign the infinite generator to a variable

f = [fibs.next() for x in xrange(1001)]

for num in f:
        print num

Above fib() function adapted from Introduction to Python Generators.

martineau
  • 119,623
  • 25
  • 170
  • 301
alex
  • 247
  • 2
  • 7
  • 2
    the reason for having to assign a generator to a variable is because `[fibs().next() for ...]` would make a new generator each time. – tox123 Aug 10 '16 at 19:02
  • 1
    Alternative use for example `islice` https://docs.python.org/3/library/itertools.html#itertools.islice to take an element from your generator. – user1556435 Feb 20 '21 at 14:35
  • Using `islice` would need to look like this (for 1001th number): `value = next(islice(fib(), 1000, 1001))`. – martineau Mar 22 '21 at 21:29
  • The opening line re:flippant is the greatest thing I've seen in a long time haha. – Carl Boneri Jun 15 '23 at 11:01
5

We can do that using @lru_cache decorator and setrecursionlimit() method:

import sys
from functools import lru_cache

sys.setrecursionlimit(15000)


@lru_cache(128)
def fib(n: int) -> int:
    if n == 0:
        return 0
    if n == 1:
        return 1

    return fib(n - 2) + fib(n - 1)


print(fib(14000))

Output

3002468761178461090995494179715025648692747937490792943468375429502230242942284835863402333575216217865811638730389352239181342307756720414619391217798542575996541081060501905302157019002614964717310808809478675602711440361241500732699145834377856326394037071666274321657305320804055307021019793251762830816701587386994888032362232198219843549865275880699612359275125243457132496772854886508703396643365042454333009802006384286859581649296390803003232654898464561589234445139863242606285711591746222880807391057211912655818499798720987302540712067959840802106849776547522247429904618357394771725653253559346195282601285019169360207355179223814857106405285007997547692546378757062999581657867188420995770650565521377874333085963123444258953052751461206977615079511435862879678439081175536265576977106865074099512897235100538241196445815568291377846656352979228098911566675956525644182645608178603837172227838896725425605719942300037650526231486881066037397866942013838296769284745527778439272995067231492069369130289154753132313883294398593507873555667211005422003204156154859031529462152953119957597195735953686798871131148255050140450845034240095305094449911578598539658855704158240221809528010179414493499583473568873253067921639513996596738275817909624857593693291980841303291145613566466575233283651420134915764961372875933822262953420444548349180436583183291944875599477240814774580187144637965487250578134990402443365677985388481961492444981994523034245619781853365476552719460960795929666883665704293897310201276011658074359194189359660792496027472226428571547971602259808697441435358578480589837766911684200275636889192254762678512597000452676191374475932796663842865744658264924913771676415404179920096074751516422872997665425047457428327276230059296132722787915300105002019006293320082955378715908263653377755031155794063450515731009402407584683132870206376994025920790298591144213659942668622062191441346200098342943955169522532574271644954360217472458521489671859465232568419404182043966092211744372699797375966048010775453444600153524772238401414789562651410289808994960533132759532092895779406940925252906166612153699850759933762897947175972147868784008320247586210378556711332739463277940255289047962323306946068381887446046387745247925675240182981190836264964640612069909458682443392729946084099312047752966806439331403663934969942958022237945205992581178803606156982034385347182766573351768749665172549908638337611953199808161937885366709285043276595726484068138091188914698151703122773726725261370542355162118164302728812259192476428938730724109825922331973256105091200551566581350508061922762910078528219869913214146575557249199263634241165352226570749618907050553115468306669184485910269806225894530809823102279231750061652042560772530576713148647858705369649642907780603247428680176236527220826640665659902650188140474762163503557640566711903907798932853656216227739411210513756695569391593763704981001125

Source

functools lru_cache

Tiago Martins Peres
  • 14,289
  • 18
  • 86
  • 145
Emma
  • 27,428
  • 11
  • 44
  • 69
  • Good but you do not need to line sys.setrecursionlimit(15000). You can check and optimize with print(fib.cache_info()) at the end. – F.Tamy Jan 05 '21 at 11:00
  • In python 3.9, It is better to use @cache(128) instead @lru_cache(128). – F.Tamy Jan 05 '21 at 11:04
4

As @alex suggested, you could use a generator function to do this sequentially instead of recursively.

Here's the equivalent of the code in your question:

def fib(n):
    def fibseq(n):
        """ Iteratively return the first n Fibonacci numbers, starting from 0. """
        a, b = 0, 1
        for _ in xrange(n):
            yield a
            a, b = b, a + b

    return sum(v for v in fibseq(n))

print format(fib(100000), ',d')  # -> no recursion depth error
martineau
  • 119,623
  • 25
  • 170
  • 301
2

Many recommend that increasing recursion limit is a good solution however it is not because there will be always limit. Instead use an iterative solution.

def fib(n):
    a,b = 1,1
    for i in range(n-1):
        a,b = b,a+b
    return a
print fib(5)
Christopher Hackett
  • 6,042
  • 2
  • 31
  • 41
Harun ERGUL
  • 5,770
  • 5
  • 53
  • 62
2

I wanted to give you an example for using memoization to compute Fibonacci as this will allow you to compute significantly larger numbers using recursion:

cache = {}
def fib_dp(n):
    if n in cache:
        return cache[n]
    if n == 0: return 0
    elif n == 1: return 1
    else:
        value = fib_dp(n-1) + fib_dp(n-2)
    cache[n] = value
    return value

print(fib_dp(998))

This is still recursive, but uses a simple hashtable that allows the reuse of previously calculated Fibonacci numbers instead of doing them again.

user3393266
  • 59
  • 2
  • 9
2
import sys
sys.setrecursionlimit(1500)

def fib(n, sum):
    if n < 1:
        return sum
    else:
        return fib(n-1, sum+n)

c = 998
print(fib(c, 0))
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
0

We could also use a variation of dynamic programming bottom up approach

def fib_bottom_up(n):

    bottom_up = [None] * (n+1)
    bottom_up[0] = 1
    bottom_up[1] = 1

    for i in range(2, n+1):
        bottom_up[i] = bottom_up[i-1] + bottom_up[i-2]

    return bottom_up[n]

print(fib_bottom_up(20000))
xariez
  • 529
  • 1
  • 5
  • 17
0

I'm not sure I'm repeating someone but some time ago some good soul wrote Y-operator for recursively called function like:

def tail_recursive(func):
  y_operator = (lambda f: (lambda y: y(y))(lambda x: f(lambda *args: lambda: x(x)(*args))))(func)
  def wrap_func_tail(*args):
    out = y_operator(*args)
    while callable(out): out = out()
    return out
  return wrap_func_tail

and then recursive function needs form:

def my_recursive_func(g):
  def wrapped(some_arg, acc):
    if <condition>: return acc
    return g(some_arg, acc)
  return wrapped

# and finally you call it in code

(tail_recursive(my_recursive_func))(some_arg, acc)

for Fibonacci numbers your function looks like this:

def fib(g):
  def wrapped(n_1, n_2, n):
    if n == 0: return n_1
    return g(n_2, n_1 + n_2, n-1)
  return wrapped

print((tail_recursive(fib))(0, 1, 1000000))

output:

..684684301719893411568996526838242546875

(actually tones of digits)

wiesiu_p
  • 558
  • 7
  • 6