mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-12-18 09:10:16 +00:00
84cca2119c
* Rewrite parts of Vector and Matrix methods * Refactor determinant method and add unit tests Refactor determinant method to create separate minor and cofactor methods. Add respective unit tests for new methods. Rename methods using snake case to follow Python naming conventions. * Reorganize Vector and Matrix methods * Update linear_algebra/README.md Co-authored-by: John Law <johnlaw.po@gmail.com> * Fix punctuation and wording * Apply suggestions from code review Co-authored-by: John Law <johnlaw.po@gmail.com> * Deduplicate euclidean length method for Vector * Add more unit tests for Euclidean length method * Fix bug in unit test for euclidean_length * Remove old comments for magnitude method * Rewrite maths/fibonacci.py * Rewrite timer and add unit tests * Fix typos in fib_binet unit tests * Fix typos in fib_binet unit tests * Clean main method Co-authored-by: John Law <johnlaw.po@gmail.com>
131 lines
3.4 KiB
Python
131 lines
3.4 KiB
Python
# 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 doesn't accept n >= 1475 because it overflows
|
|
thereafter due to 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)
|