From db2fee616a0d129325c1d53cd853477e5674d6b4 Mon Sep 17 00:00:00 2001 From: Manpreet Singh <63737630+ManpreetSingh2004@users.noreply.github.com> Date: Sun, 15 Oct 2023 14:02:22 +0530 Subject: [PATCH 1/9] Add comments and wikipedia link in calculate_prime_numbers --- project_euler/problem_187/sol1.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index 12f03e2a7023..221d6386d98a 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -16,15 +16,19 @@ def calculate_prime_numbers(max_number: int) -> list[int]: """ - Returns prime numbers below max_number + Returns prime numbers below max_number. + See: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes >>> calculate_prime_numbers(10) [2, 3, 5, 7] """ + # List containing a bool value for every number below max_number/2 is_prime = [True] * max_number + for i in range(2, isqrt(max_number - 1) + 1): if is_prime[i]: + # Mark all multiple of i as not prime for j in range(i**2, max_number, i): is_prime[j] = False From efef87696dae48284fcc9d23ea493eadb0555aaf Mon Sep 17 00:00:00 2001 From: Manpreet Singh <63737630+ManpreetSingh2004@users.noreply.github.com> Date: Sun, 15 Oct 2023 14:04:27 +0530 Subject: [PATCH 2/9] Add improved calculate_prime_numbers --- project_euler/problem_187/sol1.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index 221d6386d98a..06c9a2aa2b10 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -14,12 +14,12 @@ from math import isqrt -def calculate_prime_numbers(max_number: int) -> list[int]: +def slow_calculate_prime_numbers(max_number: int) -> list[int]: """ Returns prime numbers below max_number. See: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes - >>> calculate_prime_numbers(10) + >>> slow_calculate_prime_numbers(10) [2, 3, 5, 7] """ @@ -35,6 +35,33 @@ def calculate_prime_numbers(max_number: int) -> list[int]: return [i for i in range(2, max_number) if is_prime[i]] +def calculate_prime_numbers(max_number: int) -> list[int]: + """ + Returns prime numbers below max_number. + See: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes + + >>> calculate_prime_numbers(10) + [2, 3, 5, 7] + """ + + if max_number <= 2: + return [] + + # List containing a bool value for every odd number below max_number/2 + is_prime = [True] * (max_number // 2) + + for i in range(3, isqrt(max_number - 1) + 1, 2): + if is_prime[i // 2]: + # Mark all multiple of i as not prime using list slicing + is_prime[i**2 // 2 :: i] = [False] * ( + # Same as: (max_number - (i**2)) // (2 * i) + 1 + # but faster than len(is_prime[i**2 // 2 :: i]) + len(range(i**2 // 2, max_number // 2, i)) + ) + + return [2] + [2 * i + 1 for i in range(1, max_number // 2) if is_prime[i]] + + def solution(max_number: int = 10**8) -> int: """ Returns the number of composite integers below max_number have precisely two, From c8dd3257da58a9763b19f3ffb330fd46501e9728 Mon Sep 17 00:00:00 2001 From: Manpreet Singh <63737630+ManpreetSingh2004@users.noreply.github.com> Date: Sun, 15 Oct 2023 14:06:35 +0530 Subject: [PATCH 3/9] Separate slow_solution and new_solution --- project_euler/problem_187/sol1.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index 06c9a2aa2b10..a4733de4e101 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -62,6 +62,29 @@ def calculate_prime_numbers(max_number: int) -> list[int]: return [2] + [2 * i + 1 for i in range(1, max_number // 2) if is_prime[i]] +def slow_solution(max_number: int = 10**8) -> int: + """ + Returns the number of composite integers below max_number have precisely two, + not necessarily distinct, prime factors. + + >>> slow_solution(30) + 10 + """ + + prime_numbers = slow_calculate_prime_numbers(max_number // 2) + + semiprimes_count = 0 + left = 0 + right = len(prime_numbers) - 1 + while left <= right: + while prime_numbers[left] * prime_numbers[right] >= max_number: + right -= 1 + semiprimes_count += right - left + 1 + left += 1 + + return semiprimes_count + + def solution(max_number: int = 10**8) -> int: """ Returns the number of composite integers below max_number have precisely two, From cbf22b21e9cc10461ea98c1d9d4dc17f4a282c68 Mon Sep 17 00:00:00 2001 From: Manpreet Singh <63737630+ManpreetSingh2004@users.noreply.github.com> Date: Sun, 15 Oct 2023 14:19:37 +0530 Subject: [PATCH 4/9] Use for loops in solution --- project_euler/problem_187/sol1.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index a4733de4e101..68c4f89c120d 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -88,7 +88,7 @@ def slow_solution(max_number: int = 10**8) -> int: def solution(max_number: int = 10**8) -> int: """ Returns the number of composite integers below max_number have precisely two, - not necessarily distinct, prime factors + not necessarily distinct, prime factors. >>> solution(30) 10 @@ -97,16 +97,18 @@ def solution(max_number: int = 10**8) -> int: prime_numbers = calculate_prime_numbers(max_number // 2) semiprimes_count = 0 - left = 0 right = len(prime_numbers) - 1 - while left <= right: - while prime_numbers[left] * prime_numbers[right] >= max_number: - right -= 1 + for left in range(len(prime_numbers)): + if left > right: + break + for r in range(right, left - 2, -1): + if prime_numbers[left] * prime_numbers[r] < max_number: + break + right = r semiprimes_count += right - left + 1 - left += 1 return semiprimes_count if __name__ == "__main__": - print(f"{solution() = }") + print(f"Solution: {solution()}") From 4dff7f0c6892e1c9531e542bfa78cbc616118f44 Mon Sep 17 00:00:00 2001 From: Manpreet Singh <63737630+ManpreetSingh2004@users.noreply.github.com> Date: Sun, 15 Oct 2023 14:22:09 +0530 Subject: [PATCH 5/9] Separate while_solution and new solution --- project_euler/problem_187/sol1.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index 68c4f89c120d..9be3bdddf22b 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -85,6 +85,29 @@ def slow_solution(max_number: int = 10**8) -> int: return semiprimes_count +def while_solution(max_number: int = 10**8) -> int: + """ + Returns the number of composite integers below max_number have precisely two, + not necessarily distinct, prime factors. + + >>> while_solution(30) + 10 + """ + + prime_numbers = calculate_prime_numbers(max_number // 2) + + semiprimes_count = 0 + left = 0 + right = len(prime_numbers) - 1 + while left <= right: + while prime_numbers[left] * prime_numbers[right] >= max_number: + right -= 1 + semiprimes_count += right - left + 1 + left += 1 + + return semiprimes_count + + def solution(max_number: int = 10**8) -> int: """ Returns the number of composite integers below max_number have precisely two, From 9982e3d5ad01a0aa85ca48ca5a7f5dd04b396981 Mon Sep 17 00:00:00 2001 From: Manpreet Singh <63737630+ManpreetSingh2004@users.noreply.github.com> Date: Sun, 15 Oct 2023 14:25:24 +0530 Subject: [PATCH 6/9] Add performance benchmark --- project_euler/problem_187/sol1.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index 9be3bdddf22b..f5c397808130 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -133,5 +133,24 @@ def solution(max_number: int = 10**8) -> int: return semiprimes_count +def benchmark() -> None: + """ + Benchmarks + """ + # Running performance benchmarks... + # slow_solution : 108.50874730000032 + # while_sol : 28.09581200000048 + # solution : 25.063097400000515 + + from timeit import timeit + + print("Running performance benchmarks...") + + print(f"slow_solution : {timeit('slow_solution()', globals=globals(), number=10)}") + print(f"while_sol : {timeit('while_solution()', globals=globals(), number=10)}") + print(f"solution : {timeit('solution()', globals=globals(), number=10)}") + + if __name__ == "__main__": print(f"Solution: {solution()}") + benchmark() From b7c204da4c79942c261d2b9864adca0c8ec3fb9a Mon Sep 17 00:00:00 2001 From: Manpreet Singh <63737630+ManpreetSingh2004@users.noreply.github.com> Date: Sun, 15 Oct 2023 14:31:48 +0530 Subject: [PATCH 7/9] Add doctest for calculate_prime_numbers --- project_euler/problem_187/sol1.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index f5c397808130..9b4eb7cb9ab6 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -21,6 +21,9 @@ def slow_calculate_prime_numbers(max_number: int) -> list[int]: >>> slow_calculate_prime_numbers(10) [2, 3, 5, 7] + + >>> slow_calculate_prime_numbers(2) + [] """ # List containing a bool value for every number below max_number/2 @@ -42,6 +45,9 @@ def calculate_prime_numbers(max_number: int) -> list[int]: >>> calculate_prime_numbers(10) [2, 3, 5, 7] + + >>> calculate_prime_numbers(2) + [] """ if max_number <= 2: From 0c8f1448a407be405459417d8067a48e9aa6bedd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 15 Oct 2023 09:05:28 +0000 Subject: [PATCH 8/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- project_euler/problem_187/sol1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index 9b4eb7cb9ab6..8944776fef50 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -21,7 +21,7 @@ def slow_calculate_prime_numbers(max_number: int) -> list[int]: >>> slow_calculate_prime_numbers(10) [2, 3, 5, 7] - + >>> slow_calculate_prime_numbers(2) [] """ @@ -45,7 +45,7 @@ def calculate_prime_numbers(max_number: int) -> list[int]: >>> calculate_prime_numbers(10) [2, 3, 5, 7] - + >>> calculate_prime_numbers(2) [] """ From 8f82a46b32de0d743f882efc1f5148cd969668d5 Mon Sep 17 00:00:00 2001 From: Manpreet Singh <63737630+ManpreetSingh2004@users.noreply.github.com> Date: Sun, 15 Oct 2023 14:36:58 +0530 Subject: [PATCH 9/9] Removed white space --- project_euler/problem_187/sol1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project_euler/problem_187/sol1.py b/project_euler/problem_187/sol1.py index 9b4eb7cb9ab6..8944776fef50 100644 --- a/project_euler/problem_187/sol1.py +++ b/project_euler/problem_187/sol1.py @@ -21,7 +21,7 @@ def slow_calculate_prime_numbers(max_number: int) -> list[int]: >>> slow_calculate_prime_numbers(10) [2, 3, 5, 7] - + >>> slow_calculate_prime_numbers(2) [] """ @@ -45,7 +45,7 @@ def calculate_prime_numbers(max_number: int) -> list[int]: >>> calculate_prime_numbers(10) [2, 3, 5, 7] - + >>> calculate_prime_numbers(2) [] """