显然相同的数学表达式具有不同的输出
Posted
技术标签:
【中文标题】显然相同的数学表达式具有不同的输出【英文标题】:Apparently identical math expressions with different output 【发布时间】:2015-11-19 04:00:57 【问题描述】:以下代码将在 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);
注意...可以使用 'gcc -m32' 生成 32 位 x86 代码,感谢@Peter Cordes https://***.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...
这个python代码可以给出“数学上正确”的输出
from fractions import Fraction
a=-8988465674311578540726
b=8988465674311578540726
c=1925283223
d=4294967296
print "%.80f" % float(Fraction(c,d)*(b-a)+a)
-930037765265416519680.000...
【问题讨论】:
出于好奇,你得到了什么结果? "以下代码将在 32 位机器上为变量 'e' 和 'f' 输出不同的结果,但在 64 位机器上输出相同的结果。" -- 我会为特定对机器/机器类购买它,但作为一般规则,您的断言不能得到支持。 @don:我刚刚解决了你的 RNG 问题,答案相同:x87 FP 具有 80 位内部精度,而 SSE FP 具有 64 位精度,即使是临时性的。我希望你先问这个问题:P 我本可以节省一个小时涉足 Boost mersenne PRNG 的整数部分,寻找在 32 位和 64 位模式下运行时的差异。 另外,-m32
制作 32 位二进制文件不会“模拟”32 位机器。它确实可以生成可以在 32 位系统上运行的 32 位二进制文件。这就是为什么您需要单独的库包来支持它的原因。现代 64 位 x86 系统安装了两组库,并且可以透明地运行 i386 和 amd64 二进制文件。 (这被称为“多架构”支持,在 Linux 发行版最初移植到 amd64 之后几年才真正稳定下来。但现在只是假设,Windows 也是如此:大多数库的 32 位和 64 位版本。)
@PeterCordes 完成注释,您应该注意 32 位代码可以使用 x87 指令,但 64 位代码必须使用 SSE。
【参考方案1】:
FLT_EVAL_METHOD
.
C 允许在更高/更宽的类型上进行中间 FP 计算,具体取决于 FLT_EVAL_METHOD
。因此,当使用更广泛的类型并且代码流不同时,虽然在数学上相等,但可能会出现稍微不同的结果。
除了赋值和强制转换(删除所有额外的范围和精度)之外,由具有浮动操作数的运算符产生的值和经过通常算术转换的值和浮动常量的值被评估为范围和精度可能更大的格式比类型要求的多。评估格式的使用特点 通过
FLT_EVAL_METHOD
的实现定义值:-1。不确定; 0. 仅根据类型的范围和精度评估所有操作和常量; 1. 将 float 和 double 类型的运算和常量计算为 double 类型的范围和精度,将 long double 运算和常数计算为 long double 类型的范围和精度; 2. 评估所有操作和常数的范围和精度 长双精度型。 C11dr §5.2.4.2.2 9
[编辑]
@Pascal Cuoq 对FLT_EVAL_METHOD
的真实性发表了有用的评论。在任何情况下,沿着各种代码路径进行不同优化的 FP 代码可能会呈现不同的结果。当FLT_EVAL_METHOD != 0
或编译器不严格符合时,可能会发生这种情况。
关于帖子的一个细节:X*Y + Z
在*
和+
的两个操作中完成的操作可以与fma()
进行对比,后者“计算 (x × y) + z,四舍五入为一个三进制操作:他们根据当前的舍入模式将值(好像)计算为无限精度并舍入一次结果格式。” C11 §7.12.13.1 2. 结果差异的另一个候选可能是由于应用程序“fma”到行e=(c/d)*(b-a)+a;
【讨论】:
谢谢。欣赏知识。以上是关于显然相同的数学表达式具有不同的输出的主要内容,如果未能解决你的问题,请参考以下文章
相同的正则表达式在 Java 和 JavaScript 中具有不同的结果 [重复]
使用 SAX 解析器,如何解析具有相同名称标签但元素不同的 xml 文件?