14
14
from math import isqrt
15
15
16
16
17
- def calculate_prime_numbers (max_number : int ) -> list [int ]:
17
+ def slow_calculate_prime_numbers (max_number : int ) -> list [int ]:
18
18
"""
19
- Returns prime numbers below max_number
19
+ Returns prime numbers below max_number.
20
+ See: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
20
21
21
- >>> calculate_prime_numbers (10)
22
+ >>> slow_calculate_prime_numbers (10)
22
23
[2, 3, 5, 7]
24
+
25
+ >>> slow_calculate_prime_numbers(2)
26
+ []
23
27
"""
24
28
29
+ # List containing a bool value for every number below max_number/2
25
30
is_prime = [True ] * max_number
31
+
26
32
for i in range (2 , isqrt (max_number - 1 ) + 1 ):
27
33
if is_prime [i ]:
34
+ # Mark all multiple of i as not prime
28
35
for j in range (i ** 2 , max_number , i ):
29
36
is_prime [j ] = False
30
37
31
38
return [i for i in range (2 , max_number ) if is_prime [i ]]
32
39
33
40
34
- def solution (max_number : int = 10 ** 8 ) -> int :
41
+ def calculate_prime_numbers (max_number : int ) -> list [int ]:
42
+ """
43
+ Returns prime numbers below max_number.
44
+ See: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
45
+
46
+ >>> calculate_prime_numbers(10)
47
+ [2, 3, 5, 7]
48
+
49
+ >>> calculate_prime_numbers(2)
50
+ []
51
+ """
52
+
53
+ if max_number <= 2 :
54
+ return []
55
+
56
+ # List containing a bool value for every odd number below max_number/2
57
+ is_prime = [True ] * (max_number // 2 )
58
+
59
+ for i in range (3 , isqrt (max_number - 1 ) + 1 , 2 ):
60
+ if is_prime [i // 2 ]:
61
+ # Mark all multiple of i as not prime using list slicing
62
+ is_prime [i ** 2 // 2 :: i ] = [False ] * (
63
+ # Same as: (max_number - (i**2)) // (2 * i) + 1
64
+ # but faster than len(is_prime[i**2 // 2 :: i])
65
+ len (range (i ** 2 // 2 , max_number // 2 , i ))
66
+ )
67
+
68
+ return [2 ] + [2 * i + 1 for i in range (1 , max_number // 2 ) if is_prime [i ]]
69
+
70
+
71
+ def slow_solution (max_number : int = 10 ** 8 ) -> int :
35
72
"""
36
73
Returns the number of composite integers below max_number have precisely two,
37
- not necessarily distinct, prime factors
74
+ not necessarily distinct, prime factors.
38
75
39
- >>> solution(30)
76
+ >>> slow_solution(30)
77
+ 10
78
+ """
79
+
80
+ prime_numbers = slow_calculate_prime_numbers (max_number // 2 )
81
+
82
+ semiprimes_count = 0
83
+ left = 0
84
+ right = len (prime_numbers ) - 1
85
+ while left <= right :
86
+ while prime_numbers [left ] * prime_numbers [right ] >= max_number :
87
+ right -= 1
88
+ semiprimes_count += right - left + 1
89
+ left += 1
90
+
91
+ return semiprimes_count
92
+
93
+
94
+ def while_solution (max_number : int = 10 ** 8 ) -> int :
95
+ """
96
+ Returns the number of composite integers below max_number have precisely two,
97
+ not necessarily distinct, prime factors.
98
+
99
+ >>> while_solution(30)
40
100
10
41
101
"""
42
102
@@ -54,5 +114,49 @@ def solution(max_number: int = 10**8) -> int:
54
114
return semiprimes_count
55
115
56
116
117
+ def solution (max_number : int = 10 ** 8 ) -> int :
118
+ """
119
+ Returns the number of composite integers below max_number have precisely two,
120
+ not necessarily distinct, prime factors.
121
+
122
+ >>> solution(30)
123
+ 10
124
+ """
125
+
126
+ prime_numbers = calculate_prime_numbers (max_number // 2 )
127
+
128
+ semiprimes_count = 0
129
+ right = len (prime_numbers ) - 1
130
+ for left in range (len (prime_numbers )):
131
+ if left > right :
132
+ break
133
+ for r in range (right , left - 2 , - 1 ):
134
+ if prime_numbers [left ] * prime_numbers [r ] < max_number :
135
+ break
136
+ right = r
137
+ semiprimes_count += right - left + 1
138
+
139
+ return semiprimes_count
140
+
141
+
142
+ def benchmark () -> None :
143
+ """
144
+ Benchmarks
145
+ """
146
+ # Running performance benchmarks...
147
+ # slow_solution : 108.50874730000032
148
+ # while_sol : 28.09581200000048
149
+ # solution : 25.063097400000515
150
+
151
+ from timeit import timeit
152
+
153
+ print ("Running performance benchmarks..." )
154
+
155
+ print (f"slow_solution : { timeit ('slow_solution()' , globals = globals (), number = 10 )} " )
156
+ print (f"while_sol : { timeit ('while_solution()' , globals = globals (), number = 10 )} " )
157
+ print (f"solution : { timeit ('solution()' , globals = globals (), number = 10 )} " )
158
+
159
+
57
160
if __name__ == "__main__" :
58
- print (f"{ solution () = } " )
161
+ print (f"Solution: { solution ()} " )
162
+ benchmark ()
0 commit comments