Skip to content

Commit 3ad90ce

Browse files
08183080pre-commit-ci[bot]cclauss
authored
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 <[email protected]>
1 parent d59cf17 commit 3ad90ce

File tree

1 file changed

+51
-28
lines changed

1 file changed

+51
-28
lines changed

Diff for: maths/fibonacci.py

+51-28
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# fibonacci.py
21
"""
32
Calculates the Fibonacci sequence using iteration, recursion, memoization,
43
and a simplified form of Binet's formula
@@ -9,14 +8,12 @@
98
NOTE 2: the Binet's formula function is much more limited in the size of inputs
109
that it can handle due to the size limitations of Python floats
1110
12-
RESULTS: (n = 20)
13-
fib_iterative runtime: 0.0055 ms
14-
fib_recursive runtime: 6.5627 ms
15-
fib_memoization runtime: 0.0107 ms
16-
fib_binet runtime: 0.0174 ms
11+
See benchmark numbers in __main__ for performance comparisons/
12+
https://en.wikipedia.org/wiki/Fibonacci_number for more information
1713
"""
1814

1915
import functools
16+
from collections.abc import Iterator
2017
from math import sqrt
2118
from time import time
2219

@@ -35,6 +32,31 @@ def time_func(func, *args, **kwargs):
3532
return output
3633

3734

35+
def fib_iterative_yield(n: int) -> Iterator[int]:
36+
"""
37+
Calculates the first n (1-indexed) Fibonacci numbers using iteration with yield
38+
>>> list(fib_iterative_yield(0))
39+
[0]
40+
>>> tuple(fib_iterative_yield(1))
41+
(0, 1)
42+
>>> tuple(fib_iterative_yield(5))
43+
(0, 1, 1, 2, 3, 5)
44+
>>> tuple(fib_iterative_yield(10))
45+
(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55)
46+
>>> tuple(fib_iterative_yield(-1))
47+
Traceback (most recent call last):
48+
...
49+
ValueError: n is negative
50+
"""
51+
if n < 0:
52+
raise ValueError("n is negative")
53+
a, b = 0, 1
54+
yield a
55+
for _ in range(n):
56+
yield b
57+
a, b = b, a + b
58+
59+
3860
def fib_iterative(n: int) -> list[int]:
3961
"""
4062
Calculates the first n (0-indexed) Fibonacci numbers using iteration
@@ -49,10 +71,10 @@ def fib_iterative(n: int) -> list[int]:
4971
>>> fib_iterative(-1)
5072
Traceback (most recent call last):
5173
...
52-
Exception: n is negative
74+
ValueError: n is negative
5375
"""
5476
if n < 0:
55-
raise Exception("n is negative")
77+
raise ValueError("n is negative")
5678
if n == 0:
5779
return [0]
5880
fib = [0, 1]
@@ -75,7 +97,7 @@ def fib_recursive(n: int) -> list[int]:
7597
>>> fib_iterative(-1)
7698
Traceback (most recent call last):
7799
...
78-
Exception: n is negative
100+
ValueError: n is negative
79101
"""
80102

81103
def fib_recursive_term(i: int) -> int:
@@ -95,13 +117,13 @@ def fib_recursive_term(i: int) -> int:
95117
Exception: n is negative
96118
"""
97119
if i < 0:
98-
raise Exception("n is negative")
120+
raise ValueError("n is negative")
99121
if i < 2:
100122
return i
101123
return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)
102124

103125
if n < 0:
104-
raise Exception("n is negative")
126+
raise ValueError("n is negative")
105127
return [fib_recursive_term(i) for i in range(n + 1)]
106128

107129

@@ -119,7 +141,7 @@ def fib_recursive_cached(n: int) -> list[int]:
119141
>>> fib_iterative(-1)
120142
Traceback (most recent call last):
121143
...
122-
Exception: n is negative
144+
ValueError: n is negative
123145
"""
124146

125147
@functools.cache
@@ -128,13 +150,13 @@ def fib_recursive_term(i: int) -> int:
128150
Calculates the i-th (0-indexed) Fibonacci number using recursion
129151
"""
130152
if i < 0:
131-
raise Exception("n is negative")
153+
raise ValueError("n is negative")
132154
if i < 2:
133155
return i
134156
return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)
135157

136158
if n < 0:
137-
raise Exception("n is negative")
159+
raise ValueError("n is negative")
138160
return [fib_recursive_term(i) for i in range(n + 1)]
139161

140162

@@ -152,10 +174,10 @@ def fib_memoization(n: int) -> list[int]:
152174
>>> fib_iterative(-1)
153175
Traceback (most recent call last):
154176
...
155-
Exception: n is negative
177+
ValueError: n is negative
156178
"""
157179
if n < 0:
158-
raise Exception("n is negative")
180+
raise ValueError("n is negative")
159181
# Cache must be outside recursuive function
160182
# other it will reset every time it calls itself.
161183
cache: dict[int, int] = {0: 0, 1: 1, 2: 1} # Prefilled cache
@@ -193,29 +215,30 @@ def fib_binet(n: int) -> list[int]:
193215
>>> fib_binet(-1)
194216
Traceback (most recent call last):
195217
...
196-
Exception: n is negative
218+
ValueError: n is negative
197219
>>> fib_binet(1475)
198220
Traceback (most recent call last):
199221
...
200-
Exception: n is too large
222+
ValueError: n is too large
201223
"""
202224
if n < 0:
203-
raise Exception("n is negative")
225+
raise ValueError("n is negative")
204226
if n >= 1475:
205-
raise Exception("n is too large")
227+
raise ValueError("n is too large")
206228
sqrt_5 = sqrt(5)
207229
phi = (1 + sqrt_5) / 2
208230
return [round(phi**i / sqrt_5) for i in range(n + 1)]
209231

210232

211233
if __name__ == "__main__":
212-
import doctest
213-
214-
doctest.testmod()
234+
from doctest import testmod
215235

236+
testmod()
237+
# Time on an M1 MacBook Pro -- Fastest to slowest
216238
num = 30
217-
time_func(fib_iterative, num)
218-
time_func(fib_recursive, num) # Around 3s runtime
219-
time_func(fib_recursive_cached, num) # Around 0ms runtime
220-
time_func(fib_memoization, num)
221-
time_func(fib_binet, num)
239+
time_func(fib_iterative_yield, num) # 0.0012 ms
240+
time_func(fib_iterative, num) # 0.0031 ms
241+
time_func(fib_binet, num) # 0.0062 ms
242+
time_func(fib_memoization, num) # 0.0100 ms
243+
time_func(fib_recursive_cached, num) # 0.0153 ms
244+
time_func(fib_recursive, num) # 257.0910 ms

0 commit comments

Comments
 (0)