Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 63 additions & 5 deletions src/algebra/fibonacci-numbers.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ The encoding of an integer $n$ can be done with a simple greedy algorithm:

To decode a code word, first remove the final $1$. Then, if the $i$-th bit is set (indexing from 0 from the leftmost to the rightmost bit), sum $F_{i+2}$ to the number.


## Formulas for the $n^{\text{th}}$ Fibonacci number { data-toc-label="Formulas for the <script type='math/tex'>n</script>-th Fibonacci number" }

The $n$-th Fibonacci number can be easily found in $O(n)$ by computing the numbers one by one up to $n$. However, there are also faster ways, as we will see.
Expand All @@ -94,17 +95,71 @@ where the square brackets denote rounding to the nearest integer.

As these two formulas would require very high accuracy when working with fractional numbers, they are of little use in practical calculations.

### Fibonacci fast method

The $n$-th Fibonacci number can be easily found in $O(n)$ by computing the numbers one by one up to $n$. However, there are also faster ways, as we will see.

We can start from an iterative approach, to take advantage of the use of the formula $F_n = F_{n-1} + F_{n-2}$, therefore, we will simply precalculate those values in an array. Taking into account the base cases for $F_0$ and $F_1$.

```cpp
int fib(int n) {
int a = 0;
int b = 1;
for (int i = 0; i < n; i++) {
int tmp = a + b;
a = b;
b = tmp;
}
return b;
}
```

In this way, we obtain a linear solution, $O(n)$ time, saving all the values prior to $n$ in the sequence.

### Matrix form

It is easy to prove the following relation:

$$\begin{pmatrix}F_{n-1} & F_{n} \cr\end{pmatrix} = \begin{pmatrix}F_{n-2} & F_{n-1} \cr\end{pmatrix} \cdot \begin{pmatrix}0 & 1 \cr 1 & 1 \cr\end{pmatrix}$$

Denoting $P \equiv \begin{pmatrix}0 & 1 \cr 1 & 1 \cr\end{pmatrix}$, we have:
$$\begin{pmatrix} 1 & 1 \cr 1 & 0 \cr\end{pmatrix} ^ n = \begin{pmatrix} F_{n+1} & F_{n} \cr F_{n} & F_{n-1} \cr\end{pmatrix}$$

Thus, in order to find $F_n$ in $O(log n)$ time, we must raise the matrix to n. (See [Binary exponentiation](https://github.com/cp-algorithms/cp-algorithms/blob/master/src/algebra/binary-exp.md))

``` cpp
typedef long long ll;

struct matrix{
ll mat[2][2];
matrix friend operator *(const matrix &a, const matrix &b){
matrix c;
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++){
c.mat[i][j] = 0;
for(int k = 0; k < 2; k++){
c.mat[i][j] += (a.mat[i][k]*b.mat[k][j]);
}
}
return c;
}
};

matrix matpow(matrix base, ll n){
matrix ans {{{1, 0}, {0, 1}}};
while(n){
if(n&1)
ans = ans*base;
base = base*base;
n >>= 1;
}
return ans;
}

$$\begin{pmatrix}F_n & F_{n+1} \cr\end{pmatrix} = \begin{pmatrix}F_0 & F_1 \cr\end{pmatrix} \cdot P^n$$
long long fib(int n) {
matrix base {{{1, 1}, {1, 0}}};
base = matpow(base, n);
return base.mat[0][1];
}

Thus, in order to find $F_n$, we must raise the matrix $P$ to $n$. This can be done in $O(\log n)$ (see [Binary exponentiation](binary-exp.md)).
```

### Fast Doubling Method

Expand Down Expand Up @@ -153,4 +208,7 @@ We now choose two pairs of identical remainders with the smallest indices in the
* [Project Euler - Even Fibonacci numbers](https://www.hackerrank.com/contests/projecteuler/challenges/euler002/problem)
* [DMOJ - Fibonacci Sequence](https://dmoj.ca/problem/fibonacci)
* [DMOJ - Fibonacci Sequence (Harder)](https://dmoj.ca/problem/fibonacci2)
* [DMOJ UCLV - Numbered sequence of pencils](https://dmoj.uclv.edu.cu/problem/secnum)
* [DMOJ UCLV - Fibonacci 2D](https://dmoj.uclv.edu.cu/problem/fibonacci)
* [DMOJ UCLV - fibonacci calculation](https://dmoj.uclv.edu.cu/problem/fibonaccicalculatio)