Matrix Exponentiation Algorithm for large values of N

后端 未结 2 1262
长发绾君心
长发绾君心 2021-01-20 15:51

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 ver

相关标签:
2条回答
  • 2021-01-20 16:11

    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
    
    0 讨论(0)
  • 2021-01-20 16:30

    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.

    0 讨论(0)
提交回复
热议问题