Matrix Exponentiation Algorithm for large values of N

*爱你&永不变心* 提交于 2019-12-01 21:26:28

Use these recurrences:

F2n−1 = Fn2 + Fn−12

F2n = (2Fn−1 + Fn) Fn

together with memoization. For example, in Python you could use the @functools.lru_cache decorator, like this:

from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci_modulo(n, m):
    """Compute the nth Fibonacci number modulo m."""
    if n <= 3:
        return (0, 1, 1, 2)[n] % m
    elif n % 2 == 0:
        a = fibonacci_modulo(n // 2 - 1, m)
        b = fibonacci_modulo(n // 2, m)
        return ((2 * a + b) * b) % m
    else:
        a = fibonacci_modulo(n // 2, m)
        b = fibonacci_modulo(n // 2 + 1, m)
        return (a * a + b * b) % m

this computes the 106th Fibonacci number (modulo 109 + 7) in a few microseconds:

>>> from timeit import timeit
>>> timeit(lambda:fibonacci_modulo(10 ** 6, 10 ** 9 + 7), number=1)
0.000083282997366

I get a more reasonable - although still very slow - time of real 0m2.335s using your code.

The algorithm to compute the Fibonacci numbers is okay (there are some tweaks that could speed it up somewhat, but nothing very dramatic), so the problem is that operations on large BigIntegers are slow, and F(10^6) has nearly 700,000 bits.

Since you want to compute the remainder modulo mod = 10^9 + 7, and (mod-1)^2 fits in a long, you can get a much faster implementation using longs instead of BigIntegers, computing the remainder in each step. The direct transcription

public class FiboL {

    static final long mod = 1000000007L;

     static long fibo(long n){

          long F[][] = {{1,1},{1,0}};

          if(n == 0)
            return 0;
          power(F, n-1);
            return F[0][0]; //.mod(mod);
        }

    static void power(long F[][], long n){

          if( n == 0 || n == 1)
              return;
          long M[][] = {{1,1},{1,0}};

          power(F, n/2);
          multiply(F, F);

          if( n%2 != 0 )
             multiply(F, M);
        }

    static void multiply(long F[][], long M[][]){

          long x =  (F[0][0] * M[0][0]) % mod + (F[0][1] * M[1][0]) % mod;
          long y =  (F[0][0] * M[0][1]) % mod + (F[0][1] * M[1][1]) % mod;
          long z =  (F[1][0] * M[0][0]) % mod + (F[1][1] * M[1][0]) % mod;
          long w =  (F[1][0] * M[0][1]) % mod + (F[1][1] * M[1][1]) % mod;

          F[0][0] = x % mod;
          F[0][1] = y % mod;
          F[1][0] = z % mod;
          F[1][1] = w % mod;
    }
    public static void main(String[] args) {
        System.out.println(fibo(1000000));
    }
}

runs in real 0m0.083s.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!