繁体   English   中英

平均值的哪种实现最准确?

[英]What implementation of average is the most accurate?

给定平均值函数的这两个实现:

float average(const vector<float>& seq)
{
  float sum = 0.0f;

  for (auto&& value : seq)
  {
    sum += value;
  }

  return sum / seq.size();
}

和:

float average(const vector<float>& seq)
{
  float avg = 0.0f;

  for (auto&& value : seq)
  {
    avg += value / seq.size();
  }

  return avg;
}

为了说明我的问题,假设我们在输入数据上有巨大的差异,如下所示:

1.0f, 0.0f, 0.0f, 0.0f, 1000000.0f

我的猜测是,在第一次执行, sum可成长“太多”和松散的最低显著数字,是1000000.0f而不是1000001.0f在和循环结束。

另一方面,由于要执行的除法次数,第二种实现在理论上似乎效率较低(我没有介绍任何内容,这是一个盲目的猜测)。

那么,这些实现中的一种优于另一种吗? 我是真的第一种实现方式不太准确吗?

我不会指望第二个更加准确。 元素大小的差异除以矢量的长度,但是每次除法都会引入一些其他的不精确性。

如果精度是一个问题, 第一步应该是使用double 即使向量为float ,出于内存原因,函数内的计算也应为double

除此之外,对于大量元素,您可能应该使用Kahan算法 ,而不是天真的添加元素。 尽管它在循环中添加了许多操作,但它会跟踪错误,并会显着提高准确性。

编辑:

只是为了好玩,我编写了一个小程序,使用以下代码生成矢量:

std::vector<float> v;
v.push_back( 10000000.0f );
for ( int count = 10000000; count > 0; -- count ) {
    v.push_back( 0.1f );
}

平均值的结果应为1.0999999(实际上是1.1)。 使用原始过帐中的任何一种算法,结果均为0.999999881:10%的误差。 但是,只要在第一个算法中将sum更改为double类型,就会得到1.0999999 ,与您获得的精度1.0999999 使用Kahan算法(到处都有float)会得到相同的结果。

如果您的总和对于float类型来说不太大,则第一个精度可能会更高,因为除法产生的单个舍入错误可能会累积

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM