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 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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in prime_numbers.gemspec
4
+ gemspec
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,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = 'spec/**/*_spec.rb'
7
+ spec.rspec_opts = ['--color']
8
+ end
9
+ task :default => :spec
10
+ rescue LoadError
11
+ nil
12
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module PrimeLib
2
+ VERSION = "0.1.0"
3
+ 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
@@ -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
@@ -0,0 +1,5 @@
1
+ module RegexPrime
2
+ def self.is_prime?(n)
3
+ ('1' * n) !~ /^1?$|^(11+?)\1+$/
4
+ end
5
+ 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