1
2
3
4
5 require 'benchmark'
6
7 class Integer
8 def prime?
9 n = self.abs()
10 return true if n == 2
11 return false if n == 1 || n & 1 == 0
12 d = n-1
13 d >>= 1 while d & 1 == 0
14 20.times do
15 a = rand(n-2) + 1
16 t = d
17 y = ModMath.pow(a,t,n)
18 while t != n-1 && y != 1 && y != n-1
19 y = (y * y) % n
20 t <<= 1
21 end
22 return false if y != n-1 && t & 1 == 0
23 end
24 return true
25 end
26 end
27
28 module ModMath
29 def ModMath.pow(base, power, mod)
30 result = 1
31 while power > 0
32 result = (result * base) % mod if power & 1 == 1
33 base = (base * base) % mod
34 power >>= 1;
35 end
36 result
37 end
38 end
39
40
41
42 class Integer
43
44 def primes
45
46 sieve = []
47 3.step(self, 2) { |i| sieve[i] = i }
48 sieve[1] = nil
49 sieve[2] = 2
50
51 3.step(Math.sqrt(self).floor, 2) do |i|
52 next unless sieve[i]
53 (i*i).step(self, i) do |j|
54 sieve[j] = nil
55 end
56 end
57
58 sieve.compact!
59
60 end
61
62
63 def primes2
64
65 primes = [nil, nil].concat((2..self).to_a)
66
67 (2 .. Math.sqrt(self)).each do |i|
68 next unless primes[i]
69 (i*i).step(self, i) do |j|
70 primes[j] = nil
71 end
72 end
73
74 primes.compact!
75
76 end
77
78 end
79
80
81
82 class Integer
83
84 @primes_cache ||= 100.primes
85
86 class << self; attr_accessor :primes_cache; end
87
88 @nthprime_limit ||= 5_000_000
89 class << self; attr_reader :nthprime_limit; end
90
91
92
93 def sieve_size
94 num = self.to_i.abs
95 logn = Math.log(num)
96 if num < 15985
97 ( num * (logn + Math.log(logn) - 1 + 1.8 * Math.log(logn) / logn) ).floor
98 else
99 ( num * (logn + Math.log(logn) - 0.9427) ).floor
100 end
101 end
102
103
104 def nthprime
105
106 num = self.to_i.abs
107
108
109 raise "#{num}: number too big for Integer#nthprime" if num > Integer.nthprime_limit
110
111 primes_cache_size = Integer.primes_cache.size
112
113 if num > primes_cache_size
114
115
116 if num >= 50_000 && num < 100_000 && (num - primes_cache_size) < 5000 then return num.nthprime_add end
117 if num >= 100_000 && num < 200_000 && (num - primes_cache_size) < 15000 then return num.nthprime_add end
118 if num >= 200_000 && (num - primes_cache_size) < 35000 then return num.nthprime_add end
119
120 logn = Math.log(num)
121
122 if num < 15985
123 limit = ( num * (logn + Math.log(logn) - 1 + 1.8 * Math.log(logn) / logn) ).floor
124 Integer.primes_cache = limit.primes
125 else
126 limit = ( num * (logn + Math.log(logn) - 0.9427) ).floor
127 Integer.primes_cache = limit.primes
128 end
129
130
131
132
133
134
135
136
137
138
139 else
140 return Integer.primes_cache.at(num-1)
141 end
142
143
144 if num <= Integer.primes_cache.size
145 return Integer.primes_cache.at(num-1)
146 end
147
148 if Integer.primes_cache.size > 2_500_000
149 num.nthprime_add_mr
150 else
151 num.nthprime_add
152 end
153
154 end
155
156
157 def nthprime_add
158
159 num = self.to_i.abs
160
161 if num <= Integer.primes_cache.size
162 return Integer.primes_cache.at(num-1)
163 end
164
165 last_prime = Integer.primes_cache.last
166 last_prime_divmod = last_prime.divmod(6)
167
168 if last_prime_divmod.last == 1
169 i = last_prime_divmod.first
170 Integer.primes_cache.pop
171 else
172 i = last_prime_divmod.first + 1
173 end
174
175
176 while Integer.primes_cache.size < num
177
178 n1 = 6*i+1
179 n2 = n1+4
180 i += 1
181
182 [n1, n2].each do |p|
183
184 next if p % 5 == 0 || p % 7 == 0
185
186 next_num_sqrt = Math.sqrt(p).floor
187
188 Integer.primes_cache.each do |d|
189 if d > next_num_sqrt
190 Integer.primes_cache << p
191
192
193 break
194 elsif p % d == 0
195 break
196 end
197 end
198 end
199
200 end
201
202 return Integer.primes_cache.at(num-1)
203
204 end
205
206
207 def nthprime_add_mr
208
209 num = self.to_i.abs
210
211 if num <= Integer.primes_cache.size
212 return Integer.primes_cache.at(num-1)
213 end
214
215 last_prime = Integer.primes_cache.last
216 last_prime_divmod = last_prime.divmod(6)
217
218 if last_prime_divmod.last == 1
219 i = last_prime_divmod.first
220 Integer.primes_cache.pop
221 else
222 i = last_prime_divmod.first + 1
223 end
224
225
226 while Integer.primes_cache.size < num
227
228 search_next_prime = true
229
230 while search_next_prime
231
232 n1 = 6*i+1
233 n2 = n1+4
234 i += 1
235
236 [n1, n2].each do |p|
237
238 next if p % 5 == 0 || p % 7 == 0
239
240 if p.prime?
241 Integer.primes_cache << p
242 search_next_prime = false
243
244
245 end
246 end
247 end
248
249 end
250
251 return Integer.primes_cache.at(num-1)
252
253 end
254
255
256
257
258
259 def next_primes_in_cache
260
261 search_next_primes = self.to_i.abs
262
263 last_prime = Integer.primes_cache.last
264 last_prime_divmod = last_prime.divmod(6)
265
266 if last_prime_divmod.last == 1
267 i = last_prime_divmod.first
268 Integer.primes_cache.pop
269 else
270 i = last_prime_divmod.first + 1
271 end
272
273 while search_next_primes > 0
274
275 n1 = 6*i+1
276 n2 = n1+4
277 i += 1
278
279 [n1, n2].each do |p|
280
281 next if p % 5 == 0 || p % 7 == 0
282 next_num_sqrt = Math.sqrt(p).floor
283
284 Integer.primes_cache.each do |d|
285 if d > next_num_sqrt
286 Integer.primes_cache << p
287 search_next_primes -= 1
288
289
290 break
291 elsif p % d == 0
292 break
293 end
294 end
295 end
296 end
297
298 Integer.primes_cache.last(self.to_i.abs)
299
300 end
301
302
303 def next_mr_prime
304
305 last_num = self.to_i.abs
306 last_num_divmod = last_num.divmod(6)
307
308 if last_num_divmod.last == 1
309 i = last_num_divmod.first
310 else
311 i = last_num_divmod.first + 1
312 end
313
314 next_prime = nil
315 search_next_prime = true
316
317 while search_next_prime
318
319 n1 = 6*i+1
320 n2 = n1+4
321 i += 1
322
323 [n1, n2].each do |p|
324
325 next if p % 5 == 0 || p % 7 == 0
326
327 if p > last_num && p.prime?
328 next_prime = p
329 search_next_prime = false
330 break
331 end
332 end
333 end
334
335 next_prime
336
337 end
338
339
340
341 def next_mr_primes(n)
342
343 last_num = self.to_i.abs
344 last_num_divmod = last_num.divmod(6)
345
346 if last_num_divmod.last == 1
347 i = last_num_divmod.first
348 else
349 i = last_num_divmod.first + 1
350 end
351
352 next_primes = []
353 search_next_primes = n.to_i.abs
354
355 while search_next_primes > 0
356
357 n1 = 6*i+1
358 n2 = n1+4
359 i += 1
360
361 [n1, n2].each do |p|
362
363 next if p % 5 == 0 || p % 7 == 0
364
365 if p > last_num && p.prime?
366 next_primes << p
367 search_next_primes -= 1
368 end
369 end
370 end
371
372 next_primes
373
374 end
375
376 end
377
378
379
380 num1 = 10_000
381 num1 = 1_000
382 num1 = 5_000
383
384 num2 = 210_349
385 num2 = 100_125
386 num2 = 55_000
387
388 ret1 = nil
389 ret2 = nil
390 ret3 = nil
391 ret4 = nil
392
393
394 Benchmark.bm(16) do |t|
395
396 t.report("first #{num1} primes: ") do
397 ret1 = num1.nthprime_add
398 end
399
400 Integer.primes_cache.clear
401 Integer.primes_cache.concat(100.primes)
402
403 t.report("first #{num1} primes: ") do
404 ret2 = num1.nthprime_add_mr
405 end
406
407 Integer.primes_cache.clear
408 Integer.primes_cache.concat(100.primes)
409
410 t.report("first #{num1} primes: ") do
411 ret3 = num1.nthprime
412 end
413
414 Integer.primes_cache.clear
415 Integer.primes_cache.concat(100.primes)
416
417 t.report("first #{num2} primes: ") do
418 ret4 = num2.nthprime
419 end
420
421 end
422
423
424 puts
425 puts "the #{num1}th prime number: #{ret1}"
426 puts "the #{num1}th prime number: #{ret2}"
427 puts "the #{num1}th prime number: #{ret3}"
428 puts "the #{num2}th prime number: #{ret4}"
429 puts
430 puts "the #{num1}th prime: #{Integer.primes_cache.at(num1-1)}"
431 puts "the #{num2}th prime: #{Integer.primes_cache.at(num2-1)}"
432 puts
433 p Integer.primes_cache.first(10)
434 p Integer.primes_cache.last(10)
435 p Integer.primes_cache.size
436 puts
437
438
439 p 15.next_primes_in_cache
440
441 puts 594_213.next_mr_prime
442
443 p 149_137.next_mr_primes(5)
444
445 puts
446 p 1_000.sieve_size
447 p 1_000_000.sieve_size
448 p 2_500_000.sieve_size
449 p 5_000_000.sieve_size
450 p 10_000_000.sieve_size
451 p 100_000_000.sieve_size
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474