Reputation: 43
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;
}
Upvotes: 3
Views: 1376
Reputation: 65854
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
Upvotes: 7
Reputation: 183878
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 BigInteger
s 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 long
s instead of BigInteger
s, 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
.
Upvotes: 4