我总是得到错误的结果,而我试图总结大数组。我有以下代码示例的孤立问题(它不是一个大数组的总和,但我相信这是问题)
template <typename T>
void cpu_sum(const unsigned int size, T & od_value) {
od_value = 0;
for (unsigned int i = 0; i < size; i++) {
od_value += 1;
}
}
int main() {
typedef float Data;
const unsigned int size = 800000000;
Data sum;
cpu_sum(size, sum);
cout << setprecision(35) << sum << endl; // prints: 16777216 // ERROR !!!
getchar();
}
操作系统:Windows 8.1 x64主页
IDE: Microsoft Visual Studio 2015
虽然我的结果显然应该是sum == 800000000
,但我仍然会sum == 16777216
。
这对我来说非常奇怪,因为浮动最大值远远高于这个,但看起来sum
变量达到了极限。
我错过了什么?
答案 0 :(得分:4)
这是一个众所周知的问题。渐渐地,你的总和变得如此之大,以至于下一个求和变得与它的epsilon(大约10 ^ -14)相当。那一刻你开始失去精确度。
标准解决方案是改变求和策略:当数组大于100个元素时,将它分成两半并分别对每一半求和。它以递归方式进行,并且倾向于更好地保持精度。
答案 1 :(得分:2)
正如Michael Simbursky所指出的,当尝试对大量有限精度数进行求和时,这是一个众所周知的问题。他提供的解决方案效果很好,效率很高。
对于好奇的读者来说,一个较慢的方法是在计算总和之前对数组进行排序,确保以增加绝对值的顺序添加值。这可以确保最不重要的值在被其他值淹没之前对总和进行贡献。与任何严肃的编程企业相比,这种技术更多地用作示例/说明。
对于严重的科学编程,其中数据的整体大小可能有很大差异,另一个需要注意的算法是Kahan Summation Algorithm,引用的维基百科页面提供了很好的描述。