Haskell Fibonacci seems slow
我在学习haskell,我写了一个简单的fibonacci函数:
它似乎编译得很好,将这个脚本加载到ghci repl中,我可能会用一些数字来处理这些问题。我试过了
1 | fib 33 |
号
令人惊讶的是,用了4秒钟才得出结果。(抱歉,我还不知道如何给Haskell中的函数计时,所以算我自己)。
FIB 33不是特别的征税。答案不到400万。所以我假设我的代码写得不是很好,或者我做递归的方式有问题(好吧,它写得不好,因为它不考虑负整数)。问题是,为什么速度慢?感谢您的帮助。
由于您的函数不使用memoization,因此评估时间比预期长。关于如何使用memoization在haskell中定义fibonacci函数的答案,请参见例如这个问题或那个问题。
你把这段时间和其他语言相比了吗?
这是一种具有O(2^n)复杂性的递归算法。在n=33时,会发出惊人的呼叫量。如果你计算每一个这样的呼叫有多少毫秒或纳秒,你就可以得到一个非常显著的关于实际性能的答案。
记住,有些编译器/执行环境可能会缓存函数返回值(Frerich对函数的命名方法memoization有更好的内存),这在使用此算法的情况下大大提高了性能。在这种情况下,不会发生这种情况,因此所有2^n递归调用都会发生。
你的算法不是很好。你可以用记忆法稍微改进一下,最多是O(N)。使用分而治之,您最多可以获得o(登录n):
这个想法是,乘法是关联的,所以你可以把大括号放在战略位置上:
5^10 = (5 * 5 * 5 * 5 * 5) * (5 * 5 * 5 * 5 * 5) = (5 * 5 * 5 * 5 * 5) ^ 2 =
( (5 * 5) * (5 * 5) * 5) ^ 2 = ( (5 * 5 ) ^ 2 * 5) ^ 2 = (((5 ^ 2) ^ 2) * 5) ^2
号
同样的模式也适用于矩阵乘法。haskell已经在其
这确实有效:
1 2 |
号
这里是一个带有助手函数的优化版本。仍然比上面给出的懒惰的无限列表慢,但对像我这样的新手来说更直接!
1 2 3 4 5 6 7 |
P.S:仅适用于正数