简体   繁体   中英

Algorithm for finding last 5 digits of Fibonacci number

I'm trying to implement an iterative algorithm for computing the last 5 digits of the Nth Fibonacci number. I have no issue finding the nth Fibonacci number itself and displaying only the last 5 digits, however, my assignment also asks to find the maximum n for which my program runs under 1 minute. The problem is, the N gets very huge, and therefore Fibonacci numbers are huge as well. Should I just use BigInteger to store values and in the end use % operator to display 5 last digits? Is there a way to use the fact that I only need last 5 digits to speed up the process? I feel like I'm missing the point of the assignment.

Assignment says this: Using Java, implement the iterative algorithm for computing the last 5 digits of the nth Fibonacci number. Perform an experiment to find the largest value of n for which your program runs under 1 minute on your computer.

My code for finding last 5 digits of Nth Fibonacci number:

public static int Fibonacci(int n){
    int a, b = 0, c = 1;
    for(int i = 1; i < n; i++){
        a = b;
        b = c;
        c = a + b;
    }
    return c % 100000;
}

I would also love to know if there are better iterative solutions.

As you already noticed, finding the last 5 digits is equivalent to calculating the result modulo 100000. To solve the overflow issue, you can apply the % 100000 operation to the intermediate results so no BigInteger is required. It would be: c = (a + b) % 100000 .

In theory, you can improve the time complexity of the solution from O(N) to O(log(N)). The algorithm is based on fast matrix exponentiation. However, your assignment requires the iterative approach so I mention it just for completeness.

Ardavel's answer has a good, clear explanation of why taking the remainder in the loop gives the correct result, so that you don't need to use BigInteger. So for the purpose of your assignment, this question is answered; but the problem is too interesting to leave it there. And you said:

I would also love to know if there are better iterative solutions.

So, here goes:

Matrix multiplication

Ardavel mentions that you can compute the same result in O(log n) time by computing a matrix power with an efficient matrix power algorithm. Essentially, the n-th Fibonacci number can be written in a closed form as:

( ... ) = ( 1 1 )n ( 1 )
( F_n )   ( 1 0 )  ( 0 )

And this matrix to the power of n can be computed in O(log n) time eg using the square and multiply algorithm, which can be implemented iteratively - and the iterative version is more efficient than the recursive version.

"O(1) time" solution

In fact, you can do even better using the following observation: let's call the matrix equation above A^nv where v is the initial vector. There are only finitely many 2D integer vectors modulo 100,000, and only finitely many 2x2 integer matrices. So there is some finite number t such that A^tv = v .

This means that A^n = A^(n % t) , and it follows that however large n is , you only need to do at most a fixed, constant amount of matrix multiplication. It turns out that the value of t is 150,000, so we can improve on any algorithm by writing n %= 150000; at the start.

However, this solution isn't quite O(1) time because the remainder modulo t cannot be found in constant time for arbitrarily large n . Supposing we allow the input to be arbitrarily large (the rest of the computation can still be done using int s), then the time it takes to even read the input in a binary format is O(log n). But this is a much better O(log n) than having to do O(log n) matrix multiplications.

Chinese remainder theorem

We can go a step further. If we apply the Chinese remainder theorem then it's sufficient to find the answer modulo 2 5 and the answer modulo 5 5 , since these uniquely determine the answer modulo 10 5 . It turns out the cycle length t is much shorter in both cases: for the modulus 2 5 , t is just 48, and for 5 5 it's 12,500.

This is small enough that if performance is of great importance, we can feasibly just precompute the results for the smaller moduli in arrays of length 48 and 12,500 respectively. These numbers are small enough to fit in 2-byte short s, so the arrays take up about 25KB or so of memory, compared to about 600KB needed to store 150,000 int s if you were to precompute an array for t = 150,000.

The algorithm then is "take n modulo 48 and 12,500, look up in the two arrays, and apply the Chinese remainder theorem" , which is not really iterative, but at least you could argue that the arrays were precomputed using an iterative algorithm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM