简体   繁体   English

Python递归斐波那契函数无法处理大值

[英]Python recursive fibonacci function doesn't process large values

I wrote a simple recursive fibonacci function: 我编写了一个简单的递归斐波那契函数:

def recursive_fibonacci(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    if n > 1:
        return recursive_fibonacci(n-1) + recursive_fibonacci(n-2)

and tried to run a large value in it: 并尝试在其中发挥较大的价值:

print(recursive_fibonacci(100))

Nothing came out of the console and the fan on my mac started spinning violently 控制台什么都没掉,我的Mac上的风扇开始剧烈旋转

Can someone explain what is going on. 有人可以解释发生了什么。 What is happening internally in the stack frame? 堆栈框架内部发生了什么?

A call to your routine with argument N makes on the order of phi^N total calls. 用参数N调用例程的总次数为phi^N次。 For N=100, this is on the order of 10^20 calls. 对于N = 100,这大约是10 ^ 20次调用。 Don't wait for the output at N=100; 不要等待N = 100的输出; you won't live that long. 你不会活那么久。

However, you can memoize the function. 但是,您可以记住该功能。 Look up the term; 查找术语; there's also a Python package to do that for you automatically. 还有一个Python软件包可以自动为您完成此操作。 The idea is to store the result of each value call; 这个想法是存储每个值调用的结果。 for any N , you compute f(N) only once; 对于任何N ,您只计算一次f(N) thereafter, you just look up the value in a table. 之后,您只需在表中查找值。

Building on Prune's nice answer you can easily memoize the function calls so that each value of n is only computed once by passing a mutable argument (a dict) in the function definition and storing already computed values in the dict: 在Prune的一个很好的答案的基础上,您可以轻松地记住函数调用,从而通过在函数定义中传递一个可变参数(一个dict)并将已计算的值存储在dict中,每个n值仅被计算一次:

def recursive_fibonacci(n, mem={}):
    if n == 0 or n == 1:
        return n
    else:
        if n-1 not in mem:
            mem[n-1] = recursive_fibonacci(n-1)
        if n-2 not in mem:
            mem[n-2] = recursive_fibonacci(n-2)
        return mem[n-1] + mem[n-2]


print(recursive_fibonacci(100))
# 354224848179261915075

Already computed values are looked up the dict and would not require further recursive calls. 已经计算出的值已经在字典中查询了,不需要进一步的递归调用。

The primitive recursive solution takes a lot of time. 基本的递归解决方案需要很多时间。 The reason for this is that for each number calculated, it needs to calculate all the previous numbers more than once. 这样做的原因是,对于每个计算出的数字,它需要多次计算所有先前的数字。 Take a look at the following image. 看下面的图片。

Tree representing fibonacci calculation 代表斐波那契计算的树

It represents calculating Fibonacci(5) with your function. 它代表使用您的函数计算Fibonacci(5)。 As you can see, it computes the value of Fibonacci(2) three times, and the value of Fibonacci(1) five times. 如您所见,它计算Fibonacci(2)的值是3倍,而Fibonacci(1)的值是5倍。 That just gets worse and worse the higher the number you want to compute. 您要计算的数字越高,情况就越糟。

What makes it even worse is that with each fibonacci number you calculate in your list, you don't use the previous numbers you have knowledge of to speed up the computation – you compute each number "from scratch." 更糟糕的是,对于列表中计算出的每个斐波那契数,您不会使用以前知道的数字来加快计算速度,而是“从头开始”计算每个数。 The easiest way is to just create a list of fibonacci numbers up to the number you want. 最简单的方法是只创建一个斐波纳契数字列表,直到您想要的数字为止。 If you do that, you build "from the bottom up" or so to speak, and you can reuse previous numbers to create the next one. 如果这样做,您可以说是“从下而上”构建的,可以重复使用前一个数字来创建下一个。 If you have a list of the fibonacci numbers [0, 1, 1, 2, 3], you can use the last two numbers in that list to create the next number and return the last number of the listwhich is your final answer. 如果您有斐波那契数字[0,1,1,2,2,3]的列表,则可以使用该列表中的最后两个数字来创建下一个数字,并返回列表的最后一个数字,这是您的最终答案。

def fib_to(n):
    fibs = [0, 1]
    for i in range(2, n+1):
        fibs.append(fibs[-1] + fibs[-2])
    return fibs[-1]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM