以下代码将为变量输出不同的结果' e'和' f'在x86 32位计算机上,但在x86 64位计算机上的结果相同。为什么?从理论上讲,正在评估相同的表达,但从技术上讲,它不是。
#include <cstdio>
main()
{
double a,b,c,d,e,f;
a=-8988465674311578540726.0;
b=+8988465674311578540726.0;
c=1925283223.0;
d=4294967296.0;
e=(c/d)*(b-a)+a;
printf("%.80f\n",e);
f=c/d;
f*=(b-a);
f+=a;
printf("%.80f\n",f);
}
注意...可以使用&#39; gcc -m32&#39;生成32位x86代码。 ,谢谢@Peter Cordes https://stackoverflow.com/users/224132/peter-cordes
另见
is boost::random::uniform_real_distribution supposed to be the same across processors?
---更新用户Madivad
64 bit output
-930037765265417043968.00000...
-930037765265417043968.00000...
32 bit output
-930037765265416519680.00000...
-930037765265417043968.00000...
&#34;数学正确&#34;输出可以由这个python代码
给出from fractions import Fraction
a=-8988465674311578540726
b=8988465674311578540726
c=1925283223
d=4294967296
print "%.80f" % float(Fraction(c,d)*(b-a)+a)
-930037765265416519680.000...
答案 0 :(得分:10)
FLT_EVAL_METHOD
。
C允许根据FLT_EVAL_METHOD
在更高/更宽的类型中进行中间FP计算。因此,当使用更宽泛的类型并且代码流程不同时,尽管在数学上相同,但可能会出现稍微不同的结果。
除了赋值和强制转换(删除所有额外的范围和精度)之外,具有浮动操作数的运算符产生的值以及通常的算术转换和浮动常量的值将被计算为范围和精度可能更大的格式比所要求的类型。评估格式的使用具有特征 由实现定义的
值FLT_EVAL_METHOD
:-1。不确定的;
0.仅根据类型的范围和精度评估所有操作和常量;
1.评估float类型的操作和常量以及double类型的范围和精度,将long double操作和常量计算为long double类型的范围和精度;
2.评估所有操作和常数的范围和精度 长双色。
C11dr§5.2.4.2.29
[编辑]
@Pascal Cuoq对FLT_EVAL_METHOD
的真实性有一个有用的评论。在任何情况下,沿各种代码路径优化的FP代码可能呈现不同的结果。当FLT_EVAL_METHOD != 0
或编译器严格遵守时,可能会发生这种情况。
关于帖子的详细信息:X*Y + Z
和*
的2个操作中完成的操作+
可以与fma()
进行对比“{x} y )+ z,舍入为一个三元运算:根据当前的舍入模式,它们将值(如同)计算为无限精度,并将结果格式舍入一次。 C11§7.12.13.12。结果差异的另一个候选人可能是由于申请“fma”到行e=(c/d)*(b-a)+a;