prime 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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