teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

追記

2018/10/08 23:47

投稿

hayataka2049
hayataka2049

スコア30939

answer CHANGED
@@ -140,4 +140,88 @@
140
140
 
141
141
  この状態で10^8までだと、手元環境ではエラトステネスの篩の倍弱の実行時間になります。
142
142
 
143
- 軽くプロファイリングした感じだと、一番内側のforループで大半の時間を食っているようです。
143
+ 軽くプロファイリングした感じだと、一番内側のforループで大半の時間を食っているようです。
144
+
145
+
146
+ ### 追記
147
+ 最終的に、numbaのちからで区間篩の方が速くなるところまで持っていきました。numbaのjitコンパイルを通すためにコードをまただいぶ書き換えてあります。
148
+ ```python
149
+ import timeit
150
+ import math
151
+
152
+ import numba
153
+
154
+ #旧:エラトステネスの篩
155
+ @numba.jit(nopython=True)
156
+ def eratosthenes_list(n):
157
+ primes = [True] * n
158
+ result = [2]
159
+ for prime in range(3, n, 2):
160
+ if primes[prime]:
161
+ result.append(prime)
162
+ for i in range(prime * prime, n, prime * 2):
163
+ primes[i] = False
164
+ return result
165
+
166
+ #新:区間篩
167
+ @numba.jit(nopython=True)
168
+ def primesList(n):
169
+ n -= 1
170
+ SIEVE_MAX = int(math.sqrt(n)) + 1
171
+
172
+ sieve = [True] * (SIEVE_MAX)
173
+ sieve[0] = sieve[1] = False
174
+ for i in range(2, SIEVE_MAX):
175
+ for j in range(i * 2, SIEVE_MAX, i):
176
+ sieve[j] = False
177
+
178
+ primes = []
179
+ for i, x in enumerate(sieve):
180
+ if x:
181
+ primes.append(i)
182
+
183
+ for i in range(1, (n // (SIEVE_MAX))+1):
184
+ sieve = [True] * len(sieve)
185
+ start_index = SIEVE_MAX * i
186
+
187
+ for p in primes:
188
+ if (p * p > start_index + SIEVE_MAX):
189
+ break
190
+
191
+ jj = (p - (start_index % p)) % p
192
+ for j in range(jj, SIEVE_MAX, p):
193
+ sieve[j] = False
194
+
195
+ tmp = n - start_index + 1
196
+ if tmp < SIEVE_MAX:
197
+ x = tmp
198
+ else:
199
+ x = SIEVE_MAX
200
+ for j in range(x):
201
+ if sieve[j]:
202
+ primes.append(start_index + j)
203
+ return primes
204
+
205
+ if True:
206
+ for nn in range(10, 10**3):
207
+ a = eratosthenes_list(nn)
208
+ b = primesList(nn)
209
+ if not a == b:
210
+ print(nn)
211
+ print("miss")
212
+ print(len(a), len(b))
213
+ print(a)
214
+ print(b)
215
+ break
216
+ else:
217
+ print("all ok")
218
+
219
+ nn = 10**8
220
+ print(timeit.timeit(lambda: (eratosthenes_list(nn)), number = 1))
221
+ print(timeit.timeit(lambda: (primesList(nn)), number = 1))
222
+ """ =>
223
+ all ok
224
+ 1.2398602159810252
225
+ 1.059988280001562
226
+ """
227
+ ```