python 在这么算 fibonacci 的时候到底在干什么!?

2014-10-22 20:23:31 +08:00
 juicy
这几天学了点python,有一道题是让练习用python计算fibonacci数列,发现个很有意思的事:
当用传统的写法
return fib(n-1) + fib(n-2)
来算fib(40)的时候,算得超级慢,分钟级别的
而用generator的时候
def fib():
a = 1
b = 2
while 1:
a, b = b, (a+b)
yield a
counter = 0
for n in fib():
if counter == 40:
print n
break
counter +=1
瞬间就计算完了

后来,在这个链接里http://fengmk2.cnpmjs.org/blog/2011/fibonacci/nodejs-python-php-ruby-lua.html 发现了各种语言算fib(40)的效率

我很纳闷的是:
最后几种语言花费的时间跟python一样,都竟然达到1m,2m,甚至3m,
说得夸张一点,人脑算得都比它们快,
那么,问题来了,如题
4726 次点击
所在节点    Python
28 条回复
chlx
2014-10-22 20:27:15 +08:00
贴代码
SErHo
2014-10-22 20:29:28 +08:00
使用递归的时候有大量重复计算的。
Miorpher
2014-10-22 20:30:49 +08:00
我想vote down 1楼,人家内容里不是清清楚楚写着代码来着吗!
juicy
2014-10-22 20:32:04 +08:00
@SErHo 那么是说像nodejs,c,java等语言会自带记忆功能么。。。
juicy
2014-10-22 20:34:46 +08:00
```python
def fib():
a = 1
b = 2
while 1:
a, b = b, (a+b)
yield a

counter = 0
for n in fib():
if counter == 40:
print n
break
counter +=1
```
SErHo
2014-10-22 20:36:28 +08:00
@juicy 在计算量相同的情况下,这几种语言的确是要快点。
eriale
2014-10-22 20:42:14 +08:00
两种算法不一样,迭代器的复杂度是o(n),递归的复杂度是指数复杂度o(2^n)。
hahastudio
2014-10-22 20:44:58 +08:00
hahastudio
2014-10-22 20:48:59 +08:00
顺带一提,在 Python 引入 lru_cache 之后,也能很快地递归
https://docs.python.org/3/library/functools.html#functools.lru_cache
当然也有不少自己实现的 memoize decorator,比如
https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
juicy
2014-10-22 20:49:04 +08:00
@hahastudio 牛!
MForever78
2014-10-22 20:50:44 +08:00
@eriale 正解。举例,在递归的时候,算 fib(40) 的时候,分别要算 fib(38) 和 fib(39),而在算 fib(39) 的时候,会重新计算一遍 fib(38) 而不会利用刚刚得到的结果,导致了大量的重复计算。benchmark 里也明确写了 c with -O2 ,说明是有编译器优化的。
mengzhuo
2014-10-22 21:10:05 +08:00
算法问题,楼主就算用其他语言也是一样的结果
jox
2014-10-22 21:20:48 +08:00
第一种算法python会计算lz发的这个帖子能够得到多少回帖,第二种算法python不会计算任何东西,只是简单地把第一种算法的结果偷过来,就这么简单。
maemual
2014-10-22 21:28:33 +08:00
楼主,你是在逗我(⊙_⊙)?

你是真不懂递归?
Viztor
2014-10-22 21:44:11 +08:00
算法太差,时间复杂度是指数级的,这种情况下使用不同语言带来的效率差异。。。
试一下尾递归优化。
筛选算法之类的。
eriale
2014-10-22 22:12:13 +08:00
这种树形算法没法用尾递归优化。
想要优化直接改成迭代器方法好了,或者用@hahastudio说的内存装饰器。
advancedxy
2014-10-22 22:42:57 +08:00
@eriale 为什么不能做尾递归优化?accumulator 中存两个之前的计算值不就行了嘛? 像下面这样。

def fib(acc,n):
a,b = acc
if n <= 1:
return b
else:
return fib(b,a+b), n-1)
fib((1,1),n)
rwalle
2014-10-22 22:54:57 +08:00
楼主你缺乏一些最基础的算法知识啊
斐波那契用递归方法来计算是最愚蠢的,即使只是用于教科书讲解“递归”这个概念
可以看看《代码大全》
jox
2014-10-22 23:29:08 +08:00
谁说fibonacci不能用递归来算啊,楼主采用的递归方式不对罢了,python似乎是不支持尾递归优化的,除了函数式编程语言外,支持尾递归优化的似乎不多,C也得在编译的时候开启某个选项才行。

def fib(num):
if num == 1 or num == 2:
return 1
return fib_helper(1, 1, num)

def fib_helper(a, b, count):
if count == 1:
return a

return fib_helper(b, a + b, count - 1)
jox
2014-10-22 23:29:55 +08:00
v2ex怎么贴代码啊

hello world

怎么前面的空格都没有了?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/140836

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX