primetable 0.0.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|