[英]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.