是否有比这更好的方法(性能)计算斐波那契?

时间:2013-02-26 15:56:32

标签: performance algorithm fibonacci

我制作了这段代码..而且我需要充分利用它......我真的需要计算斐波那契数字的最佳表现..请帮助...

我已经阅读了一些此类计算的代码,我认为我得到了最好的...

对我来说,这是对... .. plz ..

ps:我真的需要BigInteger ..我会计算出庞大数字的Fibonacci

ps2:我用这个算法计算了一些大数字,我得到了很好的响应时间..但我需要知道它是否会更好

ps3:要运行此代码,您需要使用此VM参数-Xss16384k(StackSize)

public class Fibonacci {

    private static BigInteger[] fibTmp = { BigInteger.valueOf(0), BigInteger.valueOf(1) };

    public static BigInteger fibonacci(long v) {

        BigInteger fib = BigInteger.valueOf(0);

        if (v == 1) {

            fib = BigInteger.valueOf(1);

        } else if (v == 0) {

            fib = BigInteger.valueOf(0);

        } else {

            BigInteger v1 = fibonacci(v - 1);
            BigInteger v2 = fibTmp[(int) (v - 2)];

            fib = v1.add(v2);
        }

        synchronized (fibTmp) {

            if (fibTmp.length - 1 < v)
                fibTmp = Arrays.copyOf(fibTmp, (int) (v + 10));

            fibTmp[(int) v] = fib;
        }

        return fib;
    }
}

3 个答案:

答案 0 :(得分:7)

是的,有更好的方法。在给定正整数作为输入的情况下,这是一种log(n)测试且非常有效的方法,用于以任意精度计算Fibonacci的值。该算法改编自SICPexercise 1.19

的解决方案
public static BigInteger fibonacci(int n) {

    int count = n;
    BigInteger tmpA, tmpP;
    BigInteger a = BigInteger.ONE;
    BigInteger b = BigInteger.ZERO;
    BigInteger p = BigInteger.ZERO;
    BigInteger q = BigInteger.ONE;
    BigInteger two = new BigInteger("2");

    while (count != 0) {

        if ((count & 1) == 0) {
            tmpP = p.multiply(p).add(q.multiply(q));
            q = two.multiply(p.multiply(q)).add(q.multiply(q));
            p = tmpP;
            count >>= 1;
        }

        else {
            tmpA = b.multiply(q).add(a.multiply(q).add(a.multiply(p)));
            b = b.multiply(p).add(a.multiply(q));
            a = tmpA;
            count--;
        }

    }

    return b;  

}

在本书的链接章节中,有一个关于它是如何工作的解释(向下滚动到练习1.19),并且声明:

  

这是一个聪明的算法,以对数步数计算斐波纳契数...这个练习是由Joe Stoy根据安德尔Kaldewaij的一个例子提出的。 1990. 编程:算法的推导

当然,如果需要反复计算相同的值,可以通过已计算的memoizing结果来实现进一步的性能提升,例如使用地图存储以前的值。

答案 1 :(得分:4)

您的实现不适用于任何正确的数字,因为它会使堆栈溢出。

我认为没有理由在这里使用递归。递归很漂亮,但通常更重(它依赖于语言)。这是一个简单的for循环的工作实现:

private static BigInteger[] fibTmp = {BigInteger.ZERO, BigInteger.ONE};
private static int maxCached = 1;
public static BigInteger fibonacci(int v) {
    if (fibTmp.length<=v) {
        fibTmp = Arrays.copyOf(fibTmp, v*5/4);
    }
    for (; maxCached<v;) {
        maxCached++;
        BigInteger v1 = fibTmp[maxCached - 1];
        BigInteger v2 = fibTmp[maxCached - 2];
        fibTmp[maxCached] = v1.add(v2);
    }
    return fibTmp[v];
}

这是直接实现,而没有在文献中寻找有效的斐波那契算法。你最好找他们。

另请注意,基于缓存的实现内存成本很高,只有多次调用该函数才有意义。

答案 2 :(得分:0)

首先,您正在使用递归,这在时间和空间复杂性方面都不高效。你应该使用迭代方法。

然后,如果额外的内存或空间不是交易破坏者,并且性能非常重要,您可能需要预先计算以后要计算的所有数字,并将它们存储在数组或磁盘上(如果它也是如此)非常适合你的记忆。之后您可以在恒定时间内获得该值。