From 2fa555b37db9d4fe2702dc63329fabd7c7d705e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E9=BE=99?= <51738561+08183080@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:21:46 +0800 Subject: [PATCH 1/6] add a yiled method to fibonaci --- maths/fibonacci.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/maths/fibonacci.py b/maths/fibonacci.py index e810add69dc7..9fe42d59a373 100644 --- a/maths/fibonacci.py +++ b/maths/fibonacci.py @@ -19,6 +19,7 @@ import functools from math import sqrt from time import time +from collections.abc import Generator def time_func(func, *args, **kwargs): @@ -60,6 +61,22 @@ def fib_iterative(n: int) -> list[int]: fib.append(fib[-1] + fib[-2]) return fib +def fib_iterative_yield(n: int) -> Generator[int]: + """ + Calculates the first n (1-indexed) Fibonacci numbers using iteration with yield method to save memory + >>> f = fib_iterative_yield(3) + >>> next(f) + 1 + >>> next(f) + 1 + >>> next(f) + 2 + """ + a, b = 0, 1 + for _ in range(n): + yield b + a, b = b, a + b + def fib_recursive(n: int) -> list[int]: """ @@ -196,6 +213,8 @@ def fib_binet(n: int) -> list[int]: return [round(phi**i / sqrt_5) for i in range(n + 1)] + + if __name__ == "__main__": num = 30 time_func(fib_iterative, num) @@ -203,3 +222,5 @@ def fib_binet(n: int) -> list[int]: time_func(fib_recursive_cached, num) # Around 0ms runtime time_func(fib_memoization, num) time_func(fib_binet, num) + time_func(fib_iterative_yield, num) + From 36016831394a5ec34c51b325403f11d0b8e67ca5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 06:24:24 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- maths/fibonacci.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/maths/fibonacci.py b/maths/fibonacci.py index 9fe42d59a373..c4f3d66f2902 100644 --- a/maths/fibonacci.py +++ b/maths/fibonacci.py @@ -61,6 +61,7 @@ def fib_iterative(n: int) -> list[int]: fib.append(fib[-1] + fib[-2]) return fib + def fib_iterative_yield(n: int) -> Generator[int]: """ Calculates the first n (1-indexed) Fibonacci numbers using iteration with yield method to save memory @@ -213,8 +214,6 @@ def fib_binet(n: int) -> list[int]: return [round(phi**i / sqrt_5) for i in range(n + 1)] - - if __name__ == "__main__": num = 30 time_func(fib_iterative, num) @@ -222,5 +221,4 @@ def fib_binet(n: int) -> list[int]: time_func(fib_recursive_cached, num) # Around 0ms runtime time_func(fib_memoization, num) time_func(fib_binet, num) - time_func(fib_iterative_yield, num) - + time_func(fib_iterative_yield, num) From c25c1f06f6a28bdff2d1f7d691e4f6c64eee1cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E9=BE=99?= <51738561+08183080@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:30:10 +0800 Subject: [PATCH 3/6] fibonaci --- maths/fibonacci.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/maths/fibonacci.py b/maths/fibonacci.py index 9fe42d59a373..fa633e0200a3 100644 --- a/maths/fibonacci.py +++ b/maths/fibonacci.py @@ -19,7 +19,7 @@ import functools from math import sqrt from time import time -from collections.abc import Generator +from collections.abc import Iterator def time_func(func, *args, **kwargs): @@ -61,10 +61,9 @@ def fib_iterative(n: int) -> list[int]: fib.append(fib[-1] + fib[-2]) return fib -def fib_iterative_yield(n: int) -> Generator[int]: +def fib_iterative_yield(n: int) -> Iterator[int]: """ - Calculates the first n (1-indexed) Fibonacci numbers using iteration with yield method to save memory - >>> f = fib_iterative_yield(3) + Calculates the first n (1-indexed) Fibonacci numbers using iteration with yield >>> next(f) 1 >>> next(f) From 45c7e52a0e7a0af09b6e08809d4b873c39c0db1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E9=BE=99?= <51738561+08183080@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:34:36 +0800 Subject: [PATCH 4/6] Update fibonacci.py --- maths/fibonacci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maths/fibonacci.py b/maths/fibonacci.py index 2df7e0e23812..c35f36cefaa4 100644 --- a/maths/fibonacci.py +++ b/maths/fibonacci.py @@ -17,9 +17,9 @@ """ import functools +from collections.abc import Iterator from math import sqrt from time import time -from collections.abc import Iterator def time_func(func, *args, **kwargs): From 2dc798bd7a7a36eddee6e600e703ff40cdbea01d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 06:36:32 +0000 Subject: [PATCH 5/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- maths/fibonacci.py | 1 + 1 file changed, 1 insertion(+) diff --git a/maths/fibonacci.py b/maths/fibonacci.py index c35f36cefaa4..b6484aaa5362 100644 --- a/maths/fibonacci.py +++ b/maths/fibonacci.py @@ -61,6 +61,7 @@ def fib_iterative(n: int) -> list[int]: fib.append(fib[-1] + fib[-2]) return fib + def fib_iterative_yield(n: int) -> Iterator[int]: """ Calculates the first n (1-indexed) Fibonacci numbers using iteration with yield From ff4f3878e4c50bb4e4c0f8724423ec374ae9da2f Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sun, 29 Oct 2023 16:35:06 +0100 Subject: [PATCH 6/6] Update fibonacci.py --- maths/fibonacci.py | 93 +++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/maths/fibonacci.py b/maths/fibonacci.py index b6484aaa5362..95068c980292 100644 --- a/maths/fibonacci.py +++ b/maths/fibonacci.py @@ -1,4 +1,3 @@ -# fibonacci.py """ Calculates the Fibonacci sequence using iteration, recursion, memoization, and a simplified form of Binet's formula @@ -9,11 +8,8 @@ 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 -RESULTS: (n = 20) -fib_iterative runtime: 0.0055 ms -fib_recursive runtime: 6.5627 ms -fib_memoization runtime: 0.0107 ms -fib_binet runtime: 0.0174 ms +See benchmark numbers in __main__ for performance comparisons/ +https://en.wikipedia.org/wiki/Fibonacci_number for more information """ import functools @@ -36,6 +32,31 @@ def time_func(func, *args, **kwargs): 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]: """ Calculates the first n (0-indexed) Fibonacci numbers using iteration @@ -50,10 +71,10 @@ def fib_iterative(n: int) -> list[int]: >>> fib_iterative(-1) Traceback (most recent call last): ... - Exception: n is negative + ValueError: n is negative """ if n < 0: - raise Exception("n is negative") + raise ValueError("n is negative") if n == 0: return [0] fib = [0, 1] @@ -62,22 +83,6 @@ def fib_iterative(n: int) -> list[int]: return fib -def fib_iterative_yield(n: int) -> Iterator[int]: - """ - Calculates the first n (1-indexed) Fibonacci numbers using iteration with yield - >>> next(f) - 1 - >>> next(f) - 1 - >>> next(f) - 2 - """ - a, b = 0, 1 - for _ in range(n): - yield b - a, b = b, a + b - - def fib_recursive(n: int) -> list[int]: """ Calculates the first n (0-indexed) Fibonacci numbers using recursion @@ -92,7 +97,7 @@ def fib_recursive(n: int) -> list[int]: >>> fib_iterative(-1) Traceback (most recent call last): ... - Exception: n is negative + ValueError: n is negative """ def fib_recursive_term(i: int) -> int: @@ -100,13 +105,13 @@ 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") + raise ValueError("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") + raise ValueError("n is negative") return [fib_recursive_term(i) for i in range(n + 1)] @@ -124,7 +129,7 @@ def fib_recursive_cached(n: int) -> list[int]: >>> fib_iterative(-1) Traceback (most recent call last): ... - Exception: n is negative + ValueError: n is negative """ @functools.cache @@ -133,13 +138,13 @@ 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") + raise ValueError("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") + raise ValueError("n is negative") return [fib_recursive_term(i) for i in range(n + 1)] @@ -157,10 +162,10 @@ def fib_memoization(n: int) -> list[int]: >>> fib_iterative(-1) Traceback (most recent call last): ... - Exception: n is negative + ValueError: n is negative """ if n < 0: - raise Exception("n is negative") + raise ValueError("n is negative") # Cache must be outside recursuive function # other it will reset every time it calls itself. cache: dict[int, int] = {0: 0, 1: 1, 2: 1} # Prefilled cache @@ -198,26 +203,30 @@ def fib_binet(n: int) -> list[int]: >>> fib_binet(-1) Traceback (most recent call last): ... - Exception: n is negative + ValueError: n is negative >>> fib_binet(1475) Traceback (most recent call last): ... - Exception: n is too large + ValueError: n is too large """ if n < 0: - raise Exception("n is negative") + raise ValueError("n is negative") if n >= 1475: - raise Exception("n is too large") + raise ValueError("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__": + from doctest import testmod + + testmod() + # Time on an M1 MacBook Pro -- Fastest to slowest num = 30 - time_func(fib_iterative, num) - time_func(fib_recursive, num) # Around 3s runtime - time_func(fib_recursive_cached, num) # Around 0ms runtime - time_func(fib_memoization, num) - time_func(fib_binet, num) - time_func(fib_iterative_yield, num) + time_func(fib_iterative_yield, num) # 0.0012 ms + time_func(fib_iterative, num) # 0.0031 ms + time_func(fib_binet, num) # 0.0062 ms + time_func(fib_memoization, num) # 0.0100 ms + time_func(fib_recursive_cached, num) # 0.0153 ms + time_func(fib_recursive, num) # 257.0910 ms