prime 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -1
  3. data/README.md +3 -2
  4. data/lib/prime.rb +121 -23
  5. data/prime.gemspec +8 -7
  6. metadata +14 -28
  7. data/.travis.yml +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69c11faf9d0618a701ec125b9e6f4166770ade54b7868896535b75ef549c7beb
4
- data.tar.gz: f86764a32b94750b27444875ec6282cdfb2398de1bf55f643eb26c225b5a532d
3
+ metadata.gz: 69b6520022d139c1d89c5cbd15bf1faaec30e4ac67714876e7f43af40d3b3a05
4
+ data.tar.gz: 1f09f7fdb26b2e98cde5ddc7e663140796683a75aae53440a934b5c863cbcadc
5
5
  SHA512:
6
- metadata.gz: f5aa14e41c4c80c3c95828b2d7f019f220e1ba2ad461ab638ab32af7e98296e233ef390b90c13847e78b639e24fc47df8052e8f7c10c72181de743b3f78342e5
7
- data.tar.gz: 74d959b3a3d2ddb296dbf116cc8bed6314ca43fcedd98a7667ed520d3efa1340077b567a197ce0e164e21b2c7be43be28fb718ed80660d903b86d795a75c0bfb
6
+ metadata.gz: 95136886cc978693a77a243adbc7f33533918e8f7d178ce6cb1802eeecdee7ba02c9d58bf5bdde0ab512a7966a4e3091008d4f074a14cfb6864a35318654eda2
7
+ data.tar.gz: 48fd3bdaa95b4d7bd384a7892709e5c54e999fc22f87049a781416863a91547574e7a6970ab7ba07d0c593e5103663a6de75fcd87dae4a72c8ea01b9c9784c33
data/Gemfile CHANGED
@@ -2,5 +2,9 @@ source "https://rubygems.org"
2
2
 
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
- # Specify your gem's dependencies in prime.gemspec
6
5
  gemspec
6
+
7
+ group :development do
8
+ gem "rake"
9
+ gem "test-unit"
10
+ end
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(779) #=> [[19, 1], [41, 1]]
37
- Prime.int_from_prime_division([[19, 1], [41, 1]]) #=> 779
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
@@ -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 eratosthenes' sieve.
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.0"
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. The each internal
166
- # pair consists of a prime number -- a prime factor --
167
- # and a natural number -- an exponent.
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
- # 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.
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 the ascending
188
- # order. It must generate all prime numbers,
189
- # but may also generate non prime numbers too.
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(12) #=> [[2,2], [3,1]]
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 block_given?
288
- return each_with_index(&proc) if offset == 0
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
@@ -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 = ["Yuki Sonoda"]
12
- spec.email = ["yugui@yugui.jp"]
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.license = "BSD-2-Clause"
17
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
18
18
 
19
- spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/prime.rb", "prime.gemspec"]
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.add_development_dependency "bundler"
25
- spec.add_development_dependency "rake"
26
- spec.add_development_dependency "test-unit"
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.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
- - Yuki Sonoda
8
- autorequire:
7
+ - Marc-Andre Lafortune
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-01 00:00:00.000000000 Z
11
+ date: 2020-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
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: :development
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: rake
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: :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
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
- - yugui@yugui.jp
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: '0'
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.2.0.pre1
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: []
@@ -1,6 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.5.1
5
- - ruby-head
6
- before_install: gem install bundler -v 1.16.2