See the next iteration.
I have that method for computing Fibonacci numbers \$F_n\$ (\$n = 0, 1, 2, \dots)\$, that relies on computing
$$ A = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^n. $$
The solution is then read from \$A_{1,2}\$. Now I can easily compute, for instance, \$F_{100000}\$.
However, in this code snippet, I need not just large integer additions, but multiplications as well, and looking at the source code of multiplication of two BigInteger
s, it becomes evident that the algorithms are more smart and efficient than I could ever do.
What comes to the complexity of this approach, we need only \$\Theta(\log n)\$ matrix multiplications. Assuming that multiplying two (largest in the computation) BigInteger
s takes time \$\mathcal{O}(f(n))\$, the complexity of the entire algorithm is \$\mathcal{O}(f(n) \log n)\$.
import java.math.BigInteger;
public class LargeFibonacciNumbers {
public static String fibonacci(int n) {
if (n < 0) {
throw new IllegalArgumentException(
"The (" + n + ")th Fibonacci number is not defined.");
}
switch (n) {
case 0:
return "0";
case 1:
return "1";
}
BigInteger[][] matrix = new BigInteger[2][2];
matrix[0][0] = BigInteger.ONE;
matrix[0][1] = BigInteger.ONE;
matrix[1][0] = BigInteger.ONE;
matrix[1][1] = BigInteger.ZERO;
return fibonacciMatrix(matrix, n)[0][1].toString();
}
private static BigInteger[][] multiply(BigInteger[][] matrix1,
BigInteger[][] matrix2) {
BigInteger[][] ret = new BigInteger[2][2];
ret[0][0] = matrix1[0][0].multiply(matrix2[0][0])
.add(matrix1[0][1].multiply(matrix2[1][0]));
ret[0][1] = matrix1[0][0].multiply(matrix2[0][1])
.add(matrix1[0][1].multiply(matrix2[1][1]));
ret[1][0] = matrix1[1][0].multiply(matrix2[0][0])
.add(matrix1[1][1].multiply(matrix2[1][0]));
ret[1][1] = matrix1[1][0].multiply(matrix2[0][1])
.add(matrix1[1][1].multiply(matrix2[1][1]));
return ret;
}
private static BigInteger[][]
fibonacciMatrix(BigInteger[][] matrix, int n) {
if (n == 1) {
// End the recursion.
return matrix;
}
if ((n & 1) == 1) {
// 'n' is odd.
return multiply(matrix, fibonacciMatrix(matrix, n - 1));
}
// 'n' is even.
BigInteger[][] tmp = fibonacciMatrix(matrix, n >> 1);
return multiply(tmp, tmp);
}
public static void main(String[] args) {
int n = -1;
if (args.length > 0) {
try {
n = Integer.parseInt(args[0]);
} catch (NumberFormatException ex) {
}
}
System.out.println(fibonacci(n));
}
}
So, what do you think?