【问题标题】:How to fix floating point artifacts in StdDev calculation?如何修复 StdDev 计算中的浮点伪影?
【发布时间】:2015-07-09 21:25:00
【问题描述】:

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

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 - count * average * average) 还是应该四舍五入?

【问题讨论】:

  • 您可以在循环内平方之前从项目中减去平均值,然后在最后取 sum/N 的 sqrt。
  • @folkol 谢谢,但我想要单项迭代。
  • 那么我猜你会遇到这样的数字错误。您始终可以在 sqrt:ing 之前检查负数并返回 0。
  • @folkol 谢谢!可能是另一个“如果”还不错。
  • 不,它可能工作正常 :) (虽然,计算标准的数值方法的约定是在平方之前进行减法......由于您在上面遇到的原因。)

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


【解决方案1】:

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

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

【讨论】:

  • 谢谢,但我想要单次迭代的项目。 “项目”可能是一个非常大的列表。而且,当我知道项目的数量时,“项目”可以是一个迭代的 IEnumerable。
  • 其实你的代码中只有一处遗漏,那就是偏差变量的计算(见我的代码)。
猜你喜欢
  • 2017-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多