chore(C): add fibonacci algorithm (#794)

pull/789/head
Leong Teng Man 2022-08-11 05:18:21 +08:00 committed by GitHub
parent d253a29f96
commit cef837425c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 205 additions and 0 deletions

View File

@ -36,6 +36,7 @@
- [Palindrome Number](maths/palindrome.c) - [Palindrome Number](maths/palindrome.c)
- [Fibonacci Series](maths/fibonacci-series.c) - [Fibonacci Series](maths/fibonacci-series.c)
- [Odd or Even Number](maths/odd-or-even-number.c) - [Odd or Even Number](maths/odd-or-even-number.c)
- [Fibonacci Number](maths/fibonacci-number/README.md)
## Queues ## Queues

View File

@ -0,0 +1,4 @@
main
# binary files
*.o
*.exe

View File

@ -0,0 +1,4 @@
run: main.c
.\a.exe
main.c:
gcc .\src\main.c .\src\fib.c -lm

View File

@ -0,0 +1,59 @@
# Fibonacci Number
Fibonacci numbers form a Fibonacci sequence where given any number (excluding first 2 terms) is a sum of its two preceding numbers. Usually, the sequence is either start with 0 and 1 or 1 and 1. Below is a Fibonacci sequnce starting from 0 and 1:
$$
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, \dots
$$
The problem is to calculate the n-th term Fibonacci number given two starting numbers.
## Prerequisites
- C compiler (or IDE)
- MAKE software (optional if you compile the source files manually)
## Instructions
- using makefile
```bash
make # or mingw32-make
```
- compile using gcc
```
cd <path>\fibonacci-number
gcc .\src\main.c
```
## Note
The sequence can be described by a recurrent function as below:
$$
\begin{align*}
F(0) &= 0 \\
F(1) &= 1 \\
F(n) &= F(n-1) + F(n-2)
\end{align*}
$$
- This provides a direct recursive implementation. The time complexity is $O(2^n)$. It can be improved through memomization.
- It can done iteratively using 2 more states variables. The time complexity is $O(n)$.
- There exists a clever logarithmic algorithm $O(\log{n})$ in computing n-th term Fibonacci number. The computations can be in form of matrix multiplication, then we can devise some form of Ancient Egyptian multiplication (i.e.: double and squaring) to improve the algorithm. [reference](https://rybczak.net/2015/11/01/calculation-of-fibonacci-numbers-in-logarithmic-number-of-steps/)
- Lastly, there also exist a formula to approximate n-term Fibonacci number $O(1)$. [reference](https://mathworld.wolfram.com/BinetsFibonacciNumberFormula.html)
The given implementations shall assume that the Fibonacci sequence is starting from 0 and 1. The reader may try to generalize it to certain extent as a practice.
## Test Cases & Output
1. Example output of calling function:
```
/* some code */
printf("%d", iter_fib(7));
printf("%d\n", memo_fib(7));
/* some code */
```
```
13
13
```
2. The code should yield the same output as other version.
3. The sum of even Fibonacci numbers below 4000000 should be 4613732. [Adapted from Project Euler.net](https://projecteuler.net/problem=2)

View File

@ -0,0 +1,92 @@
#include"fib.h"
#include<math.h> // sqrt, pow are used in binet_fib
int recur_fib(int n){
if(n == 0 || n == 1)
return n;
else
return recur_fib(n-1) + recur_fib(n-2);
}
int iter_fib(int n){
if(n == 0 || n == 1)
return n;
int prev2 = 0;
int prev1 = 1;
int res = prev1 + prev2;
for(n = n - 2; n > 0; --n){
prev2 = prev1;
prev1 = res;
res = prev1 + prev2;
}
return res;
}
// it should be called before using the function memo_fib()
void memomizing_fib(){
memomized_fib[0] = 0;
memomized_fib[1] = 1;
for(int i = 2; i < MAXSIZE; ++i)
memomized_fib[i] = memomized_fib[i-1]+memomized_fib[i-2];
}
// return memomized value if exists, or else compute it as usual
int memo_fib(int n){
if(n < MAXSIZE && n >= 0)
return memomized_fib[n];
else
return memo_fib(n-1) + memo_fib(n-2);
}
/**
* fibonacci based linear transformation (linear algebra)
* reference: https://rybczak.net/2015/11/01/calculation-of-fibonacci-numbers-in-logarithmic-number-of-steps/
*/
int iter_log_fib(int n){
int a = 0;
int b = 1;
int p = 0;
int q = 1;
while(n > 0){
if(n%2 == 0){
int prev_p = p;
int prev_q = q;
p = prev_p*prev_p + prev_q*prev_q;
q = (2*prev_p + prev_q)*prev_q;
n = n/2;
}
else{
int prev_a = a;
int prev_b = b;
--n;
a = p*prev_a + q*prev_b;
b = q*prev_a + (p+q)*prev_b;
}
}
return a;
}
/**
* fibonacci based linear transformation (linear algebra)
* reference: https://rybczak.net/2015/11/01/calculation-of-fibonacci-numbers-in-logarithmic-number-of-steps/
*/
int log_fib_helper(int n, int a, int b, int p, int q){
if(n == 0)
return a;
else if(n%2 == 0)
return log_fib_helper(n/2, a, b, p*p+q*q, (2*p+q)*q);
else
return log_fib_helper(n-1, p*a + q*b, q*a+(p+q)*b, p, q);
}
int log_fib(int n){
return log_fib_helper(n,0,1,0,1);
}
/**
* Closed form formula
* reference: https://mathworld.wolfram.com/BinetsFibonacciNumberFormula.html
*/
int binet_fib(int n){
const double golden_ratio = (1+sqrt(5))/2;
const double conjugate_golden_ratio = 1-golden_ratio;
double res = (pow(golden_ratio,n) - pow(conjugate_golden_ratio, n))/sqrt(5);
return round(res);
}

View File

@ -0,0 +1,22 @@
#ifndef FIB_H_INCLUDED
#define FIB_H_INCLUDED
/**
* fib(n) takes nonnegative number n
* return n-th term fibonacci number.
* The prefix highlights its algorithm used
*/
int recur_fib(int n);
int iter_fib(int n);
#define MAXSIZE 30
int memomized_fib[MAXSIZE];
void memomizing_fib(); // it should be called before using the function memo_fib()
int memo_fib(int n);
int iter_log_fib(int n);
int log_fib(int n);
int binet_fib(int n);
#endif

View File

@ -0,0 +1,23 @@
#include<stdio.h>
#include"fib.h"
int main(){
memomizing_fib(); // this is to initialize the memomized table
int n = 15;
printf("%d\n", recur_fib(n)); // it becomes slow as n get larger for recur_fib
for(int i = 0; i <= 35; ++i){
printf("n = %d\t", i);
printf(" %d", iter_fib(i));
printf(" %d", memo_fib(i));
printf(" %d", log_fib(i));
printf(" %d", binet_fib(i));
printf(" %d\n", iter_log_fib(i));
}
int sum = 0;
int bound = 4000000;
for(int i = 0; memo_fib(i) < bound; ++i)
if(memo_fib(i)%2 == 0)
sum += memo_fib(i);
printf("The sum of even Fibonacci number below %d = %d", bound, sum);
return 0;
}