Java 中的非常大的斐波那契数列

Very Large Fibonacci in Java

我正在尝试快速计算大的斐波那契数列。这是我的代码。对于超过 100 万的数字,它非常慢,如何改进?

public static BigInteger fib(BigInteger n) {

        int k = n.intValue();
        BigInteger ans = null;

        if(k == 0) { 
            ans = new BigInteger("0");
        } else if(Math.abs(k) <= 2) {
            ans = new BigInteger("1");
        } else {
            BigInteger km1 = new BigInteger("1");
            BigInteger km2 = new BigInteger("1");

            for(int i = 3; i <= Math.abs(k); ++i) {
                ans = km1.add(km2);
                km2 = km1;
                km1 = ans;
            }
        }

       if(k<0 && k%2==0) { ans = ans.negate(); }
       return ans;
    } 

比奈的表现很好。谢谢你们!

一种方法是计算 2x2 矩阵的 (N-1)th 次方:

A = ((1, 1), (1, 0))

然后我们有

Fib(n) = A^(n-1)[0][0], for n >= 1

矩阵 A 的幂可以使用 Exponentiation by squaring

高效计算
static void multiply(BigInteger m[][], BigInteger n[][]) {
    BigInteger a = (m[0][0].multiply(n[0][0])).add(m[0][1].multiply(n[1][0]));
    BigInteger b = (m[0][0].multiply(n[0][1])).add(m[0][1].multiply(n[1][1]));
    BigInteger c = (m[1][0].multiply(n[0][0])).add(m[1][1].multiply(n[0][1]));
    BigInteger d = (m[1][0].multiply(n[0][1])).add(m[1][1].multiply(n[1][1]));
    m[0][0] = a;
    m[0][1] = b;
    m[1][0] = c;
    m[1][1] = d;
}

static void fib(int x) {
    BigInteger m[][] = new BigInteger[2][2];
    m[0][0] = new BigInteger("1");
    m[0][1] = new BigInteger("1"); //f1
    m[1][0] = new BigInteger("1");
    m[1][1] = new BigInteger("0");

    BigInteger n[][] = new BigInteger[2][2];
    n[0][0] = new BigInteger("1");
    n[0][1] = new BigInteger("1"); //f1
    n[1][0] = new BigInteger("1");
    n[1][1] = new BigInteger("0");

    int i = x;
    ArrayList <Integer> a = new ArrayList<>();
    while (i != 1) {
        if (i%2 == 0) {
            a.add(0);
            i = i / 2;
        } else {
            a.add(1);
            i = i / 2;
        }
    }
    for (int j = a.size() - 1; j >= 0 ; j--) {
        if (a.get(j) == 0) {
            multiply(m, m);
        } else {
            multiply(m, m);
            multiply(m, n);
        }
    }
    System.out.println(m[1][0]);
}