prime 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +6 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +46 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/prime.rb +463 -0
- data/prime.gemspec +27 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 69c11faf9d0618a701ec125b9e6f4166770ade54b7868896535b75ef549c7beb
|
4
|
+
data.tar.gz: f86764a32b94750b27444875ec6282cdfb2398de1bf55f643eb26c225b5a532d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f5aa14e41c4c80c3c95828b2d7f019f220e1ba2ad461ab638ab32af7e98296e233ef390b90c13847e78b639e24fc47df8052e8f7c10c72181de743b3f78342e5
|
7
|
+
data.tar.gz: 74d959b3a3d2ddb296dbf116cc8bed6314ca43fcedd98a7667ed520d3efa1340077b567a197ce0e164e21b2c7be43be28fb718ed80660d903b86d795a75c0bfb
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions
|
5
|
+
are met:
|
6
|
+
1. Redistributions of source code must retain the above copyright
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
10
|
+
documentation and/or other materials provided with the distribution.
|
11
|
+
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
13
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
14
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
15
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
16
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
17
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
18
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
19
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
20
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
21
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
22
|
+
SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Prime
|
2
|
+
|
3
|
+
Prime numbers and factorization library.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'prime'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install prime
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'prime'
|
25
|
+
|
26
|
+
# Prime is the set of all prime numbers, and it is Enumerable.
|
27
|
+
Prime.take(4) #=> [2, 3, 5, 7]
|
28
|
+
Prime.first(4) #=> [2, 3, 5, 7]
|
29
|
+
Prime.each(7).to_a #=> [2, 3, 5, 7]
|
30
|
+
|
31
|
+
# Determining whether an arbitrary integer is a prime number
|
32
|
+
Prime.prime?(7) #=> true
|
33
|
+
8.prime? #=> false
|
34
|
+
|
35
|
+
# Factorization in prime numbers
|
36
|
+
Prime.prime_division(779) #=> [[19, 1], [41, 1]]
|
37
|
+
Prime.int_from_prime_division([[19, 1], [41, 1]]) #=> 779
|
38
|
+
```
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/prime.
|
43
|
+
|
44
|
+
## License
|
45
|
+
|
46
|
+
The gem is available as open source under the terms of the [BSD-2-Clause](LICENSE.txt).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "prime"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/prime.rb
ADDED
@@ -0,0 +1,463 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
#
|
3
|
+
# = prime.rb
|
4
|
+
#
|
5
|
+
# Prime numbers and factorization library.
|
6
|
+
#
|
7
|
+
# Copyright::
|
8
|
+
# Copyright (c) 1998-2008 Keiju ISHITSUKA(SHL Japan Inc.)
|
9
|
+
# Copyright (c) 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp>
|
10
|
+
#
|
11
|
+
# Documentation::
|
12
|
+
# Yuki Sonoda
|
13
|
+
#
|
14
|
+
|
15
|
+
require "singleton"
|
16
|
+
require "forwardable"
|
17
|
+
|
18
|
+
class Integer
|
19
|
+
# Re-composes a prime factorization and returns the product.
|
20
|
+
#
|
21
|
+
# See Prime#int_from_prime_division for more details.
|
22
|
+
def Integer.from_prime_division(pd)
|
23
|
+
Prime.int_from_prime_division(pd)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the factorization of +self+.
|
27
|
+
#
|
28
|
+
# See Prime#prime_division for more details.
|
29
|
+
def prime_division(generator = Prime::Generator23.new)
|
30
|
+
Prime.prime_division(self, generator)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns true if +self+ is a prime number, else returns false.
|
34
|
+
def prime?
|
35
|
+
return self >= 2 if self <= 3
|
36
|
+
return true if self == 5
|
37
|
+
return false unless 30.gcd(self) == 1
|
38
|
+
(7..Integer.sqrt(self)).step(30) do |p|
|
39
|
+
return false if
|
40
|
+
self%(p) == 0 || self%(p+4) == 0 || self%(p+6) == 0 || self%(p+10) == 0 ||
|
41
|
+
self%(p+12) == 0 || self%(p+16) == 0 || self%(p+22) == 0 || self%(p+24) == 0
|
42
|
+
end
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
# Iterates the given block over all prime numbers.
|
47
|
+
#
|
48
|
+
# See +Prime+#each for more details.
|
49
|
+
def Integer.each_prime(ubound, &block) # :yields: prime
|
50
|
+
Prime.each(ubound, &block)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# The set of all prime numbers.
|
56
|
+
#
|
57
|
+
# == Example
|
58
|
+
#
|
59
|
+
# Prime.each(100) do |prime|
|
60
|
+
# p prime #=> 2, 3, 5, 7, 11, ...., 97
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# Prime is Enumerable:
|
64
|
+
#
|
65
|
+
# Prime.first 5 # => [2, 3, 5, 7, 11]
|
66
|
+
#
|
67
|
+
# == Retrieving the instance
|
68
|
+
#
|
69
|
+
# For convenience, each instance method of +Prime+.instance can be accessed
|
70
|
+
# as a class method of +Prime+.
|
71
|
+
#
|
72
|
+
# e.g.
|
73
|
+
# Prime.instance.prime?(2) #=> true
|
74
|
+
# Prime.prime?(2) #=> true
|
75
|
+
#
|
76
|
+
# == Generators
|
77
|
+
#
|
78
|
+
# A "generator" provides an implementation of enumerating pseudo-prime
|
79
|
+
# numbers and it remembers the position of enumeration and upper bound.
|
80
|
+
# Furthermore, it is an external iterator of prime enumeration which is
|
81
|
+
# compatible with an Enumerator.
|
82
|
+
#
|
83
|
+
# +Prime+::+PseudoPrimeGenerator+ is the base class for generators.
|
84
|
+
# There are few implementations of generator.
|
85
|
+
#
|
86
|
+
# [+Prime+::+EratosthenesGenerator+]
|
87
|
+
# Uses eratosthenes' sieve.
|
88
|
+
# [+Prime+::+TrialDivisionGenerator+]
|
89
|
+
# Uses the trial division method.
|
90
|
+
# [+Prime+::+Generator23+]
|
91
|
+
# Generates all positive integers which are not divisible by either 2 or 3.
|
92
|
+
# This sequence is very bad as a pseudo-prime sequence. But this
|
93
|
+
# is faster and uses much less memory than the other generators. So,
|
94
|
+
# it is suitable for factorizing an integer which is not large but
|
95
|
+
# has many prime factors. e.g. for Prime#prime? .
|
96
|
+
|
97
|
+
class Prime
|
98
|
+
|
99
|
+
VERSION = "0.1.0"
|
100
|
+
|
101
|
+
include Enumerable
|
102
|
+
include Singleton
|
103
|
+
|
104
|
+
class << self
|
105
|
+
extend Forwardable
|
106
|
+
include Enumerable
|
107
|
+
|
108
|
+
def method_added(method) # :nodoc:
|
109
|
+
(class<< self;self;end).def_delegator :instance, method
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Iterates the given block over all prime numbers.
|
114
|
+
#
|
115
|
+
# == Parameters
|
116
|
+
#
|
117
|
+
# +ubound+::
|
118
|
+
# Optional. An arbitrary positive number.
|
119
|
+
# The upper bound of enumeration. The method enumerates
|
120
|
+
# prime numbers infinitely if +ubound+ is nil.
|
121
|
+
# +generator+::
|
122
|
+
# Optional. An implementation of pseudo-prime generator.
|
123
|
+
#
|
124
|
+
# == Return value
|
125
|
+
#
|
126
|
+
# An evaluated value of the given block at the last time.
|
127
|
+
# Or an enumerator which is compatible to an +Enumerator+
|
128
|
+
# if no block given.
|
129
|
+
#
|
130
|
+
# == Description
|
131
|
+
#
|
132
|
+
# Calls +block+ once for each prime number, passing the prime as
|
133
|
+
# a parameter.
|
134
|
+
#
|
135
|
+
# +ubound+::
|
136
|
+
# Upper bound of prime numbers. The iterator stops after it
|
137
|
+
# yields all prime numbers p <= +ubound+.
|
138
|
+
#
|
139
|
+
def each(ubound = nil, generator = EratosthenesGenerator.new, &block)
|
140
|
+
generator.upper_bound = ubound
|
141
|
+
generator.each(&block)
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
# Returns true if +value+ is a prime number, else returns false.
|
146
|
+
#
|
147
|
+
# == Parameters
|
148
|
+
#
|
149
|
+
# +value+:: an arbitrary integer to be checked.
|
150
|
+
# +generator+:: optional. A pseudo-prime generator.
|
151
|
+
def prime?(value, generator = Prime::Generator23.new)
|
152
|
+
raise ArgumentError, "Expected a prime generator, got #{generator}" unless generator.respond_to? :each
|
153
|
+
raise ArgumentError, "Expected an integer, got #{value}" unless value.respond_to?(:integer?) && value.integer?
|
154
|
+
return false if value < 2
|
155
|
+
generator.each do |num|
|
156
|
+
q,r = value.divmod num
|
157
|
+
return true if q < num
|
158
|
+
return false if r == 0
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Re-composes a prime factorization and returns the product.
|
163
|
+
#
|
164
|
+
# == Parameters
|
165
|
+
# +pd+:: Array of pairs of integers. The each internal
|
166
|
+
# pair consists of a prime number -- a prime factor --
|
167
|
+
# and a natural number -- an exponent.
|
168
|
+
#
|
169
|
+
# == Example
|
170
|
+
# For <tt>[[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]]</tt>, it returns:
|
171
|
+
#
|
172
|
+
# p_1**e_1 * p_2**e_2 * .... * p_n**e_n.
|
173
|
+
#
|
174
|
+
# Prime.int_from_prime_division([[2,2], [3,1]]) #=> 12
|
175
|
+
def int_from_prime_division(pd)
|
176
|
+
pd.inject(1){|value, (prime, index)|
|
177
|
+
value * prime**index
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
181
|
+
# Returns the factorization of +value+.
|
182
|
+
#
|
183
|
+
# == Parameters
|
184
|
+
# +value+:: An arbitrary integer.
|
185
|
+
# +generator+:: Optional. A pseudo-prime generator.
|
186
|
+
# +generator+.succ must return the next
|
187
|
+
# pseudo-prime number in the ascending
|
188
|
+
# order. It must generate all prime numbers,
|
189
|
+
# but may also generate non prime numbers too.
|
190
|
+
#
|
191
|
+
# === Exceptions
|
192
|
+
# +ZeroDivisionError+:: when +value+ is zero.
|
193
|
+
#
|
194
|
+
# == Example
|
195
|
+
# For an arbitrary integer:
|
196
|
+
#
|
197
|
+
# n = p_1**e_1 * p_2**e_2 * .... * p_n**e_n,
|
198
|
+
#
|
199
|
+
# prime_division(n) returns:
|
200
|
+
#
|
201
|
+
# [[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]].
|
202
|
+
#
|
203
|
+
# Prime.prime_division(12) #=> [[2,2], [3,1]]
|
204
|
+
#
|
205
|
+
def prime_division(value, generator = Prime::Generator23.new)
|
206
|
+
raise ZeroDivisionError if value == 0
|
207
|
+
if value < 0
|
208
|
+
value = -value
|
209
|
+
pv = [[-1, 1]]
|
210
|
+
else
|
211
|
+
pv = []
|
212
|
+
end
|
213
|
+
generator.each do |prime|
|
214
|
+
count = 0
|
215
|
+
while (value1, mod = value.divmod(prime)
|
216
|
+
mod) == 0
|
217
|
+
value = value1
|
218
|
+
count += 1
|
219
|
+
end
|
220
|
+
if count != 0
|
221
|
+
pv.push [prime, count]
|
222
|
+
end
|
223
|
+
break if value1 <= prime
|
224
|
+
end
|
225
|
+
if value > 1
|
226
|
+
pv.push [value, 1]
|
227
|
+
end
|
228
|
+
pv
|
229
|
+
end
|
230
|
+
|
231
|
+
# An abstract class for enumerating pseudo-prime numbers.
|
232
|
+
#
|
233
|
+
# Concrete subclasses should override succ, next, rewind.
|
234
|
+
class PseudoPrimeGenerator
|
235
|
+
include Enumerable
|
236
|
+
|
237
|
+
def initialize(ubound = nil)
|
238
|
+
@ubound = ubound
|
239
|
+
end
|
240
|
+
|
241
|
+
def upper_bound=(ubound)
|
242
|
+
@ubound = ubound
|
243
|
+
end
|
244
|
+
def upper_bound
|
245
|
+
@ubound
|
246
|
+
end
|
247
|
+
|
248
|
+
# returns the next pseudo-prime number, and move the internal
|
249
|
+
# position forward.
|
250
|
+
#
|
251
|
+
# +PseudoPrimeGenerator+#succ raises +NotImplementedError+.
|
252
|
+
def succ
|
253
|
+
raise NotImplementedError, "need to define `succ'"
|
254
|
+
end
|
255
|
+
|
256
|
+
# alias of +succ+.
|
257
|
+
def next
|
258
|
+
raise NotImplementedError, "need to define `next'"
|
259
|
+
end
|
260
|
+
|
261
|
+
# Rewinds the internal position for enumeration.
|
262
|
+
#
|
263
|
+
# See +Enumerator+#rewind.
|
264
|
+
def rewind
|
265
|
+
raise NotImplementedError, "need to define `rewind'"
|
266
|
+
end
|
267
|
+
|
268
|
+
# Iterates the given block for each prime number.
|
269
|
+
def each
|
270
|
+
return self.dup unless block_given?
|
271
|
+
if @ubound
|
272
|
+
last_value = nil
|
273
|
+
loop do
|
274
|
+
prime = succ
|
275
|
+
break last_value if prime > @ubound
|
276
|
+
last_value = yield prime
|
277
|
+
end
|
278
|
+
else
|
279
|
+
loop do
|
280
|
+
yield succ
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# see +Enumerator+#with_index.
|
286
|
+
def with_index(offset = 0)
|
287
|
+
return enum_for(:with_index, offset) { Float::INFINITY } unless block_given?
|
288
|
+
return each_with_index(&proc) if offset == 0
|
289
|
+
|
290
|
+
each do |prime|
|
291
|
+
yield prime, offset
|
292
|
+
offset += 1
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# see +Enumerator+#with_object.
|
297
|
+
def with_object(obj)
|
298
|
+
return enum_for(:with_object, obj) { Float::INFINITY } unless block_given?
|
299
|
+
each do |prime|
|
300
|
+
yield prime, obj
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def size
|
305
|
+
Float::INFINITY
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
# An implementation of +PseudoPrimeGenerator+.
|
310
|
+
#
|
311
|
+
# Uses +EratosthenesSieve+.
|
312
|
+
class EratosthenesGenerator < PseudoPrimeGenerator
|
313
|
+
def initialize
|
314
|
+
@last_prime_index = -1
|
315
|
+
super
|
316
|
+
end
|
317
|
+
|
318
|
+
def succ
|
319
|
+
@last_prime_index += 1
|
320
|
+
EratosthenesSieve.instance.get_nth_prime(@last_prime_index)
|
321
|
+
end
|
322
|
+
def rewind
|
323
|
+
initialize
|
324
|
+
end
|
325
|
+
alias next succ
|
326
|
+
end
|
327
|
+
|
328
|
+
# An implementation of +PseudoPrimeGenerator+ which uses
|
329
|
+
# a prime table generated by trial division.
|
330
|
+
class TrialDivisionGenerator < PseudoPrimeGenerator
|
331
|
+
def initialize
|
332
|
+
@index = -1
|
333
|
+
super
|
334
|
+
end
|
335
|
+
|
336
|
+
def succ
|
337
|
+
TrialDivision.instance[@index += 1]
|
338
|
+
end
|
339
|
+
def rewind
|
340
|
+
initialize
|
341
|
+
end
|
342
|
+
alias next succ
|
343
|
+
end
|
344
|
+
|
345
|
+
# Generates all integers which are greater than 2 and
|
346
|
+
# are not divisible by either 2 or 3.
|
347
|
+
#
|
348
|
+
# This is a pseudo-prime generator, suitable on
|
349
|
+
# checking primality of an integer by brute force
|
350
|
+
# method.
|
351
|
+
class Generator23 < PseudoPrimeGenerator
|
352
|
+
def initialize
|
353
|
+
@prime = 1
|
354
|
+
@step = nil
|
355
|
+
super
|
356
|
+
end
|
357
|
+
|
358
|
+
def succ
|
359
|
+
if (@step)
|
360
|
+
@prime += @step
|
361
|
+
@step = 6 - @step
|
362
|
+
else
|
363
|
+
case @prime
|
364
|
+
when 1; @prime = 2
|
365
|
+
when 2; @prime = 3
|
366
|
+
when 3; @prime = 5; @step = 2
|
367
|
+
end
|
368
|
+
end
|
369
|
+
@prime
|
370
|
+
end
|
371
|
+
alias next succ
|
372
|
+
def rewind
|
373
|
+
initialize
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Internal use. An implementation of prime table by trial division method.
|
378
|
+
class TrialDivision
|
379
|
+
include Singleton
|
380
|
+
|
381
|
+
def initialize # :nodoc:
|
382
|
+
# These are included as class variables to cache them for later uses. If memory
|
383
|
+
# usage is a problem, they can be put in Prime#initialize as instance variables.
|
384
|
+
|
385
|
+
# There must be no primes between @primes[-1] and @next_to_check.
|
386
|
+
@primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
|
387
|
+
# @next_to_check % 6 must be 1.
|
388
|
+
@next_to_check = 103 # @primes[-1] - @primes[-1] % 6 + 7
|
389
|
+
@ulticheck_index = 3 # @primes.index(@primes.reverse.find {|n|
|
390
|
+
# n < Math.sqrt(@@next_to_check) })
|
391
|
+
@ulticheck_next_squared = 121 # @primes[@ulticheck_index + 1] ** 2
|
392
|
+
end
|
393
|
+
|
394
|
+
# Returns the +index+th prime number.
|
395
|
+
#
|
396
|
+
# +index+ is a 0-based index.
|
397
|
+
def [](index)
|
398
|
+
while index >= @primes.length
|
399
|
+
# Only check for prime factors up to the square root of the potential primes,
|
400
|
+
# but without the performance hit of an actual square root calculation.
|
401
|
+
if @next_to_check + 4 > @ulticheck_next_squared
|
402
|
+
@ulticheck_index += 1
|
403
|
+
@ulticheck_next_squared = @primes.at(@ulticheck_index + 1) ** 2
|
404
|
+
end
|
405
|
+
# Only check numbers congruent to one and five, modulo six. All others
|
406
|
+
|
407
|
+
# are divisible by two or three. This also allows us to skip checking against
|
408
|
+
# two and three.
|
409
|
+
@primes.push @next_to_check if @primes[2..@ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
|
410
|
+
@next_to_check += 4
|
411
|
+
@primes.push @next_to_check if @primes[2..@ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
|
412
|
+
@next_to_check += 2
|
413
|
+
end
|
414
|
+
@primes[index]
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
# Internal use. An implementation of Eratosthenes' sieve
|
419
|
+
class EratosthenesSieve
|
420
|
+
include Singleton
|
421
|
+
|
422
|
+
def initialize
|
423
|
+
@primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
|
424
|
+
# @max_checked must be an even number
|
425
|
+
@max_checked = @primes.last + 1
|
426
|
+
end
|
427
|
+
|
428
|
+
def get_nth_prime(n)
|
429
|
+
compute_primes while @primes.size <= n
|
430
|
+
@primes[n]
|
431
|
+
end
|
432
|
+
|
433
|
+
private
|
434
|
+
def compute_primes
|
435
|
+
# max_segment_size must be an even number
|
436
|
+
max_segment_size = 1e6.to_i
|
437
|
+
max_cached_prime = @primes.last
|
438
|
+
# do not double count primes if #compute_primes is interrupted
|
439
|
+
# by Timeout.timeout
|
440
|
+
@max_checked = max_cached_prime + 1 if max_cached_prime > @max_checked
|
441
|
+
|
442
|
+
segment_min = @max_checked
|
443
|
+
segment_max = [segment_min + max_segment_size, max_cached_prime * 2].min
|
444
|
+
root = Integer.sqrt(segment_max)
|
445
|
+
|
446
|
+
segment = ((segment_min + 1) .. segment_max).step(2).to_a
|
447
|
+
|
448
|
+
(1..Float::INFINITY).each do |sieving|
|
449
|
+
prime = @primes[sieving]
|
450
|
+
break if prime > root
|
451
|
+
composite_index = (-(segment_min + 1 + prime) / 2) % prime
|
452
|
+
while composite_index < segment.size do
|
453
|
+
segment[composite_index] = nil
|
454
|
+
composite_index += prime
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
@primes.concat(segment.compact!)
|
459
|
+
|
460
|
+
@max_checked = segment_max
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|
data/prime.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
begin
|
2
|
+
require_relative "lib/prime"
|
3
|
+
rescue LoadError
|
4
|
+
# for Ruby core repository
|
5
|
+
require_relative "prime"
|
6
|
+
end
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = "prime"
|
10
|
+
spec.version = Prime::VERSION
|
11
|
+
spec.authors = ["Yuki Sonoda"]
|
12
|
+
spec.email = ["yugui@yugui.jp"]
|
13
|
+
|
14
|
+
spec.summary = %q{Prime numbers and factorization library.}
|
15
|
+
spec.description = %q{Prime numbers and factorization library.}
|
16
|
+
spec.homepage = "https://github.com/ruby/prime"
|
17
|
+
spec.license = "BSD-2-Clause"
|
18
|
+
|
19
|
+
spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/prime.rb", "prime.gemspec"]
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "test-unit"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prime
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yuki Sonoda
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-04-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Prime numbers and factorization library.
|
56
|
+
email:
|
57
|
+
- yugui@yugui.jp
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".travis.yml"
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- bin/console
|
69
|
+
- bin/setup
|
70
|
+
- lib/prime.rb
|
71
|
+
- prime.gemspec
|
72
|
+
homepage: https://github.com/ruby/prime
|
73
|
+
licenses:
|
74
|
+
- BSD-2-Clause
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubygems_version: 3.2.0.pre1
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Prime numbers and factorization library.
|
95
|
+
test_files: []
|