如何修复StdDev计算中的浮点瑕疵?

时间:2015-04-30 08:55:49

标签: c# .net floating-point floating-accuracy

我尝试用下一个方法计算标准偏差:

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;
}

有时,表达式“sqrsum - count * average * average”小于0,Math.Sqrt返回NaN。例如,在这种情况下:

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

如何在我的代码中修复此案例?我应该使用Math.Abs​​(sqrsum - 计数*平均值*平均值)还是应该绕一些东西?

1 个答案:

答案 0 :(得分:0)

我认为以下代码可以帮助您计算标准偏差。

    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;
    }