means 1.1.0 → 1.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.
- data/VERSION +1 -1
- data/lib/means.rb +38 -12
- data/means.gemspec +2 -2
- data/spec/means_spec.rb +57 -4
- metadata +13 -13
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/lib/means.rb
CHANGED
@@ -8,23 +8,23 @@ class Mean
|
|
8
8
|
|
9
9
|
# Calculate the arithmetic mean
|
10
10
|
# @param [Array<Numeric>] data the data values
|
11
|
-
# @return [Numeric] the arithmetic mean
|
11
|
+
# @return [Numeric, nil] the arithmetic mean or nil if there is no data
|
12
12
|
def Mean.arithmetic(data)
|
13
13
|
data.reduce(:+) / data.size unless data.empty?
|
14
14
|
end
|
15
15
|
|
16
16
|
# Calculate the geometric mean
|
17
17
|
# @param (see Mean.arithmetic)
|
18
|
-
# @return [Numeric] the geometric mean
|
18
|
+
# @return [Numeric, nil] the geometric mean or nil if there is no data or any elements are zero or negative
|
19
19
|
def Mean.geometric(data)
|
20
|
-
data.reduce(:*) ** (1 / data.size) unless data.empty?
|
20
|
+
data.reduce(:*) ** (1 / data.size) unless data.empty? or includes_zero_or_negative? data
|
21
21
|
end
|
22
22
|
|
23
23
|
# Calculate the harmonic mean
|
24
24
|
# @param (see Mean.arithmetic)
|
25
|
-
# @return [Numeric] the harmonic mean
|
25
|
+
# @return [Numeric, nil] the harmonic mean or nil if there is no data or any elements are zero or negative
|
26
26
|
def Mean.harmonic(data)
|
27
|
-
data.size / data.reduce(0) {|sum, element| sum += (1 / element)} unless data.empty?
|
27
|
+
data.size / data.reduce(0) {|sum, element| sum += (1 / element)} unless data.empty? or includes_zero_or_negative? data
|
28
28
|
end
|
29
29
|
|
30
30
|
# Remember the initial state.
|
@@ -34,37 +34,63 @@ class Mean
|
|
34
34
|
# [geometric mean] needs `:product` and `:count`
|
35
35
|
# [harmonic mean] needs `:sum_of_reciprocals` and `:count`
|
36
36
|
# @param [Hash{Symbol => Numeric}]
|
37
|
+
# @raise if `:count` is negative
|
38
|
+
# @raise if `:sum_of_reciprocals` is negative
|
39
|
+
# @raise if `:product` is negative
|
37
40
|
def initialize(params={})
|
41
|
+
raise_error_for_negative params, :count
|
42
|
+
raise_error_for_negative params, :sum_of_reciprocals
|
43
|
+
raise_error_for_negative params, :product
|
44
|
+
|
38
45
|
@sum ||= params[:sum] ||= 0
|
39
46
|
@sum_of_reciprocals ||= params[:sum_of_reciprocals] ||= 0
|
40
47
|
@product ||= params[:product] ||= 1
|
41
48
|
@count ||= params[:count] ||= 0
|
49
|
+
@includes_zero_or_negative = false
|
42
50
|
end
|
43
51
|
|
44
52
|
# Add element to the data set
|
45
53
|
# @param [Numeric] element the element to add
|
46
54
|
def push(element)
|
55
|
+
if Mean.zero_or_negative? element
|
56
|
+
@includes_zero_or_negative = true
|
57
|
+
end
|
58
|
+
|
47
59
|
@sum += element
|
48
|
-
@sum_of_reciprocals += (1 / element)
|
49
|
-
@product *= element
|
60
|
+
@sum_of_reciprocals += (1 / element) unless @includes_zero_or_negative
|
61
|
+
@product *= element unless @includes_zero_or_negative
|
50
62
|
@count += 1
|
51
63
|
end
|
52
64
|
|
53
65
|
# Calculate the arithmetic mean
|
54
|
-
# @return [Numeric] the arithmetic mean
|
66
|
+
# @return [Numeric, nil] the arithmetic mean or nil if there is no data
|
55
67
|
def arithmetic_mean
|
56
68
|
@sum / @count unless @count.zero?
|
57
69
|
end
|
58
70
|
|
59
71
|
# Calculate the geometric mean
|
60
|
-
# @return [Numeric] the geometric mean
|
72
|
+
# @return [Numeric, nil] the geometric mean or nil if there is no data or any elements are zero or negative
|
61
73
|
def geometric_mean
|
62
|
-
@product ** (1 / @count) unless @count.zero?
|
74
|
+
@product ** (1 / @count) unless @count.zero? or @includes_zero_or_negative
|
63
75
|
end
|
64
76
|
|
65
77
|
# Calculate the harmonic mean
|
66
|
-
# @return [Numeric] the harmonic mean
|
78
|
+
# @return [Numeric, nil] the harmonic mean or nil if there is no data or any elements are zero or negative
|
67
79
|
def harmonic_mean
|
68
|
-
@count / @sum_of_reciprocals unless @count.zero?
|
80
|
+
@count / @sum_of_reciprocals unless @count.zero? or @includes_zero_or_negative
|
69
81
|
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def Mean.includes_zero_or_negative? data
|
86
|
+
data.any? { |element| zero_or_negative? element }
|
87
|
+
end
|
88
|
+
|
89
|
+
def Mean.zero_or_negative? element
|
90
|
+
element <= 0
|
91
|
+
end
|
92
|
+
|
93
|
+
def raise_error_for_negative params, key
|
94
|
+
raise %{cannot have negative "#{key.to_s}" of "#{params[key]}"} if params.has_key? key and params[key] < 0
|
95
|
+
end
|
70
96
|
end
|
data/means.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "means"
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nigel Lowry"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-04-12"
|
13
13
|
s.description = "Calculates the different means for a data set (arithmetic, geometric and harmonic)."
|
14
14
|
s.email = "nigel-lowry@ultra.eclipse.co.uk"
|
15
15
|
s.extra_rdoc_files = [
|
data/spec/means_spec.rb
CHANGED
@@ -20,9 +20,14 @@ end
|
|
20
20
|
|
21
21
|
shared_examples_for "non-arithmetic means" do
|
22
22
|
[:geometric, :harmonic].each do |mean|
|
23
|
-
it "is
|
23
|
+
it "is nil when there are any zeroes" do
|
24
24
|
data = [1.1, 2.2, 0.0]
|
25
|
-
Mean.send(mean, data).should
|
25
|
+
Mean.send(mean, data).should be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it "is nil when there are any negative numbers" do
|
29
|
+
data = [1, -1]
|
30
|
+
Mean.send(mean, data).should be_nil
|
26
31
|
end
|
27
32
|
end
|
28
33
|
end
|
@@ -56,6 +61,16 @@ describe "Mean" do
|
|
56
61
|
data = [1, 2, 3]
|
57
62
|
Mean.arithmetic(data).should == 2
|
58
63
|
end
|
64
|
+
|
65
|
+
it "works with zero" do
|
66
|
+
data = [0, 2]
|
67
|
+
Mean.arithmetic(data).should == 1
|
68
|
+
end
|
69
|
+
|
70
|
+
it "works with negative numbers" do
|
71
|
+
data = [-1, 3]
|
72
|
+
Mean.arithmetic(data).should == 1
|
73
|
+
end
|
59
74
|
end
|
60
75
|
|
61
76
|
describe ".geometric" do
|
@@ -107,26 +122,52 @@ describe "Mean" do
|
|
107
122
|
@m.arithmetic_mean.should == 1.5
|
108
123
|
@m.push 3
|
109
124
|
@m.arithmetic_mean.should == 2
|
125
|
+
@m.push 0
|
126
|
+
@m.arithmetic_mean.should == 1.5
|
110
127
|
end
|
111
128
|
end
|
112
129
|
|
113
130
|
describe "#geometric_mean" do
|
114
|
-
it "accumulates the geometric mean" do
|
131
|
+
it "accumulates the geometric mean until zero" do
|
132
|
+
@m.geometric_mean.should be_nil
|
133
|
+
@m.push 2
|
134
|
+
@m.geometric_mean.should == 2
|
135
|
+
@m.push 8
|
136
|
+
@m.geometric_mean.should == 4
|
137
|
+
@m.push 0
|
138
|
+
@m.geometric_mean.should be_nil
|
139
|
+
end
|
140
|
+
|
141
|
+
it "accumulates the geometric mean until negative" do
|
115
142
|
@m.geometric_mean.should be_nil
|
116
143
|
@m.push 2
|
117
144
|
@m.geometric_mean.should == 2
|
118
145
|
@m.push 8
|
119
146
|
@m.geometric_mean.should == 4
|
147
|
+
@m.push -1
|
148
|
+
@m.geometric_mean.should be_nil
|
120
149
|
end
|
121
150
|
end
|
122
151
|
|
123
152
|
describe "#harmonic_mean" do
|
124
|
-
it "accumulates the harmonic mean" do
|
153
|
+
it "accumulates the harmonic mean until zero" do
|
125
154
|
@m.harmonic_mean.should be_nil
|
126
155
|
@m.push 1
|
127
156
|
@m.harmonic_mean.should == 1
|
128
157
|
@m.push 2
|
129
158
|
@m.harmonic_mean.should == 4.0 / 3.0
|
159
|
+
@m.push 0
|
160
|
+
@m.harmonic_mean.should be_nil
|
161
|
+
end
|
162
|
+
|
163
|
+
it "accumulates the harmonic mean until negative" do
|
164
|
+
@m.harmonic_mean.should be_nil
|
165
|
+
@m.push 1
|
166
|
+
@m.harmonic_mean.should == 1
|
167
|
+
@m.push 2
|
168
|
+
@m.harmonic_mean.should == 4.0 / 3.0
|
169
|
+
@m.push -1
|
170
|
+
@m.harmonic_mean.should be_nil
|
130
171
|
end
|
131
172
|
end
|
132
173
|
end
|
@@ -152,5 +193,17 @@ describe "Mean" do
|
|
152
193
|
m.push 2
|
153
194
|
m.harmonic_mean.should == 4.0 / 3.0
|
154
195
|
end
|
196
|
+
|
197
|
+
it "rejects a negative count" do
|
198
|
+
lambda { Mean.new(count: -1) }.should raise_error
|
199
|
+
end
|
200
|
+
|
201
|
+
it "rejects negative sum of reciprocals" do
|
202
|
+
lambda { Mean.new(sum_of_reciprocals: -1) }.should raise_error
|
203
|
+
end
|
204
|
+
|
205
|
+
it "rejects negative product" do
|
206
|
+
lambda { Mean.new(product: -1) }.should raise_error
|
207
|
+
end
|
155
208
|
end
|
156
209
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: means
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70325868075600 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 2.9.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70325868075600
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: yard
|
27
|
-
requirement: &
|
27
|
+
requirement: &70325868073840 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.7.4
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70325868073840
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bundler
|
38
|
-
requirement: &
|
38
|
+
requirement: &70325868072040 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 1.0.0
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70325868072040
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: jeweler
|
49
|
-
requirement: &
|
49
|
+
requirement: &70325868132480 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.6.4
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70325868132480
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rcov
|
60
|
-
requirement: &
|
60
|
+
requirement: &70325868131760 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70325868131760
|
69
69
|
description: Calculates the different means for a data set (arithmetic, geometric
|
70
70
|
and harmonic).
|
71
71
|
email: nigel-lowry@ultra.eclipse.co.uk
|
@@ -103,7 +103,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
103
|
version: '0'
|
104
104
|
segments:
|
105
105
|
- 0
|
106
|
-
hash:
|
106
|
+
hash: 2648056903560015944
|
107
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
108
|
none: false
|
109
109
|
requirements:
|