prime 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +5 -1
- data/README.md +3 -2
- data/lib/prime.rb +121 -23
- data/prime.gemspec +8 -7
- metadata +14 -28
- data/.travis.yml +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69b6520022d139c1d89c5cbd15bf1faaec30e4ac67714876e7f43af40d3b3a05
|
4
|
+
data.tar.gz: 1f09f7fdb26b2e98cde5ddc7e663140796683a75aae53440a934b5c863cbcadc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95136886cc978693a77a243adbc7f33533918e8f7d178ce6cb1802eeecdee7ba02c9d58bf5bdde0ab512a7966a4e3091008d4f074a14cfb6864a35318654eda2
|
7
|
+
data.tar.gz: 48fd3bdaa95b4d7bd384a7892709e5c54e999fc22f87049a781416863a91547574e7a6970ab7ba07d0c593e5103663a6de75fcd87dae4a72c8ea01b9c9784c33
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -33,8 +33,9 @@ Prime.prime?(7) #=> true
|
|
33
33
|
8.prime? #=> false
|
34
34
|
|
35
35
|
# Factorization in prime numbers
|
36
|
-
Prime.prime_division(
|
37
|
-
Prime.int_from_prime_division([[
|
36
|
+
Prime.prime_division(8959) #=> [[17, 2], [31, 1]]
|
37
|
+
Prime.int_from_prime_division([[17, 2], [31, 1]]) #=> 8959
|
38
|
+
17**2 * 31 #=> 8959
|
38
39
|
```
|
39
40
|
|
40
41
|
## Contributing
|
data/lib/prime.rb
CHANGED
@@ -31,8 +31,14 @@ class Integer
|
|
31
31
|
end
|
32
32
|
|
33
33
|
# Returns true if +self+ is a prime number, else returns false.
|
34
|
+
# Not recommended for very big integers (> 10**23).
|
34
35
|
def prime?
|
35
36
|
return self >= 2 if self <= 3
|
37
|
+
|
38
|
+
if (bases = miller_rabin_bases)
|
39
|
+
return miller_rabin_test(bases)
|
40
|
+
end
|
41
|
+
|
36
42
|
return true if self == 5
|
37
43
|
return false unless 30.gcd(self) == 1
|
38
44
|
(7..Integer.sqrt(self)).step(30) do |p|
|
@@ -43,6 +49,73 @@ class Integer
|
|
43
49
|
true
|
44
50
|
end
|
45
51
|
|
52
|
+
MILLER_RABIN_BASES = [
|
53
|
+
[2],
|
54
|
+
[2,3],
|
55
|
+
[31,73],
|
56
|
+
[2,3,5],
|
57
|
+
[2,3,5,7],
|
58
|
+
[2,7,61],
|
59
|
+
[2,13,23,1662803],
|
60
|
+
[2,3,5,7,11],
|
61
|
+
[2,3,5,7,11,13],
|
62
|
+
[2,3,5,7,11,13,17],
|
63
|
+
[2,3,5,7,11,13,17,19,23],
|
64
|
+
[2,3,5,7,11,13,17,19,23,29,31,37],
|
65
|
+
[2,3,5,7,11,13,17,19,23,29,31,37,41],
|
66
|
+
].map!(&:freeze).freeze
|
67
|
+
private_constant :MILLER_RABIN_BASES
|
68
|
+
|
69
|
+
private def miller_rabin_bases
|
70
|
+
# Miller-Rabin's complexity is O(k log^3n).
|
71
|
+
# So we can reduce the complexity by reducing the number of bases tested.
|
72
|
+
# Using values from https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
|
73
|
+
i = case
|
74
|
+
when self < 0xffff then
|
75
|
+
# For small integers, Miller Rabin can be slower
|
76
|
+
# There is no mathematical significance to 0xffff
|
77
|
+
return nil
|
78
|
+
# when self < 2_047 then 0
|
79
|
+
when self < 1_373_653 then 1
|
80
|
+
when self < 9_080_191 then 2
|
81
|
+
when self < 25_326_001 then 3
|
82
|
+
when self < 3_215_031_751 then 4
|
83
|
+
when self < 4_759_123_141 then 5
|
84
|
+
when self < 1_122_004_669_633 then 6
|
85
|
+
when self < 2_152_302_898_747 then 7
|
86
|
+
when self < 3_474_749_660_383 then 8
|
87
|
+
when self < 341_550_071_728_321 then 9
|
88
|
+
when self < 3_825_123_056_546_413_051 then 10
|
89
|
+
when self < 318_665_857_834_031_151_167_461 then 11
|
90
|
+
when self < 3_317_044_064_679_887_385_961_981 then 12
|
91
|
+
else return nil
|
92
|
+
end
|
93
|
+
MILLER_RABIN_BASES[i]
|
94
|
+
end
|
95
|
+
|
96
|
+
private def miller_rabin_test(bases)
|
97
|
+
return false if even?
|
98
|
+
|
99
|
+
r = 0
|
100
|
+
d = self >> 1
|
101
|
+
while d.even?
|
102
|
+
d >>= 1
|
103
|
+
r += 1
|
104
|
+
end
|
105
|
+
|
106
|
+
self_minus_1 = self-1
|
107
|
+
bases.each do |a|
|
108
|
+
x = a.pow(d, self)
|
109
|
+
next if x == 1 || x == self_minus_1 || a == self
|
110
|
+
|
111
|
+
return false if r.times do
|
112
|
+
x = x.pow(2, self)
|
113
|
+
break if x == self_minus_1
|
114
|
+
end
|
115
|
+
end
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
46
119
|
# Iterates the given block over all prime numbers.
|
47
120
|
#
|
48
121
|
# See +Prime+#each for more details.
|
@@ -84,7 +157,7 @@ end
|
|
84
157
|
# There are few implementations of generator.
|
85
158
|
#
|
86
159
|
# [+Prime+::+EratosthenesGenerator+]
|
87
|
-
# Uses
|
160
|
+
# Uses Eratosthenes' sieve.
|
88
161
|
# [+Prime+::+TrialDivisionGenerator+]
|
89
162
|
# Uses the trial division method.
|
90
163
|
# [+Prime+::+Generator23+]
|
@@ -96,7 +169,7 @@ end
|
|
96
169
|
|
97
170
|
class Prime
|
98
171
|
|
99
|
-
VERSION = "0.1.
|
172
|
+
VERSION = "0.1.2"
|
100
173
|
|
101
174
|
include Enumerable
|
102
175
|
include Singleton
|
@@ -141,8 +214,22 @@ class Prime
|
|
141
214
|
generator.each(&block)
|
142
215
|
end
|
143
216
|
|
217
|
+
# Returns true if +obj+ is an Integer and is prime. Also returns
|
218
|
+
# true if +obj+ is a Module that is an ancestor of +Prime+.
|
219
|
+
# Otherwise returns false.
|
220
|
+
def include?(obj)
|
221
|
+
case obj
|
222
|
+
when Integer
|
223
|
+
prime?(obj)
|
224
|
+
when Module
|
225
|
+
Module.instance_method(:include?).bind(Prime).call(obj)
|
226
|
+
else
|
227
|
+
false
|
228
|
+
end
|
229
|
+
end
|
144
230
|
|
145
231
|
# Returns true if +value+ is a prime number, else returns false.
|
232
|
+
# Integer#prime? is much more performant.
|
146
233
|
#
|
147
234
|
# == Parameters
|
148
235
|
#
|
@@ -161,17 +248,23 @@ class Prime
|
|
161
248
|
|
162
249
|
# Re-composes a prime factorization and returns the product.
|
163
250
|
#
|
251
|
+
# For the decomposition:
|
252
|
+
#
|
253
|
+
# [[p_1, e_1], [p_2, e_2], ..., [p_n, e_n]],
|
254
|
+
#
|
255
|
+
# it returns:
|
256
|
+
#
|
257
|
+
# p_1**e_1 * p_2**e_2 * ... * p_n**e_n.
|
258
|
+
#
|
164
259
|
# == Parameters
|
165
|
-
# +pd+:: Array of pairs of integers.
|
166
|
-
# pair consists of a prime number -- a prime factor --
|
167
|
-
# and a natural number --
|
260
|
+
# +pd+:: Array of pairs of integers.
|
261
|
+
# Each pair consists of a prime number -- a prime factor --
|
262
|
+
# and a natural number -- its exponent (multiplicity).
|
168
263
|
#
|
169
264
|
# == Example
|
170
|
-
#
|
171
|
-
#
|
172
|
-
# p_1**e_1 * p_2**e_2 * .... * p_n**e_n.
|
265
|
+
# Prime.int_from_prime_division([[3, 2], [5, 1]]) #=> 45
|
266
|
+
# 3**2 * 5 #=> 45
|
173
267
|
#
|
174
|
-
# Prime.int_from_prime_division([[2,2], [3,1]]) #=> 12
|
175
268
|
def int_from_prime_division(pd)
|
176
269
|
pd.inject(1){|value, (prime, index)|
|
177
270
|
value * prime**index
|
@@ -180,27 +273,32 @@ class Prime
|
|
180
273
|
|
181
274
|
# Returns the factorization of +value+.
|
182
275
|
#
|
276
|
+
# For an arbitrary integer:
|
277
|
+
#
|
278
|
+
# p_1**e_1 * p_2**e_2 * ... * p_n**e_n,
|
279
|
+
#
|
280
|
+
# prime_division returns an array of pairs of integers:
|
281
|
+
#
|
282
|
+
# [[p_1, e_1], [p_2, e_2], ..., [p_n, e_n]].
|
283
|
+
#
|
284
|
+
# Each pair consists of a prime number -- a prime factor --
|
285
|
+
# and a natural number -- its exponent (multiplicity).
|
286
|
+
#
|
183
287
|
# == Parameters
|
184
288
|
# +value+:: An arbitrary integer.
|
185
289
|
# +generator+:: Optional. A pseudo-prime generator.
|
186
290
|
# +generator+.succ must return the next
|
187
|
-
# pseudo-prime number in
|
188
|
-
#
|
189
|
-
# but may also generate non
|
291
|
+
# pseudo-prime number in ascending order.
|
292
|
+
# It must generate all prime numbers,
|
293
|
+
# but may also generate non-prime numbers, too.
|
190
294
|
#
|
191
295
|
# === Exceptions
|
192
296
|
# +ZeroDivisionError+:: when +value+ is zero.
|
193
297
|
#
|
194
298
|
# == 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
299
|
#
|
203
|
-
# Prime.prime_division(
|
300
|
+
# Prime.prime_division(45) #=> [[3, 2], [5, 1]]
|
301
|
+
# 3**2 * 5 #=> 45
|
204
302
|
#
|
205
303
|
def prime_division(value, generator = Prime::Generator23.new)
|
206
304
|
raise ZeroDivisionError if value == 0
|
@@ -283,9 +381,9 @@ class Prime
|
|
283
381
|
end
|
284
382
|
|
285
383
|
# see +Enumerator+#with_index.
|
286
|
-
def with_index(offset = 0)
|
287
|
-
return enum_for(:with_index, offset) { Float::INFINITY } unless
|
288
|
-
return each_with_index(&
|
384
|
+
def with_index(offset = 0, &block)
|
385
|
+
return enum_for(:with_index, offset) { Float::INFINITY } unless block
|
386
|
+
return each_with_index(&block) if offset == 0
|
289
387
|
|
290
388
|
each do |prime|
|
291
389
|
yield prime, offset
|
data/prime.gemspec
CHANGED
@@ -8,20 +8,21 @@ end
|
|
8
8
|
Gem::Specification.new do |spec|
|
9
9
|
spec.name = "prime"
|
10
10
|
spec.version = Prime::VERSION
|
11
|
-
spec.authors = ["
|
12
|
-
spec.email = ["
|
11
|
+
spec.authors = ["Marc-Andre Lafortune"]
|
12
|
+
spec.email = ["ruby-core@marc-andre.ca"]
|
13
13
|
|
14
14
|
spec.summary = %q{Prime numbers and factorization library.}
|
15
15
|
spec.description = %q{Prime numbers and factorization library.}
|
16
16
|
spec.homepage = "https://github.com/ruby/prime"
|
17
|
-
spec.
|
17
|
+
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
18
18
|
|
19
|
-
spec.files = [".gitignore", "
|
19
|
+
spec.files = [".gitignore", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/prime.rb", "prime.gemspec"]
|
20
20
|
spec.bindir = "exe"
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.
|
25
|
-
|
26
|
-
spec.
|
24
|
+
spec.required_ruby_version = ">= 2.5.0"
|
25
|
+
|
26
|
+
spec.add_dependency "singleton"
|
27
|
+
spec.add_dependency "forwardable"
|
27
28
|
end
|
metadata
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
autorequire:
|
7
|
+
- Marc-Andre Lafortune
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: singleton
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
|
-
type: :
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
@@ -25,27 +25,13 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: forwardable
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
|
-
type: :
|
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
|
34
|
+
type: :runtime
|
49
35
|
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
@@ -54,13 +40,12 @@ dependencies:
|
|
54
40
|
version: '0'
|
55
41
|
description: Prime numbers and factorization library.
|
56
42
|
email:
|
57
|
-
-
|
43
|
+
- ruby-core@marc-andre.ca
|
58
44
|
executables: []
|
59
45
|
extensions: []
|
60
46
|
extra_rdoc_files: []
|
61
47
|
files:
|
62
48
|
- ".gitignore"
|
63
|
-
- ".travis.yml"
|
64
49
|
- Gemfile
|
65
50
|
- LICENSE.txt
|
66
51
|
- README.md
|
@@ -71,9 +56,10 @@ files:
|
|
71
56
|
- prime.gemspec
|
72
57
|
homepage: https://github.com/ruby/prime
|
73
58
|
licenses:
|
59
|
+
- Ruby
|
74
60
|
- BSD-2-Clause
|
75
61
|
metadata: {}
|
76
|
-
post_install_message:
|
62
|
+
post_install_message:
|
77
63
|
rdoc_options: []
|
78
64
|
require_paths:
|
79
65
|
- lib
|
@@ -81,15 +67,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
67
|
requirements:
|
82
68
|
- - ">="
|
83
69
|
- !ruby/object:Gem::Version
|
84
|
-
version:
|
70
|
+
version: 2.5.0
|
85
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
72
|
requirements:
|
87
73
|
- - ">="
|
88
74
|
- !ruby/object:Gem::Version
|
89
75
|
version: '0'
|
90
76
|
requirements: []
|
91
|
-
rubygems_version: 3.
|
92
|
-
signing_key:
|
77
|
+
rubygems_version: 3.1.4
|
78
|
+
signing_key:
|
93
79
|
specification_version: 4
|
94
80
|
summary: Prime numbers and factorization library.
|
95
81
|
test_files: []
|