什么实现平均是最准确的
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
可能增长"太多"并丢失最低有效数字,并且在sum循环结束时成为1000000.0f
而不是1000001.0f
。
另一方面,第二个实现在理论上似乎效率较低,因为要执行的除法的数量(我没有分析任何东西,这是一个盲目的猜测)。
那么,这些实现中的一个比另一个更好吗?我是不是说第一个实现不太准确?
我不指望第二个更准确。的元素大小的差异除以向量的长度,但每次除法都会引入一些额外的不精确。
如果精度有问题,应该使用第一步double
。即使向量是float
,出于内存原因,函数内的计算应该是double
.
除此之外,对于大量元素,您可能应该使用Kahan算法,而不仅仅是naïvely添加元素。虽然它在循环中增加了一些操作,它跟踪错误,并将导致显著更多的准确性。
编辑:
只是为了好玩,我写了一个小程序,使用下面的代码生成向量:
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算法(到处都是float)给出
如果您的总和对于类型float
不是太大,则第一个可能更准确,因为除法产生的单个四舍五入错误可能会累积
相关文章:
- 实现无开销push_back的最佳方法是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 什么是现实中的"endl"(或任何输出操纵器)?它是如何实现的,它如何与操作员<<一起工
- cv::Normalise() 中的 L2_NORM 和 NORM_MINMAX 实现有什么区别?
- "in-situ without memory allocation" 字符串的愚蠢实现意味着什么?
- 私有在函数定义/实现的返回值范围内是什么意思 (c++)?
- 在 c++ 或 python 中生成一个体面的视差图以在 Raspberry Pi 上实现的最佳方法(算法或函数)是什么
- 在C++中将内部类实现为具有名称空间的独立类有什么好处
- 在 C++17 中实现迭代器和const_iterator的正确方法是什么?
- 它叫什么以及如何实现此行为?
- 十进制到二进制的实现不能完全适用于我大学的检查器。问题或提示可能是什么
- 不实现父类的虚拟方法有什么风险
- const_forward在C++中的可选实现中做什么?
- 在这种情况下,有什么正确的方法可以实现锁定吗?
- 实现此自定义priority_queue的正确方法是什么
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- 我需要一个像堆栈一样的数据结构,但具有随机访问,但是,我应该实现什么
- 这C++代码试图实现什么
- 在linux中调用bg时应该实现什么状态