1- # fibonacci.py 
21""" 
32Calculates the Fibonacci sequence using iteration, recursion, memoization, 
43and a simplified form of Binet's formula 
98NOTE 2: the Binet's formula function is much more limited in the size of inputs 
109that 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
1915import  functools 
16+ from  collections .abc  import  Iterator 
2017from  math  import  sqrt 
2118from  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+ 
3860def  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
211233if  __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