prime_lib 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +34 -0
- data/LICENCE.txt +22 -0
- data/README.md +36 -0
- data/Rakefile +12 -0
- data/lib/prime_lib/decorator/table.rb +27 -0
- data/lib/prime_lib/decorator/table_product.rb +27 -0
- data/lib/prime_lib/generator/gen_engine.rb +25 -0
- data/lib/prime_lib/generator/sieve_of_eratosthenes.rb +47 -0
- data/lib/prime_lib/generator/sieve_of_eratosthenes_c.rb +74 -0
- data/lib/prime_lib/generator.rb +32 -0
- data/lib/prime_lib/generator_product.rb +28 -0
- data/lib/prime_lib/version.rb +3 -0
- data/lib/prime_lib.rb +19 -0
- data/prime_lib.gemspec +33 -0
- data/spec/decorator/table_spec.rb +22 -0
- data/spec/generator/generator_product_spec.rb +19 -0
- data/spec/generator/generator_spec.rb +57 -0
- data/spec/performance/performance_spec.rb +34 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/original_prime.rb +500 -0
- data/spec/support/regex_prime.rb +5 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 648f92351097b6d1df329f8fc3f87497852c098d
|
4
|
+
data.tar.gz: 1f641e1d56f54b6f919e08a8fa790b7ffc7289fd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 415051537d123ca4b6329cc39dd249caf9775a187141d9397cdd7f32d619d9a63ea4660dab0ccd8b0a42eae8806b1d4cc7ae3f912ebb4fa4b4466013aa910f33
|
7
|
+
data.tar.gz: 964c19325578dc3c77cc9e1d28a21b1958911f4357851e8898b9854f5c9231cf8271058e956d14158281311d7f25e3623e48202e92d12b9d6155f05678b4109f
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
prime_lib (0.1.0)
|
5
|
+
RubyInline (~> 3.12.2)
|
6
|
+
terminal-table
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
RubyInline (3.12.2)
|
12
|
+
ZenTest (~> 4.3)
|
13
|
+
ZenTest (4.9.5)
|
14
|
+
awesome_print (1.2.0)
|
15
|
+
diff-lcs (1.2.5)
|
16
|
+
rake (10.1.1)
|
17
|
+
rspec (2.14.1)
|
18
|
+
rspec-core (~> 2.14.0)
|
19
|
+
rspec-expectations (~> 2.14.0)
|
20
|
+
rspec-mocks (~> 2.14.0)
|
21
|
+
rspec-core (2.14.7)
|
22
|
+
rspec-expectations (2.14.4)
|
23
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
24
|
+
rspec-mocks (2.14.4)
|
25
|
+
terminal-table (1.4.5)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
awesome_print
|
32
|
+
prime_lib!
|
33
|
+
rake
|
34
|
+
rspec
|
data/LICENCE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Adit
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# PrimeLib
|
2
|
+
|
3
|
+
This gem generates a table of the product of N prime numbers.
|
4
|
+
Current version aims to improve its performance on prime numbers retrieval.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Gemfile:
|
9
|
+
|
10
|
+
gem 'prime_lib', '~> 0.1.0'
|
11
|
+
|
12
|
+
## Usage (in terminal)
|
13
|
+
|
14
|
+
> puts PrimeLib::GeneratorProduct.new(10).to_table
|
15
|
+
|
16
|
+
|
17
|
+
## WHAT I'VE DONE
|
18
|
+
|
19
|
+
1. Optimization of prime generation based on Sieve of Eratosthenes algorithm
|
20
|
+
|
21
|
+
Currently my implementation runs slightly faster[1] than sieve generator of Ruby 2.0 Prime lib[2] which has been greatly improved 6 month ago by Yugui[3].
|
22
|
+
|
23
|
+
[1] Ruby Lib takes roughly 1 sec to calculate 200,000 primes, my lib takes 0.6 secs
|
24
|
+
[2] https://github.com/ruby/ruby/blob/trunk/lib/prime.rb
|
25
|
+
[3] https://github.com/ruby/ruby/commit/def83bff91d59fa5fdd1898f903f9000ad1dbe13#diff-cb376f8d9ff85c3dbf97cd71a7463898
|
26
|
+
|
27
|
+
2. To maximize performance gain I decided to run on C code
|
28
|
+
|
29
|
+
|
30
|
+
> PrimeLib::Generator.new(n_samples, engine: PrimeLib::Generator::SieveOfEratosthenesC.new).to_a
|
31
|
+
|
32
|
+
Known issues:
|
33
|
+
- Ruby Inline C compiler throws some[1] warnings I should optimize, meanwhile I've not experienced any trouble (tested till 20_000_000 primes)
|
34
|
+
[1] "left-hand operand of comma expression has no effect",
|
35
|
+
"passing argument 3 of ‘rb_ary_store’ makes integer from pointer without a cast"
|
36
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module PrimeLib
|
2
|
+
|
3
|
+
module Decorator
|
4
|
+
|
5
|
+
module Table
|
6
|
+
|
7
|
+
def lister_keys
|
8
|
+
%W(i Prime)
|
9
|
+
end
|
10
|
+
|
11
|
+
def lister
|
12
|
+
primes = []
|
13
|
+
each_with_index do |i, prime|
|
14
|
+
primes << [i, prime.to_i]
|
15
|
+
end
|
16
|
+
primes
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_table
|
20
|
+
::Terminal::Table.new :headings => lister_keys, :rows => lister
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module PrimeLib
|
2
|
+
|
3
|
+
module Decorator
|
4
|
+
|
5
|
+
module TableProduct
|
6
|
+
|
7
|
+
def lister_keys
|
8
|
+
%W(i Prime Product)
|
9
|
+
end
|
10
|
+
|
11
|
+
def lister
|
12
|
+
primes = []
|
13
|
+
each_with_index do |i, prime, product|
|
14
|
+
primes << [i, prime, product]
|
15
|
+
end
|
16
|
+
primes
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_table
|
20
|
+
::Terminal::Table.new :headings => lister_keys, :rows => lister
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module PrimeLib
|
2
|
+
|
3
|
+
class Generator
|
4
|
+
|
5
|
+
class GenEngine
|
6
|
+
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
attr_accessor :max_els
|
10
|
+
attr_reader :primes
|
11
|
+
|
12
|
+
def initialize(max_els = 10)
|
13
|
+
@max_els = max_els
|
14
|
+
@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]
|
15
|
+
end
|
16
|
+
|
17
|
+
def retrieve_primes
|
18
|
+
raise 'define me'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module PrimeLib
|
2
|
+
|
3
|
+
class Generator
|
4
|
+
|
5
|
+
class SieveOfEratosthenes < GenEngine
|
6
|
+
|
7
|
+
def initialize(max_els = 10)
|
8
|
+
super
|
9
|
+
@max_checked = @primes.last + 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def retrieve_primes
|
13
|
+
next_batch while primes.size <= max_els
|
14
|
+
primes.take(max_els)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def next_batch
|
20
|
+
max_segment_size = 1e6.to_i
|
21
|
+
max_cached_prime = @primes.last
|
22
|
+
|
23
|
+
segment_min = @max_checked
|
24
|
+
segment_max = [segment_min + max_segment_size, max_cached_prime * 2].min
|
25
|
+
|
26
|
+
root = Math.sqrt(segment_max).floor
|
27
|
+
|
28
|
+
sieving_primes = @primes[1..-1].take_while { |prime| prime <= root } # 3 5 7 11 13
|
29
|
+
segment = ((segment_min + 1) .. segment_max).step(2).to_a
|
30
|
+
|
31
|
+
sieving_primes.each do |sieving_prime| # 102 103 104 105 106 ~ 3 5 7 11 13 -> 1 1 1 9 7
|
32
|
+
cursor = (-(segment_min + 1 + sieving_prime) / 2) % sieving_prime
|
33
|
+
while cursor <= segment.size
|
34
|
+
segment[cursor] = nil
|
35
|
+
cursor += sieving_prime
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
@primes = @primes + segment.compact
|
40
|
+
@max_checked = segment_max
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module PrimeLib
|
2
|
+
|
3
|
+
class Generator
|
4
|
+
|
5
|
+
class SieveOfEratosthenesC < GenEngine
|
6
|
+
|
7
|
+
def initialize(max_els = 10)
|
8
|
+
super
|
9
|
+
@max_checked = @primes.last + 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def retrieve_primes
|
13
|
+
max_segment_size = 1e6.to_i
|
14
|
+
|
15
|
+
while primes.size <= max_els do
|
16
|
+
max_cached_prime = @primes.last
|
17
|
+
|
18
|
+
segment_min = @max_checked
|
19
|
+
segment_max = [segment_min + max_segment_size, max_cached_prime * 2].min
|
20
|
+
|
21
|
+
@primes = @primes + next_batch(@primes, segment_min, segment_max).reject{|el| el == false }
|
22
|
+
@max_checked = segment_max
|
23
|
+
end
|
24
|
+
|
25
|
+
primes.take(max_els)
|
26
|
+
end
|
27
|
+
|
28
|
+
inline(:C) do |builder|
|
29
|
+
builder.c <<-EOC
|
30
|
+
static VALUE next_batch(VALUE primes, double segment_min, double segment_max)
|
31
|
+
{
|
32
|
+
int i;
|
33
|
+
int root = sqrt(segment_max);
|
34
|
+
|
35
|
+
VALUE sieving_primes = rb_ary_new();
|
36
|
+
int prime;
|
37
|
+
|
38
|
+
VALUE segment = rb_ary_new();
|
39
|
+
|
40
|
+
int neg_offset, cursor;
|
41
|
+
|
42
|
+
for (i = 1; i < RARRAY_LEN(primes), (prime = NUM2DBL(rb_ary_entry(primes, i))) <= root; i++) {
|
43
|
+
rb_ary_push(sieving_primes, INT2NUM(prime) );
|
44
|
+
}
|
45
|
+
|
46
|
+
for (i = segment_min + 1; i < segment_max; i += 2) {
|
47
|
+
rb_ary_push(segment, INT2NUM(i));
|
48
|
+
}
|
49
|
+
|
50
|
+
for (i = 0; i < RARRAY_LEN(sieving_primes); i++) {
|
51
|
+
int sieving_prime = NUM2DBL(rb_ary_entry(sieving_primes, i));
|
52
|
+
|
53
|
+
neg_offset = (-(segment_min + 1 + sieving_prime) / 2);
|
54
|
+
cursor = neg_offset + (int)((neg_offset < 0 ? -neg_offset : neg_offset) / sieving_prime) * sieving_prime;
|
55
|
+
if (cursor < 0) {
|
56
|
+
cursor += sieving_prime;
|
57
|
+
}
|
58
|
+
|
59
|
+
while(cursor <= RARRAY_LEN(segment)){
|
60
|
+
rb_ary_store(segment, cursor, NULL);
|
61
|
+
cursor += sieving_prime;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
return segment;
|
66
|
+
}
|
67
|
+
EOC
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module PrimeLib
|
2
|
+
|
3
|
+
class Generator
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
include PrimeLib::Decorator::Table
|
7
|
+
|
8
|
+
def_delegators :@engine, :retrieve_primes
|
9
|
+
|
10
|
+
def initialize(max_els = 100, engine: SieveOfEratosthenes.new)
|
11
|
+
@engine = engine
|
12
|
+
engine.max_els = max_els
|
13
|
+
@max_els = max_els
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_added(method)
|
17
|
+
(class<< self;self;end).def_delegator :instance, method
|
18
|
+
end
|
19
|
+
|
20
|
+
def each_with_index
|
21
|
+
retrieve_primes.each_with_index do |prime, iprime|
|
22
|
+
yield(prime, iprime)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_a
|
27
|
+
retrieve_primes
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module PrimeLib
|
2
|
+
|
3
|
+
class GeneratorProduct < Generator
|
4
|
+
include PrimeLib::Decorator::TableProduct
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
super(*args)
|
8
|
+
@product = 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def each_with_index
|
12
|
+
retrieve_primes.each_with_index do |prime, iprime|
|
13
|
+
@product *= prime
|
14
|
+
yield(iprime, prime, @product)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_a
|
19
|
+
ret_primes = []
|
20
|
+
each_with_index do |iprime, prime, product|
|
21
|
+
ret_primes << [iprime, prime, product]
|
22
|
+
end
|
23
|
+
ret_primes
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/prime_lib.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'inline'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'terminal-table'
|
4
|
+
require 'prime_lib/version'
|
5
|
+
|
6
|
+
require 'prime_lib/decorator/table'
|
7
|
+
require 'prime_lib/decorator/table_product'
|
8
|
+
|
9
|
+
require 'prime_lib/generator'
|
10
|
+
require 'prime_lib/generator_product'
|
11
|
+
require 'prime_lib/generator/gen_engine'
|
12
|
+
require 'prime_lib/generator/sieve_of_eratosthenes'
|
13
|
+
require 'prime_lib/generator/sieve_of_eratosthenes_c'
|
14
|
+
|
15
|
+
module PrimeLib
|
16
|
+
|
17
|
+
ROOT_PATH = File.expand_path '../..', __FILE__
|
18
|
+
|
19
|
+
end
|
data/prime_lib.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'prime_lib/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "prime_lib"
|
8
|
+
gem.version = PrimeLib::VERSION
|
9
|
+
gem.authors = ["Adit"]
|
10
|
+
gem.email = ["a.saxena@email.it"]
|
11
|
+
gem.description = "Write a program that calculates and prints out a multiplication table of the first 10 calculated prime numbers."
|
12
|
+
gem.summary = "The program must run from the command line and print to screen 1 table.\nAcross the top and down the left side should be the 10 primes, and the body of the table should contain the product of multiplying these numbers."
|
13
|
+
|
14
|
+
gem.homepage = "https://bitbucket.org/aditsaxena/prime_lib/src"
|
15
|
+
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
|
19
|
+
gem.files = `git ls-files`.split($/)
|
20
|
+
# s.files = Dir["[A-Z]*[^~]"] + Dir["lib/**/*.rb"] + Dir["spec/*"] + [".gitignore"]
|
21
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
22
|
+
|
23
|
+
gem.require_paths = ["lib"]
|
24
|
+
|
25
|
+
gem.add_dependency "RubyInline", "~> 3.12.2"
|
26
|
+
|
27
|
+
gem.add_dependency "terminal-table"
|
28
|
+
|
29
|
+
gem.add_development_dependency "rake"
|
30
|
+
gem.add_development_dependency "rspec"
|
31
|
+
gem.add_development_dependency "awesome_print"
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "PrimeLib" do
|
4
|
+
|
5
|
+
it "Prints a table of first N primes" do
|
6
|
+
primelib = PrimeLib::Generator.new(10)
|
7
|
+
puts primelib.to_table
|
8
|
+
end
|
9
|
+
|
10
|
+
it "Prints a table of first N primes products" do
|
11
|
+
primelib = PrimeLib::GeneratorProduct.new(10)
|
12
|
+
puts primelib.to_table
|
13
|
+
end
|
14
|
+
|
15
|
+
it "Prints a table of first N primes products", focus: true do
|
16
|
+
primelib = PrimeLib::GeneratorProduct.new(10, engine: PrimeLib::Generator::SieveOfEratosthenesC.new)
|
17
|
+
puts primelib.to_table
|
18
|
+
end
|
19
|
+
|
20
|
+
# primes = PrimeLib::Generator.new(n_samples, engine: PrimeLib::Generator::SieveOfEratosthenesC.new).to_a
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PrimeLib::Generator do
|
4
|
+
|
5
|
+
it "provides a multiplication list of the first N primes" do
|
6
|
+
qty = 30
|
7
|
+
qty.should be > 1
|
8
|
+
|
9
|
+
primes_prods = PrimeLib::GeneratorProduct.new(qty).to_a
|
10
|
+
manual_prod = 1
|
11
|
+
|
12
|
+
(qty - 1).times do |i|
|
13
|
+
manual_prod = manual_prod * primes_prods[i][1]
|
14
|
+
expect(manual_prod).to eq primes_prods[i][2]
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PrimeLib::Generator do
|
4
|
+
|
5
|
+
let(:first_primes) {
|
6
|
+
# http://primes.utm.edu/lists/small/1000.txt
|
7
|
+
%W( 2 3 5 7 11 13 17 19 23 29
|
8
|
+
31 37 41 43 47 53 59 61 67 71
|
9
|
+
73 79 83 89 97 101 103 107 109 113
|
10
|
+
127 131 137 139 149 151 157 163 167 173
|
11
|
+
179 181 191 193 197 199 211 223 227 229
|
12
|
+
233 239 241 251 257 263 269 271 277 281
|
13
|
+
283 293 307 311 313 317 331 337 347 349
|
14
|
+
353 359 367 373 379 383 389 397 401 409
|
15
|
+
419 421 431 433 439 443 449 457 461 463
|
16
|
+
467 479 487 491 499 503 509 521 523 541
|
17
|
+
547 557 563 569 571 577 587 593 599 601
|
18
|
+
607 613 617 619 631 641 643 647 653 659
|
19
|
+
661 673 677 683 691 701 709 719 727 733
|
20
|
+
739 743 751 757 761 769 773 787 797 809
|
21
|
+
811 821 823 827 829 839 853 857 859 863
|
22
|
+
877 881 883 887 907 911 919 929 937 941
|
23
|
+
947 953 967 971 977 983 991 997 1009 1013
|
24
|
+
1019 1021 1031 1033 1039 1049 1051 1061 1063 1069
|
25
|
+
1087 1091 1093 1097 1103 1109 1117 1123 1129 1151
|
26
|
+
1153 1163 1171 1181 1187 1193 1201 1213 1217 1223
|
27
|
+
1229 1231 1237 1249 1259 1277 1279 1283 1289 1291
|
28
|
+
1297 1301 1303 1307 1319 1321 1327 1361 1367 1373
|
29
|
+
1381 1399 1409 1423 1427 1429 1433 1439 1447 1451
|
30
|
+
1453 1459 1471 1481 1483 1487 1489 1493 1499 1511
|
31
|
+
1523 1531 1543 1549 1553 1559 1567 1571 1579 1583
|
32
|
+
1597 1601 1607 1609 1613 1619 1621 1627 1637 1657
|
33
|
+
1663 1667 1669 1693 1697 1699 1709 1721 1723 1733 ).map{ |el| el.to_i }
|
34
|
+
}
|
35
|
+
|
36
|
+
it "fetches N primes, test with a precalculated list" do
|
37
|
+
n_samples = 100
|
38
|
+
primes = PrimeLib::Generator.new(n_samples).to_a
|
39
|
+
expect(primes).to eq first_primes.take(n_samples)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "fetches N primes, with C code" do
|
43
|
+
n_samples = 100
|
44
|
+
primes = PrimeLib::Generator.new(n_samples, engine: PrimeLib::Generator::SieveOfEratosthenesC.new).to_a
|
45
|
+
expect(primes.to_a).to eq first_primes.take(n_samples)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "fetches N primes, test with regex" do
|
49
|
+
primes = PrimeLib::Generator.new(1000).to_a
|
50
|
+
|
51
|
+
for i in 0..1000
|
52
|
+
is_prime = primes.include?(i)
|
53
|
+
expect(RegexPrime.is_prime? i).to eq is_prime
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "PrimeLib" do
|
4
|
+
|
5
|
+
let(:prime_200_000th) { 2750159 } # http://is.2750159.aprimenumber.com/
|
6
|
+
|
7
|
+
it "compares Ruby 2.0 Prime class" do
|
8
|
+
std_class_prime = Prime::EratosthenesGenerator.new
|
9
|
+
std_class_last = 200_000.times.map { std_class_prime.next }.last
|
10
|
+
expect(std_class_last).to eq prime_200_000th
|
11
|
+
end
|
12
|
+
|
13
|
+
it "produces same values as standard Ruby 2.0 Prime class" do
|
14
|
+
primelib = PrimeLib::Generator.new(200_000)
|
15
|
+
primelib_last = primelib.to_a.last
|
16
|
+
expect(primelib_last).to eq prime_200_000th
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can speed its calculation time piping directly C code" do
|
20
|
+
primelib = PrimeLib::Generator.new(200_000, engine: PrimeLib::Generator::SieveOfEratosthenesC.new)
|
21
|
+
|
22
|
+
primelib_last = primelib.to_a.last
|
23
|
+
expect(primelib_last).to eq prime_200_000th
|
24
|
+
end
|
25
|
+
|
26
|
+
it "have an performance improvement over its competitor" do
|
27
|
+
Benchmark.bm(1) do |bm|
|
28
|
+
bm.report("Prime Ruby 2.0 "){ prime = Prime::EratosthenesGenerator.new ; 200_000.times.map { prime.next }.last }
|
29
|
+
bm.report("My implem. in ruby "){ primelib = PrimeLib::Generator.new(200_000) ; primelib.to_a.last }
|
30
|
+
bm.report("My implem. inline C"){ primelib = PrimeLib::Generator.new(200_000, engine: PrimeLib::Generator::SieveOfEratosthenesC.new) ; primelib.to_a.last }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require "benchmark"
|
5
|
+
require "awesome_print"
|
6
|
+
require "prime_lib"
|
7
|
+
|
8
|
+
Dir["#{PrimeLib::ROOT_PATH}/spec/support/**/*.rb"].each { |f| require f }
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.order = "random" # --seed 1234
|
12
|
+
|
13
|
+
config.filter_run :focus => true
|
14
|
+
config.run_all_when_everything_filtered = true
|
15
|
+
|
16
|
+
# Coloring stuff
|
17
|
+
config.color_enabled = true # Use color in STDOUT
|
18
|
+
config.tty = true
|
19
|
+
|
20
|
+
# config.include MyTestingHelpers #, :type => :controller # http://stackoverflow.com/questions/20614213/how-to-include-a-support-file-in-rails-4-for-rspec
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,500 @@
|
|
1
|
+
# https://github.com/ruby/ruby/blob/trunk/lib/prime.rb
|
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, false for a composite.
|
34
|
+
def prime?
|
35
|
+
Prime.prime?(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Iterates the given block over all prime numbers.
|
39
|
+
#
|
40
|
+
# See +Prime+#each for more details.
|
41
|
+
def Integer.each_prime(ubound, &block) # :yields: prime
|
42
|
+
Prime.each(ubound, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# The set of all prime numbers.
|
48
|
+
#
|
49
|
+
# == Example
|
50
|
+
#
|
51
|
+
# Prime.each(100) do |prime|
|
52
|
+
# p prime #=> 2, 3, 5, 7, 11, ...., 97
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# Prime is Enumerable:
|
56
|
+
#
|
57
|
+
# Prime.first 5 # => [2, 3, 5, 7, 11]
|
58
|
+
#
|
59
|
+
# == Retrieving the instance
|
60
|
+
#
|
61
|
+
# +Prime+.new is obsolete. Now +Prime+ has the default instance and you can
|
62
|
+
# access it as +Prime+.instance.
|
63
|
+
#
|
64
|
+
# For convenience, each instance method of +Prime+.instance can be accessed
|
65
|
+
# as a class method of +Prime+.
|
66
|
+
#
|
67
|
+
# e.g.
|
68
|
+
# Prime.instance.prime?(2) #=> true
|
69
|
+
# Prime.prime?(2) #=> true
|
70
|
+
#
|
71
|
+
# == Generators
|
72
|
+
#
|
73
|
+
# A "generator" provides an implementation of enumerating pseudo-prime
|
74
|
+
# numbers and it remembers the position of enumeration and upper bound.
|
75
|
+
# Furthermore, it is an external iterator of prime enumeration which is
|
76
|
+
# compatible with an Enumerator.
|
77
|
+
#
|
78
|
+
# +Prime+::+PseudoPrimeGenerator+ is the base class for generators.
|
79
|
+
# There are few implementations of generator.
|
80
|
+
#
|
81
|
+
# [+Prime+::+EratosthenesGenerator+]
|
82
|
+
# Uses eratosthenes' sieve.
|
83
|
+
# [+Prime+::+TrialDivisionGenerator+]
|
84
|
+
# Uses the trial division method.
|
85
|
+
# [+Prime+::+Generator23+]
|
86
|
+
# Generates all positive integers which are not divisible by either 2 or 3.
|
87
|
+
# This sequence is very bad as a pseudo-prime sequence. But this
|
88
|
+
# is faster and uses much less memory than the other generators. So,
|
89
|
+
# it is suitable for factorizing an integer which is not large but
|
90
|
+
# has many prime factors. e.g. for Prime#prime? .
|
91
|
+
|
92
|
+
class Prime
|
93
|
+
include Enumerable
|
94
|
+
@the_instance = Prime.new
|
95
|
+
|
96
|
+
# obsolete. Use +Prime+::+instance+ or class methods of +Prime+.
|
97
|
+
def initialize
|
98
|
+
@generator = EratosthenesGenerator.new
|
99
|
+
extend OldCompatibility
|
100
|
+
warn "Prime::new is obsolete. use Prime::instance or class methods of Prime."
|
101
|
+
end
|
102
|
+
|
103
|
+
class << self
|
104
|
+
extend Forwardable
|
105
|
+
include Enumerable
|
106
|
+
# Returns the default instance of Prime.
|
107
|
+
def instance; @the_instance end
|
108
|
+
|
109
|
+
def method_added(method) # :nodoc:
|
110
|
+
(class<< self;self;end).def_delegator :instance, method
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Iterates the given block over all prime numbers.
|
115
|
+
#
|
116
|
+
# == Parameters
|
117
|
+
#
|
118
|
+
# +ubound+::
|
119
|
+
# Optional. An arbitrary positive number.
|
120
|
+
# The upper bound of enumeration. The method enumerates
|
121
|
+
# prime numbers infinitely if +ubound+ is nil.
|
122
|
+
# +generator+::
|
123
|
+
# Optional. An implementation of pseudo-prime generator.
|
124
|
+
#
|
125
|
+
# == Return value
|
126
|
+
#
|
127
|
+
# An evaluated value of the given block at the last time.
|
128
|
+
# Or an enumerator which is compatible to an +Enumerator+
|
129
|
+
# if no block given.
|
130
|
+
#
|
131
|
+
# == Description
|
132
|
+
#
|
133
|
+
# Calls +block+ once for each prime number, passing the prime as
|
134
|
+
# a parameter.
|
135
|
+
#
|
136
|
+
# +ubound+::
|
137
|
+
# Upper bound of prime numbers. The iterator stops after it
|
138
|
+
# yields all prime numbers p <= +ubound+.
|
139
|
+
#
|
140
|
+
# == Note
|
141
|
+
#
|
142
|
+
# +Prime+.+new+ returns an object extended by +Prime+::+OldCompatibility+
|
143
|
+
# in order to be compatible with Ruby 1.8, and +Prime+#each is overwritten
|
144
|
+
# by +Prime+::+OldCompatibility+#+each+.
|
145
|
+
#
|
146
|
+
# +Prime+.+new+ is now obsolete. Use +Prime+.+instance+.+each+ or simply
|
147
|
+
# +Prime+.+each+.
|
148
|
+
def each(ubound = nil, generator = EratosthenesGenerator.new, &block)
|
149
|
+
generator.upper_bound = ubound
|
150
|
+
generator.each(&block)
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# Returns true if +value+ is prime, false for a composite.
|
155
|
+
#
|
156
|
+
# == Parameters
|
157
|
+
#
|
158
|
+
# +value+:: an arbitrary integer to be checked.
|
159
|
+
# +generator+:: optional. A pseudo-prime generator.
|
160
|
+
def prime?(value, generator = Prime::Generator23.new)
|
161
|
+
value = -value if value < 0
|
162
|
+
return false if value < 2
|
163
|
+
for num in generator
|
164
|
+
q,r = value.divmod num
|
165
|
+
return true if q < num
|
166
|
+
return false if r == 0
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Re-composes a prime factorization and returns the product.
|
171
|
+
#
|
172
|
+
# == Parameters
|
173
|
+
# +pd+:: Array of pairs of integers. The each internal
|
174
|
+
# pair consists of a prime number -- a prime factor --
|
175
|
+
# and a natural number -- an exponent.
|
176
|
+
#
|
177
|
+
# == Example
|
178
|
+
# For <tt>[[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]]</tt>, it returns:
|
179
|
+
#
|
180
|
+
# p_1**e_1 * p_2**e_2 * .... * p_n**e_n.
|
181
|
+
#
|
182
|
+
# Prime.int_from_prime_division([[2,2], [3,1]]) #=> 12
|
183
|
+
def int_from_prime_division(pd)
|
184
|
+
pd.inject(1){|value, (prime, index)|
|
185
|
+
value *= prime**index
|
186
|
+
}
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns the factorization of +value+.
|
190
|
+
#
|
191
|
+
# == Parameters
|
192
|
+
# +value+:: An arbitrary integer.
|
193
|
+
# +generator+:: Optional. A pseudo-prime generator.
|
194
|
+
# +generator+.succ must return the next
|
195
|
+
# pseudo-prime number in the ascending
|
196
|
+
# order. It must generate all prime numbers,
|
197
|
+
# but may also generate non prime numbers too.
|
198
|
+
#
|
199
|
+
# === Exceptions
|
200
|
+
# +ZeroDivisionError+:: when +value+ is zero.
|
201
|
+
#
|
202
|
+
# == Example
|
203
|
+
# For an arbitrary integer:
|
204
|
+
#
|
205
|
+
# n = p_1**e_1 * p_2**e_2 * .... * p_n**e_n,
|
206
|
+
#
|
207
|
+
# prime_division(n) returns:
|
208
|
+
#
|
209
|
+
# [[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]].
|
210
|
+
#
|
211
|
+
# Prime.prime_division(12) #=> [[2,2], [3,1]]
|
212
|
+
#
|
213
|
+
def prime_division(value, generator = Prime::Generator23.new)
|
214
|
+
raise ZeroDivisionError if value == 0
|
215
|
+
if value < 0
|
216
|
+
value = -value
|
217
|
+
pv = [[-1, 1]]
|
218
|
+
else
|
219
|
+
pv = []
|
220
|
+
end
|
221
|
+
for prime in generator
|
222
|
+
count = 0
|
223
|
+
while (value1, mod = value.divmod(prime)
|
224
|
+
mod) == 0
|
225
|
+
value = value1
|
226
|
+
count += 1
|
227
|
+
end
|
228
|
+
if count != 0
|
229
|
+
pv.push [prime, count]
|
230
|
+
end
|
231
|
+
break if value1 <= prime
|
232
|
+
end
|
233
|
+
if value > 1
|
234
|
+
pv.push [value, 1]
|
235
|
+
end
|
236
|
+
return pv
|
237
|
+
end
|
238
|
+
|
239
|
+
# An abstract class for enumerating pseudo-prime numbers.
|
240
|
+
#
|
241
|
+
# Concrete subclasses should override succ, next, rewind.
|
242
|
+
class PseudoPrimeGenerator
|
243
|
+
include Enumerable
|
244
|
+
|
245
|
+
def initialize(ubound = nil)
|
246
|
+
@ubound = ubound
|
247
|
+
end
|
248
|
+
|
249
|
+
def upper_bound=(ubound)
|
250
|
+
@ubound = ubound
|
251
|
+
end
|
252
|
+
def upper_bound
|
253
|
+
@ubound
|
254
|
+
end
|
255
|
+
|
256
|
+
# returns the next pseudo-prime number, and move the internal
|
257
|
+
# position forward.
|
258
|
+
#
|
259
|
+
# +PseudoPrimeGenerator+#succ raises +NotImplementedError+.
|
260
|
+
def succ
|
261
|
+
raise NotImplementedError, "need to define `succ'"
|
262
|
+
end
|
263
|
+
|
264
|
+
# alias of +succ+.
|
265
|
+
def next
|
266
|
+
raise NotImplementedError, "need to define `next'"
|
267
|
+
end
|
268
|
+
|
269
|
+
# Rewinds the internal position for enumeration.
|
270
|
+
#
|
271
|
+
# See +Enumerator+#rewind.
|
272
|
+
def rewind
|
273
|
+
raise NotImplementedError, "need to define `rewind'"
|
274
|
+
end
|
275
|
+
|
276
|
+
# Iterates the given block for each prime number.
|
277
|
+
def each(&block)
|
278
|
+
return self.dup unless block
|
279
|
+
if @ubound
|
280
|
+
last_value = nil
|
281
|
+
loop do
|
282
|
+
prime = succ
|
283
|
+
break last_value if prime > @ubound
|
284
|
+
last_value = block.call(prime)
|
285
|
+
end
|
286
|
+
else
|
287
|
+
loop do
|
288
|
+
block.call(succ)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# see +Enumerator+#with_index.
|
294
|
+
alias with_index each_with_index
|
295
|
+
|
296
|
+
# see +Enumerator+#with_object.
|
297
|
+
def with_object(obj)
|
298
|
+
return enum_for(:with_object) unless block_given?
|
299
|
+
each do |prime|
|
300
|
+
yield prime, obj
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
# An implementation of +PseudoPrimeGenerator+.
|
306
|
+
#
|
307
|
+
# Uses +EratosthenesSieve+.
|
308
|
+
class EratosthenesGenerator < PseudoPrimeGenerator
|
309
|
+
def initialize
|
310
|
+
@last_prime_index = -1
|
311
|
+
super
|
312
|
+
end
|
313
|
+
|
314
|
+
def succ
|
315
|
+
@last_prime_index += 1
|
316
|
+
EratosthenesSieve.instance.get_nth_prime(@last_prime_index)
|
317
|
+
end
|
318
|
+
|
319
|
+
def curr
|
320
|
+
EratosthenesSieve.instance.get_last
|
321
|
+
end
|
322
|
+
|
323
|
+
def rewind
|
324
|
+
initialize
|
325
|
+
end
|
326
|
+
alias next succ
|
327
|
+
end
|
328
|
+
|
329
|
+
# An implementation of +PseudoPrimeGenerator+ which uses
|
330
|
+
# a prime table generated by trial division.
|
331
|
+
class TrialDivisionGenerator<PseudoPrimeGenerator
|
332
|
+
def initialize
|
333
|
+
@index = -1
|
334
|
+
super
|
335
|
+
end
|
336
|
+
|
337
|
+
def succ
|
338
|
+
TrialDivision.instance[@index += 1]
|
339
|
+
end
|
340
|
+
def rewind
|
341
|
+
initialize
|
342
|
+
end
|
343
|
+
alias next succ
|
344
|
+
end
|
345
|
+
|
346
|
+
# Generates all integers which are greater than 2 and
|
347
|
+
# are not divisible by either 2 or 3.
|
348
|
+
#
|
349
|
+
# This is a pseudo-prime generator, suitable on
|
350
|
+
# checking primality of an integer by brute force
|
351
|
+
# method.
|
352
|
+
class Generator23<PseudoPrimeGenerator
|
353
|
+
def initialize
|
354
|
+
@prime = 1
|
355
|
+
@step = nil
|
356
|
+
super
|
357
|
+
end
|
358
|
+
|
359
|
+
def succ
|
360
|
+
loop do
|
361
|
+
if (@step)
|
362
|
+
@prime += @step
|
363
|
+
@step = 6 - @step
|
364
|
+
else
|
365
|
+
case @prime
|
366
|
+
when 1; @prime = 2
|
367
|
+
when 2; @prime = 3
|
368
|
+
when 3; @prime = 5; @step = 2
|
369
|
+
end
|
370
|
+
end
|
371
|
+
return @prime
|
372
|
+
end
|
373
|
+
end
|
374
|
+
alias next succ
|
375
|
+
def rewind
|
376
|
+
initialize
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Internal use. An implementation of prime table by trial division method.
|
381
|
+
class TrialDivision
|
382
|
+
include Singleton
|
383
|
+
|
384
|
+
def initialize # :nodoc:
|
385
|
+
# These are included as class variables to cache them for later uses. If memory
|
386
|
+
# usage is a problem, they can be put in Prime#initialize as instance variables.
|
387
|
+
|
388
|
+
# There must be no primes between @primes[-1] and @next_to_check.
|
389
|
+
@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]
|
390
|
+
# @next_to_check % 6 must be 1.
|
391
|
+
@next_to_check = 103 # @primes[-1] - @primes[-1] % 6 + 7
|
392
|
+
@ulticheck_index = 3 # @primes.index(@primes.reverse.find {|n|
|
393
|
+
# n < Math.sqrt(@@next_to_check) })
|
394
|
+
@ulticheck_next_squared = 121 # @primes[@ulticheck_index + 1] ** 2
|
395
|
+
end
|
396
|
+
|
397
|
+
# Returns the cached prime numbers.
|
398
|
+
def cache
|
399
|
+
return @primes
|
400
|
+
end
|
401
|
+
alias primes cache
|
402
|
+
alias primes_so_far cache
|
403
|
+
|
404
|
+
# Returns the +index+th prime number.
|
405
|
+
#
|
406
|
+
# +index+ is a 0-based index.
|
407
|
+
def [](index)
|
408
|
+
while index >= @primes.length
|
409
|
+
# Only check for prime factors up to the square root of the potential primes,
|
410
|
+
# but without the performance hit of an actual square root calculation.
|
411
|
+
if @next_to_check + 4 > @ulticheck_next_squared
|
412
|
+
@ulticheck_index += 1
|
413
|
+
@ulticheck_next_squared = @primes.at(@ulticheck_index + 1) ** 2
|
414
|
+
end
|
415
|
+
# Only check numbers congruent to one and five, modulo six. All others
|
416
|
+
|
417
|
+
# are divisible by two or three. This also allows us to skip checking against
|
418
|
+
# two and three.
|
419
|
+
@primes.push @next_to_check if @primes[2..@ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
|
420
|
+
@next_to_check += 4
|
421
|
+
@primes.push @next_to_check if @primes[2..@ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
|
422
|
+
@next_to_check += 2
|
423
|
+
end
|
424
|
+
return @primes[index]
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
# Internal use. An implementation of eratosthenes' sieve
|
429
|
+
class EratosthenesSieve
|
430
|
+
include Singleton
|
431
|
+
|
432
|
+
def initialize
|
433
|
+
@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]
|
434
|
+
# @max_checked must be an even number
|
435
|
+
@max_checked = @primes.last + 1
|
436
|
+
end
|
437
|
+
|
438
|
+
def get_last
|
439
|
+
@primes.last
|
440
|
+
end
|
441
|
+
|
442
|
+
def get_nth_prime(n)
|
443
|
+
compute_primes while @primes.size <= n
|
444
|
+
@primes[n]
|
445
|
+
end
|
446
|
+
|
447
|
+
private
|
448
|
+
def compute_primes
|
449
|
+
# max_segment_size must be an even number
|
450
|
+
max_segment_size = 1e6.to_i
|
451
|
+
max_cached_prime = @primes.last
|
452
|
+
# do not double count primes if #compute_primes is interrupted
|
453
|
+
# by Timeout.timeout
|
454
|
+
@max_checked = max_cached_prime + 1 if max_cached_prime > @max_checked
|
455
|
+
|
456
|
+
segment_min = @max_checked
|
457
|
+
segment_max = [segment_min + max_segment_size, max_cached_prime * 2].min
|
458
|
+
root = Integer(Math.sqrt(segment_max).floor)
|
459
|
+
|
460
|
+
sieving_primes = @primes[1 .. -1].take_while { |prime| prime <= root }
|
461
|
+
offsets = Array.new(sieving_primes.size) do |i|
|
462
|
+
(-(segment_min + 1 + sieving_primes[i]) / 2) % sieving_primes[i]
|
463
|
+
end
|
464
|
+
|
465
|
+
segment = ((segment_min + 1) .. segment_max).step(2).to_a
|
466
|
+
sieving_primes.each_with_index do |prime, index|
|
467
|
+
composite_index = offsets[index]
|
468
|
+
while composite_index < segment.size do
|
469
|
+
segment[composite_index] = nil
|
470
|
+
composite_index += prime
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
segment.each do |prime|
|
475
|
+
@primes.push prime unless prime.nil?
|
476
|
+
end
|
477
|
+
@max_checked = segment_max
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
# Provides a +Prime+ object with compatibility to Ruby 1.8 when instantiated via +Prime+.+new+.
|
482
|
+
module OldCompatibility
|
483
|
+
# Returns the next prime number and forwards internal pointer.
|
484
|
+
def succ
|
485
|
+
@generator.succ
|
486
|
+
end
|
487
|
+
alias next succ
|
488
|
+
|
489
|
+
# Overwrites Prime#each.
|
490
|
+
#
|
491
|
+
# Iterates the given block over all prime numbers. Note that enumeration
|
492
|
+
# starts from the current position of internal pointer, not rewound.
|
493
|
+
def each(&block)
|
494
|
+
return @generator.dup unless block_given?
|
495
|
+
loop do
|
496
|
+
yield succ
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prime_lib
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adit
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: RubyInline
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.12.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.12.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: terminal-table
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: rake
|
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
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: awesome_print
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Write a program that calculates and prints out a multiplication table
|
84
|
+
of the first 10 calculated prime numbers.
|
85
|
+
email:
|
86
|
+
- a.saxena@email.it
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- .gitignore
|
92
|
+
- Gemfile
|
93
|
+
- Gemfile.lock
|
94
|
+
- LICENCE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- lib/prime_lib.rb
|
98
|
+
- lib/prime_lib/decorator/table.rb
|
99
|
+
- lib/prime_lib/decorator/table_product.rb
|
100
|
+
- lib/prime_lib/generator.rb
|
101
|
+
- lib/prime_lib/generator/gen_engine.rb
|
102
|
+
- lib/prime_lib/generator/sieve_of_eratosthenes.rb
|
103
|
+
- lib/prime_lib/generator/sieve_of_eratosthenes_c.rb
|
104
|
+
- lib/prime_lib/generator_product.rb
|
105
|
+
- lib/prime_lib/version.rb
|
106
|
+
- prime_lib.gemspec
|
107
|
+
- spec/decorator/table_spec.rb
|
108
|
+
- spec/generator/generator_product_spec.rb
|
109
|
+
- spec/generator/generator_spec.rb
|
110
|
+
- spec/performance/performance_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
- spec/support/original_prime.rb
|
113
|
+
- spec/support/regex_prime.rb
|
114
|
+
homepage: https://bitbucket.org/aditsaxena/prime_lib/src
|
115
|
+
licenses: []
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.1.11
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: The program must run from the command line and print to screen 1 table. Across
|
137
|
+
the top and down the left side should be the 10 primes, and the body of the table
|
138
|
+
should contain the product of multiplying these numbers.
|
139
|
+
test_files:
|
140
|
+
- spec/decorator/table_spec.rb
|
141
|
+
- spec/generator/generator_product_spec.rb
|
142
|
+
- spec/generator/generator_spec.rb
|
143
|
+
- spec/performance/performance_spec.rb
|
144
|
+
- spec/spec_helper.rb
|
145
|
+
- spec/support/original_prime.rb
|
146
|
+
- spec/support/regex_prime.rb
|