2

I trying to calculate standard deviation with a next method:

private static double? StdDev(IReadOnlyCollection<double> items) {
  if(items == null) {
    throw new ArgumentNullException("items");
  }//if

  var count = items.Count;
  if(count == 0 || count == 1) {
    return null;
  }//if

  var sum = 0d;
  var sqrsum = 0d;
  foreach(var item in items) {
    sum += item;
    sqrsum += item * item;
  }//for

  var average = sum / count;
  var stddev = Math.Sqrt((sqrsum - count * average * average) / (count - 1));
  return stddev;
}

Sometimes, the expression "sqrsum - count * average * average" is less than 0 and Math.Sqrt returns NaN. For example, in this case:

private static void Main() {
  var data = Enumerable.Repeat(86.399999999999991, 3).ToList();
  var stddev = StdDev(data);
  Console.WriteLine("StdDev = " + stddev);
}

How can I fix this cases in my code? should I use Math.Abs(sqrsum - count * average * average) or should I round something?

5
  • You can subtract average from the item before squaring inside your loop, and then just take sqrt of sum/N in the end.
    – folkol
    Apr 30, 2015 at 8:59
  • @folkol Thanks, but I want to have a single iteration of items. Apr 30, 2015 at 9:03
  • 2
    Then I guess you will be stuck with numeric errors like that. You can always check for negative numbers and return 0 before sqrt:ing.
    – folkol
    Apr 30, 2015 at 9:05
  • @folkol Thanks! May be yet another "if" is not a bad. Apr 30, 2015 at 9:07
  • No, it might work fine :) (Although, the convention for numeric methods of calculating std is doing the subtraction before squaring... For the reasons that you are experiencing above.)
    – folkol
    Apr 30, 2015 at 9:09

1 Answer 1

0

I think the following code will work for you to calculate the standard deviation.

    private object StdDev(IReadOnlyCollection<double> items)
    {
        if (items == null)
        {
            throw new ArgumentNullException("items");
        }//if

        var count = items.Count;
        if (count == 0 || count == 1)
        {
            return null;
        }//if

        var sum = 0d;
        var sqrsum = 0d;
        foreach (var item in items)
        {
            sum += item;
            sqrsum += item * item;
        }//for

        var average = sum / count;

        double deviation = 0d;
        for (int i = 0; i < items.Count(); i++)
        {
            deviation += (items[i] - average) * (items[i] - average);
        }
        deviation = deviation / (count - 1);

        var stddev = Math.Sqrt(deviation);
        return stddev;
    }
2
  • Thanks, but I want to have a single iteration of items. "Items" can be a very big list. And, when I know a count of items, "items" can be an IEnumerable<> that iterated ones. Apr 30, 2015 at 9:24
  • Actually there was only one miss in your code and that is the calculation of deviation variable(see in my code).
    – captainsac
    Apr 30, 2015 at 9:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.