Standard Deviation question regarding EDOM errors

Okay,

Take a very close look at the two (one is a class, the other is a
method):

class Stdev
def initialize(arr)
@arr = arr
@size = @arr.to_a.size
end

def sum
@arr.inject {|a,b| a + b }
end

def product
@arr.inject {|a,b| a * b }
end

def calculate
Math.sqrt(((product - (sum * sum)/@size)/(@size-1)))
end

end

def stddev(arr)
size = arr.to_a.size
product, sum = 0.0, 0.0
arr.each do |a|
sum += a
product += a*a
end
std = Math.sqrt(((product - (sum * sum)/size)/(size-1)))
return std
end

Testing with both:

a = [123.369, 68.6179]

Stdev.new(a).calculate
=> Errno::EDOM: Domain error - sqrt

stddev(a)
=> 38.7148740874228

Test a web calculator for the same thing:

http://www.easycalculation.com/statistics/standard-deviation.php

The method will pan out.

So, to save suspense the reason why the class is erroring out is because
the sqrt is being attempted on a negative number. Therefore, in order
to continue to use that I would have to require ‘complex’ and the return
values from complex return two values in an array.

I’m just curious, why, given both of these being so very similar - the
method passes but the class fails?

Hi –

On Wed, 22 Jul 2009, Älphä Blüë wrote:

def product
@arr.inject {|a,b| a * b }
end

product, sum = 0.0, 0.0
arr.each do |a|
sum += a
product += a*a
end

The logic in the second snippet is wrong (assuming the logic in the
product method is what you want). Try it with [1,2], for example, and
you’ll get 2 for the first one and 5 for the second.

David

The logic in the second snippet is wrong (assuming the logic in the
product method is what you want). Try it with [1,2], for example, and
you’ll get 2 for the first one and 5 for the second.

David

Hi David,

Please bear with me as my brain is a bit fried - been working on a lot
of complex issues all day long and so my mind is mush at this point. I
don’t quite follow…

The method produces correct standard deviation results everytime…

a = [1,2,3,4,5]
b = [1,2]
c = [123.369, 68.6179]

stddev(a)
=> 1.58113883008419

stddev(b)
=> 0.707106781186548

stddev©
=> 38.7148740874228

Hi David,

I think I understand what you are saying…

What I want with…

product += a*a

is … a[0]*a[0]+a[1]*a[1]+a[2]*a[2]…etc.

Hi –

On Wed, 22 Jul 2009, Älphä Blüë wrote:

of complex issues all day long and so my mind is mush at this point. I
don’t quite follow…

The method is calculating “product” as the sum of the squares (which I
don’t actually think is the product, is it?). The class’s product
method is calculating the product of all the elements of the array. So
they’re different.

[1,2,3].inject {|a,b| a * b } # 6

total = 0.0
[1,2,3].each {|a| total += a * a }
total # 14.0

David

Hi –

On Wed, 22 Jul 2009, Älphä Blüë wrote:

Hi David,

I think I understand what you are saying…

What I want with…

product += a*a

is … a[0]*a[0]+a[1]*a[1]+a[2]*a[2]…etc.

OK, then the product method in the class is wrong. “Product” doesn’t
sound like the right name for a sum-of-the-squares calculation. But
anyway –

def whatever_you_call_it # :slight_smile:
@arr.inject(0) {|acc,x| acc + x * x }
end

David

Hi David,

Thanks for showing me my error. So, I implemented a change in the class
for testing purposes:

class Stdev
def initialize(arr)
@arr = arr
@size = @arr.to_a.size
end

def sum
  @arr.inject {|a,b| a + b }
end


def product
  total = 0.0
  @arr.each {|a| total += a * a }
  total
end

def calculate
  Math.sqrt(((product - (sum * sum)/@size)/(@size-1)))
end

end

Running the same test with the same things:

a = [1,2,3,4,5]
b = [1,2]
c = [123.369, 68.6179]

stddev(a)
=> 1.58113883008419 (correct)

stddev(b)
=> 1.0 (NOT expected)

stddev©
=> 38.7148740874228 (correct)

So, compared to the class now, versus the method I created, do you see
any anomolies that would change this behavior?

Thanks so much David - that’s perfect…

Works great now as a class…

Hi –

On Wed, 22 Jul 2009, Älphä Blüë wrote:

def sum
@arr.inject {|a,b| a + b }
end

@arr.inject(0.0) {|a,b| a + b }

which will give you a float error (which corresponds to what you have
in the method version).

So, compared to the class now, versus the method I created, do you see
any anomolies that would change this behavior?

See above :slight_smile:

David