Matrix Exponentiation Algorithm for large values of N

落爺英雄遲暮 提交于 2019-12-20 02:14:22

问题


I want to calculate the Fibonacci of very large value of N ie. 10^6 with a complexity of O(logN). Here is my code but it gives the result for 10^6 in 30 seconds which is very time consuming.Help me point out the mistake.I have to give the output in modulo 10^9+7.

static BigInteger mod=new BigInteger("1000000007");

BigInteger fibo(long n){
    BigInteger F[][] = {{BigInteger.ONE,BigInteger.ONE},{BigInteger.ONE,BigInteger.ZERO}};
    if(n == 0)
        return BigInteger.ZERO;
    power(F, n-1);
    return F[0][0].mod(mod);
}

void power(BigInteger F[][], long n) {
    if( n == 0 || n == 1)
        return;
    BigInteger M[][] = {{BigInteger.ONE,BigInteger.ONE},{BigInteger.ONE,BigInteger.ZERO}};
    power(F, n/2);
    multiply(F, F);
    if( n%2 != 0 )
        multiply(F, M);
  }

void multiply(BigInteger F[][], BigInteger M[][]){
    BigInteger x =  (F[0][0].multiply(M[0][0])).add(F[0][1].multiply(M[1][0])) ;
    BigInteger y =  F[0][0].multiply(M[0][1]).add(F[0][1].multiply(M[1][1])) ;
    BigInteger z =  F[1][0].multiply(M[0][0]).add( F[1][1].multiply(M[1][0]));
    BigInteger w =  F[1][0].multiply(M[0][1]).add(F[1][1].multiply(M[1][1]));

    F[0][0] = x;
    F[0][1] = y;
    F[1][0] = z;
    F[1][1] = w;
}

回答1:


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



回答2:


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.



来源:https://stackoverflow.com/questions/14781543/matrix-exponentiation-algorithm-for-large-values-of-n

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