Skip to content

Merge maths/fibonacci.py and maths/fibonacci_sequence_recursion.py #5738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ad6c215
Rewrite parts of Vector and Matrix methods
tianyizheng02 Oct 16, 2021
f84d769
Refactor determinant method and add unit tests
tianyizheng02 Oct 17, 2021
86c03a8
Merge branch 'TheAlgorithms:master' into master
tianyizheng02 Oct 17, 2021
72ada86
Merge branch 'TheAlgorithms:master' into master
tianyizheng02 Oct 18, 2021
3756b2f
Reorganize Vector and Matrix methods
tianyizheng02 Oct 18, 2021
04a0845
Update linear_algebra/README.md
tianyizheng02 Oct 19, 2021
53f9953
Fix punctuation and wording
tianyizheng02 Oct 19, 2021
f176b18
Apply suggestions from code review
tianyizheng02 Oct 19, 2021
768bda8
Merge branch 'TheAlgorithms:master' into master
tianyizheng02 Oct 29, 2021
36dd293
Deduplicate euclidean length method for Vector
tianyizheng02 Oct 29, 2021
6615be8
Add more unit tests for Euclidean length method
tianyizheng02 Oct 29, 2021
22af986
Merge branch 'TheAlgorithms:master' into master
tianyizheng02 Oct 29, 2021
c3d5dfd
Fix bug in unit test for euclidean_length
tianyizheng02 Oct 29, 2021
45662fe
Remove old comments for magnitude method
tianyizheng02 Oct 30, 2021
29299ae
Merge branch 'TheAlgorithms:master' into master
tianyizheng02 Oct 30, 2021
cabcf88
Merge branch 'TheAlgorithms:master' into master
tianyizheng02 Oct 31, 2021
66304f9
Rewrite maths/fibonacci.py
tianyizheng02 Oct 31, 2021
ea585c6
Merge branch 'TheAlgorithms:master' into master
tianyizheng02 Nov 1, 2021
3d97fd6
Rewrite timer and add unit tests
tianyizheng02 Nov 1, 2021
2cf941c
Fix typos in fib_binet unit tests
tianyizheng02 Nov 1, 2021
68f33f1
Fix typos in fib_binet unit tests
tianyizheng02 Nov 1, 2021
ba163ac
Merge branch 'master' of github.com:tianyizheng02/Python
tianyizheng02 Nov 1, 2021
2460ff6
Clean main method
tianyizheng02 Nov 1, 2021
64aaad8
Merge fibonacci.py and fibonacci_sequence_recursion.py
tianyizheng02 Nov 1, 2021
08cad1a
Fix fib_binet unit test
tianyizheng02 Nov 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 130 additions & 130 deletions maths/fibonacci.py
Original file line number Diff line number Diff line change
@@ -1,130 +1,130 @@
# fibonacci.py
"""
1. Calculates the iterative fibonacci sequence
2. Calculates the fibonacci sequence with a formula
an = [ Phin - (phi)n ]/Sqrt[5]
reference-->Su, Francis E., et al. "Fibonacci Number Formula." Math Fun Facts.
<http://www.math.hmc.edu/funfacts>
"""
import functools
import math
import time
from decimal import Decimal, getcontext
getcontext().prec = 100
def timer_decorator(func):
@functools.wraps(func)
def timer_wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
if int(end - start) > 0:
print(f"Run time for {func.__name__}: {(end - start):0.2f}s")
else:
print(f"Run time for {func.__name__}: {(end - start)*1000:0.2f}ms")
return func(*args, **kwargs)
return timer_wrapper
# define Python user-defined exceptions
class Error(Exception):
"""Base class for other exceptions"""
class ValueTooLargeError(Error):
"""Raised when the input value is too large"""
class ValueTooSmallError(Error):
"""Raised when the input value is not greater than one"""
class ValueLessThanZero(Error):
"""Raised when the input value is less than zero"""
def _check_number_input(n, min_thresh, max_thresh=None):
"""
:param n: single integer
:type n: int
:param min_thresh: min threshold, single integer
:type min_thresh: int
:param max_thresh: max threshold, single integer
:type max_thresh: int
:return: boolean
"""
try:
if n >= min_thresh and max_thresh is None:
return True
elif min_thresh <= n <= max_thresh:
return True
elif n < 0:
raise ValueLessThanZero
elif n < min_thresh:
raise ValueTooSmallError
elif n > max_thresh:
raise ValueTooLargeError
except ValueLessThanZero:
print("Incorrect Input: number must not be less than 0")
except ValueTooSmallError:
print(
f"Incorrect Input: input number must be > {min_thresh} for the recursive "
"calculation"
)
except ValueTooLargeError:
print(
f"Incorrect Input: input number must be < {max_thresh} for the recursive "
"calculation"
)
return False
@timer_decorator
def fib_iterative(n):
"""
:param n: calculate Fibonacci to the nth integer
:type n:int
:return: Fibonacci sequence as a list
"""
n = int(n)
if _check_number_input(n, 2):
seq_out = [0, 1]
a, b = 0, 1
for _ in range(n - len(seq_out)):
a, b = b, a + b
seq_out.append(b)
return seq_out
@timer_decorator
def fib_formula(n):
"""
:param n: calculate Fibonacci to the nth integer
:type n:int
:return: Fibonacci sequence as a list
"""
seq_out = [0, 1]
n = int(n)
if _check_number_input(n, 2, 1000000):
sqrt = Decimal(math.sqrt(5))
phi_1 = Decimal(1 + sqrt) / Decimal(2)
phi_2 = Decimal(1 - sqrt) / Decimal(2)
for i in range(2, n):
temp_out = ((phi_1 ** Decimal(i)) - (phi_2 ** Decimal(i))) * (
Decimal(sqrt) ** Decimal(-1)
)
seq_out.append(int(temp_out))
return seq_out
if __name__ == "__main__":
num = 20
# print(f'{fib_recursive(num)}\n')
# print(f'{fib_iterative(num)}\n')
# print(f'{fib_formula(num)}\n')
fib_iterative(num)
fib_formula(num)
# fibonacci.py
"""
Calculates the Fibonacci sequence using iteration, recursion, and a simplified
form of Binet's formula

NOTE 1: the iterative and recursive functions are more accurate than the Binet's
formula function because the iterative function doesn't use floats

NOTE 2: the Binet's formula function is much more limited in the size of inputs
that it can handle due to the size limitations of Python floats
"""

from math import sqrt
from time import time


def time_func(func, *args, **kwargs):
"""
Times the execution of a function with parameters
"""
start = time()
output = func(*args, **kwargs)
end = time()
if int(end - start) > 0:
print(f"{func.__name__} runtime: {(end - start):0.4f} s")
else:
print(f"{func.__name__} runtime: {(end - start) * 1000:0.4f} ms")
return output


def fib_iterative(n: int) -> list[int]:
"""
Calculates the first n (0-indexed) Fibonacci numbers using iteration
>>> fib_iterative(0)
[0]
>>> fib_iterative(1)
[0, 1]
>>> fib_iterative(5)
[0, 1, 1, 2, 3, 5]
>>> fib_iterative(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> fib_iterative(-1)
Traceback (most recent call last):
...
Exception: n is negative
"""
if n < 0:
raise Exception("n is negative")
if n == 0:
return [0]
fib = [0, 1]
for _ in range(n - 1):
fib.append(fib[-1] + fib[-2])
return fib


def fib_recursive(n: int) -> list[int]:
"""
Calculates the first n (0-indexed) Fibonacci numbers using recursion
>>> fib_iterative(0)
[0]
>>> fib_iterative(1)
[0, 1]
>>> fib_iterative(5)
[0, 1, 1, 2, 3, 5]
>>> fib_iterative(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> fib_iterative(-1)
Traceback (most recent call last):
...
Exception: n is negative
"""

def fib_recursive_term(i: int) -> int:
"""
Calculates the i-th (0-indexed) Fibonacci number using recursion
"""
if i < 0:
raise Exception("n is negative")
if i < 2:
return i
return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)

if n < 0:
raise Exception("n is negative")
return [fib_recursive_term(i) for i in range(n + 1)]


def fib_binet(n: int) -> list[int]:
"""
Calculates the first n (0-indexed) Fibonacci numbers using a simplified form
of Binet's formula:
https://en.m.wikipedia.org/wiki/Fibonacci_number#Computation_by_rounding

NOTE 1: this function diverges from fib_iterative at around n = 71, likely
due to compounding floating-point arithmetic errors

NOTE 2: this function overflows on n >= 1475 because of the size limitations
of Python floats
>>> fib_binet(0)
[0]
>>> fib_binet(1)
[0, 1]
>>> fib_binet(5)
[0, 1, 1, 2, 3, 5]
>>> fib_binet(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> fib_binet(-1)
Traceback (most recent call last):
...
Exception: n is negative
>>> fib_binet(1475)
Traceback (most recent call last):
...
Exception: n is too large
"""
if n < 0:
raise Exception("n is negative")
if n >= 1475:
raise Exception("n is too large")
sqrt_5 = sqrt(5)
phi = (1 + sqrt_5) / 2
return [round(phi ** i / sqrt_5) for i in range(n + 1)]


if __name__ == "__main__":
num = 20
time_func(fib_iterative, num)
time_func(fib_recursive, num)
time_func(fib_binet, num)
22 changes: 0 additions & 22 deletions maths/fibonacci_sequence_recursion.py

This file was deleted.