mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-04-18 03:37:35 +00:00
add a yield method to fibonaci (#10826)
* add a yiled method to fibonaci * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fibonaci * Update fibonacci.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update fibonacci.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
parent
d59cf1734f
commit
3ad90cea83
@ -1,4 +1,3 @@
|
|||||||
# fibonacci.py
|
|
||||||
"""
|
"""
|
||||||
Calculates the Fibonacci sequence using iteration, recursion, memoization,
|
Calculates the Fibonacci sequence using iteration, recursion, memoization,
|
||||||
and a simplified form of Binet's formula
|
and a simplified form of Binet's formula
|
||||||
@ -9,14 +8,12 @@ the Binet's formula function because the Binet formula function uses floats
|
|||||||
NOTE 2: the Binet's formula function is much more limited in the size of inputs
|
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
|
that it can handle due to the size limitations of Python floats
|
||||||
|
|
||||||
RESULTS: (n = 20)
|
See benchmark numbers in __main__ for performance comparisons/
|
||||||
fib_iterative runtime: 0.0055 ms
|
https://en.wikipedia.org/wiki/Fibonacci_number for more information
|
||||||
fib_recursive runtime: 6.5627 ms
|
|
||||||
fib_memoization runtime: 0.0107 ms
|
|
||||||
fib_binet runtime: 0.0174 ms
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
from collections.abc import Iterator
|
||||||
from math import sqrt
|
from math import sqrt
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
@ -35,6 +32,31 @@ def time_func(func, *args, **kwargs):
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
def fib_iterative_yield(n: int) -> Iterator[int]:
|
||||||
|
"""
|
||||||
|
Calculates the first n (1-indexed) Fibonacci numbers using iteration with yield
|
||||||
|
>>> list(fib_iterative_yield(0))
|
||||||
|
[0]
|
||||||
|
>>> tuple(fib_iterative_yield(1))
|
||||||
|
(0, 1)
|
||||||
|
>>> tuple(fib_iterative_yield(5))
|
||||||
|
(0, 1, 1, 2, 3, 5)
|
||||||
|
>>> tuple(fib_iterative_yield(10))
|
||||||
|
(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55)
|
||||||
|
>>> tuple(fib_iterative_yield(-1))
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: n is negative
|
||||||
|
"""
|
||||||
|
if n < 0:
|
||||||
|
raise ValueError("n is negative")
|
||||||
|
a, b = 0, 1
|
||||||
|
yield a
|
||||||
|
for _ in range(n):
|
||||||
|
yield b
|
||||||
|
a, b = b, a + b
|
||||||
|
|
||||||
|
|
||||||
def fib_iterative(n: int) -> list[int]:
|
def fib_iterative(n: int) -> list[int]:
|
||||||
"""
|
"""
|
||||||
Calculates the first n (0-indexed) Fibonacci numbers using iteration
|
Calculates the first n (0-indexed) Fibonacci numbers using iteration
|
||||||
@ -49,10 +71,10 @@ def fib_iterative(n: int) -> list[int]:
|
|||||||
>>> fib_iterative(-1)
|
>>> fib_iterative(-1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: n is negative
|
ValueError: n is negative
|
||||||
"""
|
"""
|
||||||
if n < 0:
|
if n < 0:
|
||||||
raise Exception("n is negative")
|
raise ValueError("n is negative")
|
||||||
if n == 0:
|
if n == 0:
|
||||||
return [0]
|
return [0]
|
||||||
fib = [0, 1]
|
fib = [0, 1]
|
||||||
@ -75,7 +97,7 @@ def fib_recursive(n: int) -> list[int]:
|
|||||||
>>> fib_iterative(-1)
|
>>> fib_iterative(-1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: n is negative
|
ValueError: n is negative
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def fib_recursive_term(i: int) -> int:
|
def fib_recursive_term(i: int) -> int:
|
||||||
@ -95,13 +117,13 @@ def fib_recursive(n: int) -> list[int]:
|
|||||||
Exception: n is negative
|
Exception: n is negative
|
||||||
"""
|
"""
|
||||||
if i < 0:
|
if i < 0:
|
||||||
raise Exception("n is negative")
|
raise ValueError("n is negative")
|
||||||
if i < 2:
|
if i < 2:
|
||||||
return i
|
return i
|
||||||
return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)
|
return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)
|
||||||
|
|
||||||
if n < 0:
|
if n < 0:
|
||||||
raise Exception("n is negative")
|
raise ValueError("n is negative")
|
||||||
return [fib_recursive_term(i) for i in range(n + 1)]
|
return [fib_recursive_term(i) for i in range(n + 1)]
|
||||||
|
|
||||||
|
|
||||||
@ -119,7 +141,7 @@ def fib_recursive_cached(n: int) -> list[int]:
|
|||||||
>>> fib_iterative(-1)
|
>>> fib_iterative(-1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: n is negative
|
ValueError: n is negative
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@functools.cache
|
@functools.cache
|
||||||
@ -128,13 +150,13 @@ def fib_recursive_cached(n: int) -> list[int]:
|
|||||||
Calculates the i-th (0-indexed) Fibonacci number using recursion
|
Calculates the i-th (0-indexed) Fibonacci number using recursion
|
||||||
"""
|
"""
|
||||||
if i < 0:
|
if i < 0:
|
||||||
raise Exception("n is negative")
|
raise ValueError("n is negative")
|
||||||
if i < 2:
|
if i < 2:
|
||||||
return i
|
return i
|
||||||
return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)
|
return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)
|
||||||
|
|
||||||
if n < 0:
|
if n < 0:
|
||||||
raise Exception("n is negative")
|
raise ValueError("n is negative")
|
||||||
return [fib_recursive_term(i) for i in range(n + 1)]
|
return [fib_recursive_term(i) for i in range(n + 1)]
|
||||||
|
|
||||||
|
|
||||||
@ -152,10 +174,10 @@ def fib_memoization(n: int) -> list[int]:
|
|||||||
>>> fib_iterative(-1)
|
>>> fib_iterative(-1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: n is negative
|
ValueError: n is negative
|
||||||
"""
|
"""
|
||||||
if n < 0:
|
if n < 0:
|
||||||
raise Exception("n is negative")
|
raise ValueError("n is negative")
|
||||||
# Cache must be outside recursuive function
|
# Cache must be outside recursuive function
|
||||||
# other it will reset every time it calls itself.
|
# other it will reset every time it calls itself.
|
||||||
cache: dict[int, int] = {0: 0, 1: 1, 2: 1} # Prefilled cache
|
cache: dict[int, int] = {0: 0, 1: 1, 2: 1} # Prefilled cache
|
||||||
@ -193,29 +215,30 @@ def fib_binet(n: int) -> list[int]:
|
|||||||
>>> fib_binet(-1)
|
>>> fib_binet(-1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: n is negative
|
ValueError: n is negative
|
||||||
>>> fib_binet(1475)
|
>>> fib_binet(1475)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: n is too large
|
ValueError: n is too large
|
||||||
"""
|
"""
|
||||||
if n < 0:
|
if n < 0:
|
||||||
raise Exception("n is negative")
|
raise ValueError("n is negative")
|
||||||
if n >= 1475:
|
if n >= 1475:
|
||||||
raise Exception("n is too large")
|
raise ValueError("n is too large")
|
||||||
sqrt_5 = sqrt(5)
|
sqrt_5 = sqrt(5)
|
||||||
phi = (1 + sqrt_5) / 2
|
phi = (1 + sqrt_5) / 2
|
||||||
return [round(phi**i / sqrt_5) for i in range(n + 1)]
|
return [round(phi**i / sqrt_5) for i in range(n + 1)]
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
from doctest import testmod
|
||||||
|
|
||||||
doctest.testmod()
|
|
||||||
|
|
||||||
|
testmod()
|
||||||
|
# Time on an M1 MacBook Pro -- Fastest to slowest
|
||||||
num = 30
|
num = 30
|
||||||
time_func(fib_iterative, num)
|
time_func(fib_iterative_yield, num) # 0.0012 ms
|
||||||
time_func(fib_recursive, num) # Around 3s runtime
|
time_func(fib_iterative, num) # 0.0031 ms
|
||||||
time_func(fib_recursive_cached, num) # Around 0ms runtime
|
time_func(fib_binet, num) # 0.0062 ms
|
||||||
time_func(fib_memoization, num)
|
time_func(fib_memoization, num) # 0.0100 ms
|
||||||
time_func(fib_binet, num)
|
time_func(fib_recursive_cached, num) # 0.0153 ms
|
||||||
|
time_func(fib_recursive, num) # 257.0910 ms
|
||||||
|
Loading…
x
Reference in New Issue
Block a user