我现在正在开发一个在WIN32和WIN64上需要一致结果的程序。我发现的一个难点是这些平台上的双数组值的总和可能导致不一致的结果。以我的代码片段为例:
double sum=0;
std::vector<double>::iterator itW = weighting.begin();
for(std::vector<double>::iterator it = x_array.begin(); it<x_array.end(); it++,itW++)
sum += (*it)*(*it)*(*itW);
在上面的代码片段中,计算加权平方值数组求和。 x_array
值如下所示:
[size] 982 long
[capacity] 982 long
[0] 202.00000000000000 double
[1] 202.00000000000000 double
[2] 202.00000000000000 double
[3] 202.00000000000000 double
[4] 201.00000000000000 double
[5] 201.00000000000000 double
[6] 201.00000000000000 double
[7] 201.00000000000000 double
而weighting
数组看起来像:
[size] 982 long
[capacity] 982 long
[0] 3.8144169965399290e-015 double
[1] 1.0367629020002889e-014 double
[2] 2.8179334245287864e-014 double
[3] 7.6591752750373270e-014 double
[4] 2.0526158725409399e-013 double
[5] 5.5790334162148110e-013 double
[6] 1.5163876629635047e-012 double
[7] 4.1215590100336753e-012 double
我仔细检查并在两个平台上查看x_array
和weighing
具有相同的值。但是,总和不同,在WIN32上总和是575994.17931926867,而在WIN64上总和是575994.17931926856。有什么结果不一致的想法吗?
修改 (1)我正在使用Visual Studio 2010进行编译。 (2)/ fp精确和严格都使用,但它不会改变结果。
答案 0 :(得分:1)
我注意到在64位编译中,MSVC编译器更喜欢使用SSE指令,大概是为了通过SIMD获得速度。在32位编译中,它使用较旧的集成x87 FPU指令。
x87浮点单元使用扩展精度的80位浮点寄存器。根据编译器优化设置,编译器会将中间累加结果(您的变量和)存储在80位精度寄存器中。使用额外的16位精度,因为乘以两个双精度数会在截断之前产生128位精度数。
SSE寄存器是64位IEEE双精度浮点寄存器。因此,您在第16个十进制数字中失去了一点累积精度 - 这是您希望FP截断误差出现在正数的任何简单乘积中的地方,具有双精度。
有关详细信息,请参阅"What Every Computer Scientist Should Know About Floating-Point Arithmetic" Goldberg 1991 ACM.