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
更改为typedouble
,
但是,结果是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 );
}