平均的哪些实现最准确?

时间:2013-05-03 08:08:02

标签: c++ algorithm floating-accuracy

给出平均函数的两个实现:

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

另一方面,第二个实现似乎理论上效率较低,因为要执行的分割数量(我没有描述任何内容,这是一个盲目猜测)。

那么,这些实现中的一个是否优于另一个?我是否认为第一次实施不太准确?

2 个答案:

答案 0 :(得分:5)

我不会指望第二个更准确。该 元素大小的差异除以 向量的长度,但每个部门介绍一些 额外的不精确。

如果准确性有问题,则应使用第一个步骤 double。即使向量是float,出于内存原因, 函数内的计算应为double

除此之外,对于大量元素,你应该这样做 使用Kahan algorithm,而不是天真地添加 元素。虽然它在循环中添加了许多操作, 它会跟踪错误,并会显着地导致错误 更准确。

编辑:

只是为了它的乐趣,我写了一个小程序,使用了 以下代码生成向量:

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,尽可能准确 得到。使用Kahan算法(随处浮动)给出 相同的结果。

答案 1 :(得分:0)

如果你的总和对于float类型来说不是太大,那么第一个可能更准确,因为除法产生的个别舍入错误可能会累积