【问题标题】:Is there a better way (performance) calculate fibonacci than this one?有没有比这更好的方法(性能)计算斐波那契?
【发布时间】:2013-02-12 03:59:54
【问题描述】:

我编写了这段代码.. 我需要充分利用它.. 我真的需要计算斐波那契数的最佳性能.. 请帮忙..

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

帮我解决这个问题.. plz..

ps:我真的需要 BigInteger.. 我会计算大量数字的斐波那契

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;
    }
}

【问题讨论】:

  • 这看起来像java。为了获得最佳性能,语言可能很重要。可以加个语言标签吗?
  • 不..忘记语言..是算法性能..在这种情况下语言无关紧要! =)
  • 一个更好的算法会更快,无论它是在什么语言或机器上实现的(当你得到足够大的数字时)。哦,渐近分析的乐趣和乐趣。
  • 有一个 O(log n) 算法可以找到斐波那契数。其称为矩阵求幂法。你可以试试。 fusharblog.com/…
  • @AndroidDecoded 那是O(log n) 步骤。由于F(n) 具有theta(n) 位数,因此没有任何算法可以比O(n) 位运算更好。

标签: performance algorithm fibonacci


【解决方案1】:

是的,有更好的方法。这是一个log(n) 测试且非常有效的方法,用于计算具有任意精度的斐波那契值,给定一个正整数作为输入。该算法改编自SICP的exercise 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 已经计算的结果来进一步提高性能,例如使用映射来存储以前的值。

【讨论】:

  • 为了获得更好的性能,您可以将 BigInteger 替换为 jscience LargeInteger(java.math.BigInteger.multiply 具有三次复杂度)
【解决方案2】:

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

我看不出有什么理由在这里使用递归。递归性很漂亮,但通常更重(它取决于语言)。这是一个简单的 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];
}

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

另请注意,这种基于缓存的实现会占用大量内存,并且只有在多次调用该函数时才有意义。

【讨论】:

    【解决方案3】:

    首先,您使用的是递归,这在时间和空间复杂度方面都不是很有效。您应该使用迭代方法。

    然后,如果额外的内存或空间不会破坏交易并且性能确实很关键,您可能需要预先计算所有您想稍后计算的数字并将它们存储在数组或磁盘中(如果它也是)很适合你的记忆。稍后您可以在恒定时间内获取该值。

    【讨论】:

      猜你喜欢
      • 2013-03-31
      • 2016-09-01
      • 1970-01-01
      • 2020-01-18
      • 1970-01-01
      • 1970-01-01
      • 2021-04-19
      • 2014-01-09
      • 1970-01-01
      相关资源
      最近更新 更多