prime_lib 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 +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
|