IEEE 754-2008浮点算法标准和ISO / IEC 10967语言独立算法(LIA)标准的第1部分回答了为什么会这样。
IEEE 754§6.3符号位
当输入或结果为NaN时,此标准不解释NaN的符号。但是请注意,对位字符串(copy,negate,abs,copySign)的操作有时会基于NaN操作数的符号位来指定NaN结果的符号位。逻辑谓词totalOrder也受NaN操作数的符号位影响。对于所有其他操作,即使只有一个输入NaN或无效操作产生了NaN,该标准也未指定NaN结果的符号位。
当输入或结果都不为NaN时,乘积或商的符号为操作数符号的异或;否则为0。和的符号或被视为和x +(-y)的差x-y最多与加数的符号之一不同;转换结果的符号,量化操作,roundTo-Integral操作和roundToIntegralExact(请参阅5.3.1)是第一个或唯一操作数的符号。即使操作数或结果为零或无限,这些规则也应适用。
当两个具有相反符号的操作数之和(或两个具有相似符号的操作数之差)正好为零时,除roundTowardNegative之外,所有舍入方向属性的该和(或差异)的符号应为+0;在该属性下,精确零和(或差)的符号应为-0。但是,即使x为零,x + x = x −(-x)仍保留与x相同的符号。
加法案
在默认的四舍五入模式下 (舍入为最近,从领带为偶数),我们看到x+0.0
产生了x
,除了x
是时-0.0
:在这种情况下,我们有两个具有相反符号的操作数之和,其和为零,以及§6.3段落此加法产生的3条规则+0.0
。
由于与原始位+0.0
不完全相同,并且这是可能作为输入出现的合法值,因此编译器必须放入将潜在的负零转换为的代码。-0.0
-0.0
+0.0
摘要:在默认舍入模式下x+0.0
,如果x
- 不是
-0.0
,那么x
它本身就是一个可接受的输出值。
- 是
-0.0
,那么输出值必须是 +0.0
,与位不一致-0.0
。
乘法的情况
在默认的舍入模式下,不会发生此类问题x*1.0
。如果x
:
减法的情况
在默认的舍入模式下,减法x-0.0
也是空操作,因为它等效于x + (-0.0)
。如果x
是
- 是
NaN
,则§6.3p1和§6.2.3的应用方式与加法和乘法非常相似。
- 是
+/- infinity
,则结果具有+/- infinity
相同的符号。
x-0.0 == x
总是(次)正常数。
- 是
-0.0
,则根据第6.3p2节,我们有一个[...]的符号或差x-y的和x +(-y),最多与加数的符号之一不同。 ”。这迫使我们分配-0.0
作为的结果(-0.0) + (-0.0)
,因为-0.0
从不同的标志没有加数,而+0.0
在不同的标志2加数,违反本条款。
- 是
+0.0
,然后减少到(+0.0) + (-0.0)
上文“加法案例”中所考虑的加法案例,第 6.3p3节规定了加法案例+0.0
。
由于在所有情况下,输入值都是合法的输出,因此可以考虑x-0.0
不操作和x == x-0.0
重言式。
改变价值的优化
IEEE 754-2008标准具有以下有趣的引用:
IEEE 754§10.4字面意义和价值改变优化
[...]
除其他外,以下更改值的转换保留了源代码的字面含义:
- 当x不为零且不是NaN信号时,应用标识属性0 + x,并且结果与x具有相同的指数。
- 当x不是信号NaN且结果具有与x相同的指数时,应用标识属性1×x。
- 更改安静的NaN的有效载荷或符号位。
- [...]
由于所有NaN和无穷的所有共享相同的指数,以及正确舍入的结果x+0.0
,并x*1.0
为有限x
具有完全相同的量值相同x
,其指数是一样的。
声纳
信号NaN是浮点陷阱值;它们是特殊的NaN值,将其用作浮点操作数会导致无效的操作异常(SIGFPE)。如果优化了触发异常的循环,则软件将不再具有相同的行为。
但是,正如user2357112 在注释中指出的那样,C11标准显式地使信号NaNs(sNaN
)的行为未定义,因此允许编译器假定它们未发生,因此也不会发生它们引发的异常。C ++ 11标准省略了描述NaN信号传递行为的描述,因此也未定义。
舍入模式
在备用舍入模式下,允许的优化可能会更改。例如,在“取整到负无穷大”模式下,优化x+0.0 -> x
成为可能,但x-0.0 -> x
被禁止。
为了防止GCC采用默认的舍入模式和行为,-frounding-math
可以将实验标记传递给GCC。
结论
Clang和GCC甚至在-O3
仍保持IEEE-754兼容性。这意味着它必须遵守IEEE-754标准的上述规则。x+0.0
是没有被比特相同,以x
对所有x
的那些规则,但x*1.0
可以被选择成这样:即,当我们
- 请遵守建议,即
x
当NaN时不传递有效载荷。
- 将NaN结果的正负号保持不变
* 1.0
。
- 服从期间的商/产品的符号位的顺序进行XOR,当
x
是不为NaN。
要启用IEEE-754-unsafe优化(x+0.0) -> x
,-ffast-math
需要将标志传递给Clang或GCC。