IEEE 浮点标准的 (+0)+(-0) 是什么?

What is (+0)+(-0) by IEEE floating point standard?

IEEE 浮点标准明确定义了对任何浮点数的任何算术运算,我说得对吗?如果是,出于好奇,(+0)+(-0) 是什么?有没有办法在实践中用 C++ 或其他常用编程语言检查这些事情?

根据 IEEE 浮点标准,答案是 +0。

我的回答涉及 IEEE 754:2008,这是标准的当前版本。

在 IEEE 754:2008 标准中:

第 4.3 节介绍了在执行算术运算时为了使位适合尾数而对值进行舍入。

4.3 Rounding-direction attributes

Rounding takes a number regarded as infinitely precise and, if necessary, modifies it to fit in the destination’s format while signaling the inexact exception, underflow, or overflow when appropriate (see 7). Except where stated otherwise, every operation shall be performed as if it first produced an intermediate result correct to infinite precision and with unbounded range, and then rounded that result according to one of the attributes in this clause.

The rounding-direction attribute affects all computational operations that might be inexact. Inexact numeric floating-point results always have the same sign as the unrounded result.

The rounding-direction attribute affects the signs of exact zero sums (see 6.3), and also affects the thresholds beyond which overflow and underflow are signaled.


第 6.3 节规定了用特殊值(NaN、无穷大、+0、-0)进行算术运算时符号位的值。

6.3 The sign bit

When the sum of two operands with opposite signs (or the difference of two operands with like signs) is exactly zero, the sign of that sum (or difference) shall be +0 in all rounding-direction attributes except roundTowardNegative; under that attribute, the sign of an exact zero sum (or difference) shall be −0.

However, x + x = x − (−x) retains the same sign as x even when x is zero.

(强调我的)

换句话说,(+0) + (-0) = +0 除非 rounding moderoundTowardNegative,在这种情况下它是 (+0) + (-0) = -0.




在 C# 上下文中:

根据§7.7.4 of the C# Language Specification(强调我的):

  • Floating-point addition:

float operator +(float x, float y);

double operator +(double x, double y);

The sum is computed according to the rules of IEEE 754 arithmetic. The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. In the table, x and y are nonzero finite values, and z is the result of x + y. If x and y have the same magnitude but opposite signs, z is positive zero. If x + y is too large to represent in the destination type, z is an infinity with the same sign as x + y.

 +  •  x      +0     -0     +∞     -∞    NaN
•••••••••••••••••••••••••••••••••••••••••••••
y   •  z      y      y      +∞     -∞    NaN
+0  •  x      +0     +0     +∞     -∞    NaN
-0  •  x      +0     -0     +∞     -∞    NaN
+∞  •  +∞     +∞     +∞     +∞     NaN   NaN
-∞  •  -∞     -∞     -∞     NaN    -∞    NaN
NaN •  NaN    NaN    NaN    NaN    NaN   NaN

(+0) + (-0) 在 C# 中:

换句话说,根据规范,如果两者 都为负零,则添加两个零只会产生负零。因此,原题的答案

What is (+0)+(-0) by IEEE floating point standard?

是+0。


C# 中的舍入模式:

如果有人对更改 C# 中的舍入模式感兴趣,请在“Is there an C# equivalent of c++ fesetround() function?", Hans Passant 状态:

Never tinker with the FPU control word in C#. It is the worst possible global variable you can imagine. With the standard misery that globals cause, your changes cannot last and will arbitrarily disappear. The internal exception handling code in the CLR resets it when it processes an exception.

有符号零的 IEEE 754 算术规则声明 +0.0 + -0.0 取决于舍入模式。在默认舍入模式下,它将是 +0.0。当向-∞四舍五入时,它将是-0.0.

您可以像这样在 C++ 中检查:

#include <iostream>

int main() {
    std::cout << "+0.0 + +0.0 == " << +0.0 + +0.0 << std::endl;
    std::cout << "+0.0 + -0.0 == " << +0.0 + -0.0 << std::endl;
    std::cout << "-0.0 + +0.0 == " << -0.0 + +0.0 << std::endl;
    std::cout << "-0.0 + -0.0 == " << -0.0 + -0.0 << std::endl;
    return 0;
}

Output:

+0.0 + +0.0 == 0
+0.0 + -0.0 == 0
-0.0 + +0.0 == 0
-0.0 + -0.0 == -0

采用标准舍入模式(如果您不知道什么是舍入模式以及如何更改它,则可以使用该模式)。

如果精确结果不为零但小到四舍五入为零,则如果精确结果大于 0,则结​​果为 +0,如果精确结果小于 0,则结​​果为 -0。这这种情况只会发生在乘法和除法上,不会发生在加法和减法上。

有几种情况精确结果为零。在这种情况下,在以下情况下结果为 -0:添加 (-0) + (-0)。减去 (-0) - (+0)。乘以一个因子为零,另一个因子具有相反的符号(包括 (+0) * (-0)。将一个零除以一个非零数,包括相反符号的无穷大。在所有其他情况下,结果是+0。

此规则的一个不幸的副作用是 x + 0.0 并不总是与 x 相同(当 x 为 -0 时则不同)。另一方面,x - 0.0 始终与 x 相同。此外,x * 0.0 可能是 +0 或 -0,具体取决于 x。这会阻止精确支持 IEE754 的编译器进行某些优化,或者使它们更加困难。