显然具有不同输出的相同数学表达式

don*_*ght 6 c++ floating-point precision

以下代码将在x86 32位计算机上为变量"e"和"f"输出不同的结果,但在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);
}
Run Code Online (Sandbox Code Playgroud)

注意...使用'gcc -m32'可以生成32位x86代码,谢谢@Peter Cordes /sf/users/15689271/

也可以看看

boost :: random :: uniform_real_distribution应该是跨处理器的相同吗?

---为用户Madivad更新

64 bit output 
-930037765265417043968.00000...
-930037765265417043968.00000...

32 bit output
-930037765265416519680.00000...
-930037765265417043968.00000...
Run Code Online (Sandbox Code Playgroud)

这个python代码可以给出"数学上正确"的输出

from fractions import Fraction
a=-8988465674311578540726
b=8988465674311578540726
c=1925283223
d=4294967296
print "%.80f" % float(Fraction(c,d)*(b-a)+a)

-930037765265416519680.000...
Run Code Online (Sandbox Code Playgroud)

chu*_*ica 10

FLT_EVAL_METHOD.

C允许中间FP计算在更高/更宽的类型下发生,具体取决于FLT_EVAL_METHOD.因此,当使用更宽的类型并且代码流不同时,尽管在数学上相等,但可能会出现略微不同的结果.


除了赋值和强制转换(删除所有额外的范围和精度)之外,具有浮动操作数的运算符产生的值以及通常算术转换和浮动常量的值将被评估为其范围和精度可能大于所需的格式.类型.评估格式的使用以实现定义的值为特征FLT_EVAL_METHOD:

-1.不确定的;
0.仅根据类型的范围和精度评估所有操作和常量;
1.计算float类型的操作和常量以及double类型的范围和精度,将long double操作和常量计算为long double类型的范围和精度;
2.评估long double类型的范围和精度的所有操作和常量.
C11dr§5.2.4.2.29

[编辑]

@Pascal Cuoq对于真实性有一个有用的评论FLT_EVAL_METHOD.在任何情况下,沿各种代码路径优化的FP代码可能呈现不同的结果.当FLT_EVAL_METHOD != 0编译器不严格符合时,可能会发生这种情况.

关于帖子的细节:X*Y + Z在2个操作中完成的操作*然后+可以与fma()"compute(x×y)+ z 进行对比,舍入为一个三元操作:他们计算值(好像)到无限精度和圆形根据当前的舍入模式,一次到结果格式." C11§7.12.13.12.结果差异的另一个候选人可能是由于申请"fma"到该线e=(c/d)*(b-a)+a;