Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 平均值的哪种实现方式最准确?_C++_Algorithm_Floating Accuracy - Fatal编程技术网

C++ 平均值的哪种实现方式最准确?

C++ 平均值的哪种实现方式最准确?,c++,algorithm,floating-accuracy,C++,Algorithm,Floating Accuracy,给定平均值函数的这两种实现: float average(const vector<float>& seq) { float sum = 0.0f; for (auto&& value : seq) { sum += value; } return sum / seq.size(); } 我的猜测是,在第一个实现中,sum可能增长“太多”并丢失最低有效位,在sum循环的末尾是1000000.0f,而不是1000001.0f 另

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

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

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

  return sum / seq.size();
}
我的猜测是,在第一个实现中,
sum
可能增长“太多”并丢失最低有效位,在sum循环的末尾是
1000000.0f
,而不是
1000001.0f

另一方面,第二个实现在理论上似乎效率较低,这是由于要执行的分区的数量(我没有分析任何内容,这是一个盲目的猜测)


那么,这些实现中的一个比另一个更可取吗?第一个实现的精度较低,这是真的吗?

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

我不认为第二个更准确。这个 元素大小的差异除以 向量的长度,但每个除法都会引入一些 额外的不精确性

如果准确性有问题,第一步应该是使用
double
。即使向量是浮动的,出于内存原因, 函数中的计算应为双精度

除此之外,对于大量元素,您可能应该 使用,而不是简单地添加 元素。虽然它在循环中添加了许多操作, 它跟踪错误,并将导致严重的错误 更准确

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

std::vector<float> v;
v.push_back( 10000000.0f );
for ( int count = 10000000; count > 0; -- count ) {
    v.push_back( 0.1f );
}
std::vector v;
v、 推回(10000000.0f);
对于(int count=10000000;count>0;--count){
v、 推回(0.1f);
}
平均值的结果应为1.099999(实际值) 我是说,1.1)。使用原始文档中的任一算法 发布后,结果为0.99999881:错误为10%。只是 在第一个算法中将
sum
更改为type
double
, 但是,结果是
1.099999
,尽可能精确 收到使用Kahan算法(到处都是浮点)给出
相同的结果。

为什么不在每个
n
迭代中除以一次,而不是在每个迭代中?根据
seq
中的值,您可以计算
n
的近似值。一旦计算了
n
,就可以在外部循环中使用它,并相应地修改代码。这种方法可能还有其他变体。@Nawaz:我相信我完全理解你的意思。你有例子吗?请看我对这个问题的回答:。正如@James建议的那样,它使用了Kahan总结。@PeterWood:谢谢,这正是我想要的。我不太清楚为什么这被否决了,但你能解释一下,这样我就有机会改进吗?(我从不投反对票,查看我的统计数据)非常感谢。我随意添加了@PeterWood answer的链接,该链接给出了算法的实现。我特别喜欢Peter Wood的实现:定义一个KahanAccumulator并使用
std::accumulate
。朴素典雅。
1.0f, 0.0f, 0.0f, 0.0f, 1000000.0f
std::vector<float> v;
v.push_back( 10000000.0f );
for ( int count = 10000000; count > 0; -- count ) {
    v.push_back( 0.1f );
}