primetable 0.0.1 → 0.2.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 +4 -4
- data/Gemfile.lock +3 -1
- data/README.md +13 -0
- data/bin/primetable +99 -0
- data/data/prime.dat +13413 -0
- data/lib/primetable.rb +136 -3
- data/lib/primetable/version.rb +2 -2
- data/lib/timer.rb +28 -0
- data/primetable.gemspec +1 -0
- data/spec/primetable_spec.rb +58 -1
- metadata +21 -3
data/lib/primetable.rb
CHANGED
@@ -1,5 +1,138 @@
|
|
1
|
+
# Not sure why this is here. I'll have to experiment with taking it out.
|
1
2
|
require "primetable/version"
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
# This is needed for load_primes method, which loads data from a file.
|
5
|
+
require "yaml"
|
6
|
+
|
7
|
+
# I'll probably remove this later, but it's my interim table display solution.
|
8
|
+
require "awesome_print"
|
9
|
+
|
10
|
+
# It's a pretty simple program. I considered making multiple classes, but it's not necessary.
|
11
|
+
class PrimeTable
|
12
|
+
|
13
|
+
# We're going to want to get and set things from inside multiple methods, so...
|
14
|
+
attr_accessor :primes, :table
|
15
|
+
|
16
|
+
def initialize(first=1, count=10, prime_method=:calc, suppress_output=false)
|
17
|
+
|
18
|
+
# This is only for testing, I'm unlikely to implement a command-line flag for this
|
19
|
+
unless suppress_output
|
20
|
+
|
21
|
+
puts "PrimeTable is running..."
|
22
|
+
end
|
23
|
+
|
24
|
+
# Ye olde instance variables
|
25
|
+
@primes = init_primes(:load,first,count)
|
26
|
+
@table = build_data(@primes)
|
27
|
+
|
28
|
+
# I added this suppress_output so I could run certain tests without a huge, admittly
|
29
|
+
# ugly, table clobbering my nice green passing specs
|
30
|
+
unless suppress_output
|
31
|
+
display_table(@table)
|
32
|
+
end
|
33
|
+
|
34
|
+
end # def initialize()
|
35
|
+
|
36
|
+
# One way or another, we need to get an array of consecutive prime numbers.
|
37
|
+
def init_primes(prime_method, first, count)
|
38
|
+
|
39
|
+
# Of course, we calculate the primes by default. But having three methods is not only
|
40
|
+
# fancy; it's also comes in handy for testing that our calculated values are correct.
|
41
|
+
case prime_method
|
42
|
+
when :fast # Shaves off about between 10 and 40 milliseconds vs. the :load method
|
43
|
+
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
|
44
|
+
|
45
|
+
when :load # Using precalculated values saves us a lot of time vs. the :calc method
|
46
|
+
load_primes(first,count)
|
47
|
+
when :calc # The slowest, but presumably preferred, method in our arsenal
|
48
|
+
calc_primes(first,count)
|
49
|
+
end # case prime_method
|
50
|
+
|
51
|
+
end # def init_primes()
|
52
|
+
|
53
|
+
# Calculates the primes using basic math. This can be slow for higher primes or higher counts.
|
54
|
+
# TODO: Include note on computational complexity here: O(n*sqrt(n)), I think
|
55
|
+
# TODO: Include note on average run time using this method.
|
56
|
+
def calc_primes(first, count)
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# Loads precalculated primes from a data file. The file is formatted with 10 primes per line.
|
61
|
+
# Each line is enclosed in square brackets, and the primes are comma-delimited. Thus, it's
|
62
|
+
# trivial to read each line in as an array of ten primes. Please note that this file is 995K
|
63
|
+
|
64
|
+
# and contains 13413 lines. You don't want to just slurp this file. That would be rude. Instead
|
65
|
+
|
66
|
+
# we read lines one at a time and only keep what we need. Also note the highest prime in this
|
67
|
+
# file is currently 1999993, although conceivably we could use the :calc method and extend it.
|
68
|
+
def load_primes(first, count)
|
69
|
+
|
70
|
+
# Again, we only have the first 134128 primes in here right now
|
71
|
+
if (first + count) > 134128
|
72
|
+
throw "We only have the first 134128 primes in the data file right now. Please pass -c to use calculated primes."
|
73
|
+
end
|
74
|
+
|
75
|
+
# An array to keep our prime numbers in, right?
|
76
|
+
primes = []
|
77
|
+
|
78
|
+
# Because there are ten primes on each line, we can get the line number we're looking for by
|
79
|
+
# dividing the indices we want by 10 and rounding down for the bottom of our range and up for
|
80
|
+
|
81
|
+
# the top. It's not immediately intuitive why we might want to do this, but it's because:
|
82
|
+
# 1) We don't want to slurp the whole file...what if the file was even larger? Not cool.
|
83
|
+
|
84
|
+
# 2) IO.readlines gets the file one line at a time, so we need a line number, not an index.
|
85
|
+
|
86
|
+
first_line = (first/10).floor
|
87
|
+
last_line = ((first+count)/10).ceil
|
88
|
+
|
89
|
+
# Here we read in the file one line at a time. Yes I looked for a faster way. Try :fast (-f).
|
90
|
+
IO.readlines("data/prime.dat").each_with_index{|line,ln|
|
91
|
+
|
92
|
+
# When we find the lines we want, we concatenate them into a single array. We get extra.
|
93
|
+
if (ln >= first_line and ln <= last_line)
|
94
|
+
primes.concat(YAML::load(line))
|
95
|
+
end
|
96
|
+
}
|
97
|
+
|
98
|
+
# The extra is trimmed off in this step. We know what we want. Just this, thanks!
|
99
|
+
start = first - (first_line*10) - 1
|
100
|
+
return primes.slice!(start,count)
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_data(primes)
|
105
|
+
|
106
|
+
# To make this code simpler we act as if our first prime is 1 so that the matrix includes
|
107
|
+
# our header row and column of primes (multiplied by 1)...we remove the corner 1 later
|
108
|
+
primes.unshift(1)
|
109
|
+
|
110
|
+
# An empty two-dimensional array to act as the data model for our table
|
111
|
+
table = Array.new(primes.length) { Array.new(primes.length) }
|
112
|
+
|
113
|
+
# We populate the array-of-arrays with the products-of-primes ;-)
|
114
|
+
primes.each_with_index{|outerprime,i|
|
115
|
+
primes.each_with_index{|innerprime,y|
|
116
|
+
table[i][y] = outerprime*innerprime
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
# Here we remove the corner 1 which was added as a side-effect of the matrix generation
|
121
|
+
primes.shift(1)
|
122
|
+
table[0][0] = nil
|
123
|
+
|
124
|
+
# And send the table data to display (or, in theory, whoever called us)
|
125
|
+
return table
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
# The plan is to use Formatador to make this display nicely. For now, I'm just dumping the data,
|
130
|
+
# and making it slightly less lame with awesome_print.
|
131
|
+
def display_table(table)
|
132
|
+
|
133
|
+
# Not much to see here. But I expect to be able to justify a comment soon enough.
|
134
|
+
ap table
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
data/lib/primetable/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0
|
1
|
+
class PrimeTable
|
2
|
+
VERSION = "0.2.0"
|
3
3
|
end
|
data/lib/timer.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class Timer
|
2
|
+
|
3
|
+
def self.timer(&block)
|
4
|
+
start_time = Time.now
|
5
|
+
result = block.call
|
6
|
+
end_time = Time.now
|
7
|
+
@time_taken = (end_time - start_time) * 1000
|
8
|
+
result
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.humanize ms
|
12
|
+
[[1000, :ms], [60, :secs], [60, :mins], [24, :hrs], [365, :days], [10000, :yrs]].map{ |count, name|
|
13
|
+
if ms > 0
|
14
|
+
ms, n = ms.divmod(count)
|
15
|
+
"#{n.to_i} #{name}"
|
16
|
+
end
|
17
|
+
}.compact.reverse.join(' ')
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.elapsedTime
|
21
|
+
humanize @time_taken
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.time()
|
25
|
+
elapsedTime
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/primetable.gemspec
CHANGED
data/spec/primetable_spec.rb
CHANGED
@@ -1,8 +1,65 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe PrimeTable do
|
4
|
+
before(:all) do
|
5
|
+
@expected_execution_output = "PrimeTable is running...\n"
|
6
|
+
@expected_time_output = "ms"
|
7
|
+
@expected_version_output = PrimeTable::VERSION
|
8
|
+
@expected_help_output = "Common options:
|
9
|
+
-t, --time Display run time
|
10
|
+
-h, --help Show this message
|
11
|
+
-v, --version Show version"
|
12
|
+
@expected_first_ten_primes = [2,3,5,7,11,13,17,19,23,29]
|
13
|
+
@expected_table_with_first_ten_primes = [[nil,2,3,5,7,11,13,17,19,23,29],
|
14
|
+
[2,4,6,10,14,22,26,34,38,46,58],
|
15
|
+
[3,6,9,15,21,33,39,51,57,69,87],
|
16
|
+
[5,10,15,25,35,55,65,85,95,115,145],
|
17
|
+
[7,14,21,35,49,77,91,119,133,161,203],
|
18
|
+
[11,22,33,55,77,121,143,187,209,253,319],
|
19
|
+
[13,26,39,65,91,143,169,221,247,299,377],
|
20
|
+
[17,34,51,85,119,187,221,289,323,391,493],
|
21
|
+
[19,38,57,95,133,209,247,323,361,437,551],
|
22
|
+
[23,46,69,115,161,253,299,391,437,529,667],
|
23
|
+
[29,58,87,145,203,319,377,493,551,667,841]]
|
24
|
+
end
|
4
25
|
it 'has a version number' do
|
5
26
|
expect(PrimeTable::VERSION).not_to be nil
|
6
27
|
end
|
7
|
-
|
28
|
+
it 'executes when called on the command line' do
|
29
|
+
expect(`primetable`).to include("PrimeTable is running...\n")
|
30
|
+
end
|
31
|
+
it 'executes *and* prints out a run time when passed -t or --time' do
|
32
|
+
execution_output = `primetable -t`
|
33
|
+
expect(execution_output).to include(@expected_execution_output)
|
34
|
+
expect(execution_output).to include(@expected_time_output)
|
35
|
+
execution_output = `primetable --time`
|
36
|
+
expect(execution_output).to include(@expected_execution_output)
|
37
|
+
expect(execution_output).to include(@expected_time_output)
|
38
|
+
end
|
39
|
+
it 'prints out the version number when passed -v or --version' do
|
40
|
+
expect(`primetable -v`).to include(@expected_version_output)
|
41
|
+
end
|
42
|
+
it 'executes *and* prints out a run time *and* prints out the version number when passed both -t and -v arguments' do
|
43
|
+
execution_output = `primetable -tv`
|
44
|
+
expect(execution_output).to include(@expected_execution_output)
|
45
|
+
expect(execution_output).to include(@expected_time_output)
|
46
|
+
expect(execution_output).to include(@expected_version_output)
|
47
|
+
end
|
48
|
+
it 'executes *and* prints out a run time *and* prints out the version number when passed both --time and --version arguments' do
|
49
|
+
execution_output = `primetable -tv`
|
50
|
+
expect(execution_output).to include(@expected_execution_output)
|
51
|
+
expect(execution_output).to include(@expected_time_output)
|
52
|
+
expect(execution_output).to include(@expected_version_output)
|
53
|
+
end
|
54
|
+
it 'prints out usage details when passed -h or --help' do
|
55
|
+
execution_output = `primetable -h`
|
56
|
+
expect(execution_output).to include(@expected_help_output)
|
57
|
+
execution_output = `primetable --help`
|
58
|
+
expect(execution_output).to include(@expected_help_output)
|
59
|
+
end
|
60
|
+
it "has the right data when we run it with :load" do
|
61
|
+
test_instance = PrimeTable.new(1,10,:load,true)
|
62
|
+
expect(test_instance.primes).to eq(@expected_first_ten_primes)
|
63
|
+
expect(test_instance.table).to eq(@expected_table_with_first_ten_primes)
|
64
|
+
end
|
8
65
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: primetable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Day Davis Waterbury
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,11 +52,26 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: awesome_print
|
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'
|
55
69
|
description: Displays the products of N primes in a table format. Optionally uses
|
56
70
|
generated primes or precalculated.
|
57
71
|
email:
|
58
72
|
- day.waterbury@gmail.com
|
59
|
-
executables:
|
73
|
+
executables:
|
74
|
+
- primetable
|
60
75
|
extensions: []
|
61
76
|
extra_rdoc_files: []
|
62
77
|
files:
|
@@ -67,8 +82,11 @@ files:
|
|
67
82
|
- LICENSE.txt
|
68
83
|
- README.md
|
69
84
|
- Rakefile
|
85
|
+
- bin/primetable
|
86
|
+
- data/prime.dat
|
70
87
|
- lib/primetable.rb
|
71
88
|
- lib/primetable/version.rb
|
89
|
+
- lib/timer.rb
|
72
90
|
- primetable.gemspec
|
73
91
|
- spec/primetable_spec.rb
|
74
92
|
- spec/spec_helper.rb
|