Hey*_*sch 3 c++ floating-point rounding-error rounding infinity
考虑以下 C++ 代码:
#include <fenv.h>
#include <iostream>
using namespace std;
int main(){
fesetround(FE_TONEAREST);
double a = 0x1.efc7f0001p+376;
double b = -0x1.0fdfdp+961;
double c = a*b;
cout << a << " "<< b << " " << c << endl;
}
Run Code Online (Sandbox Code Playgroud)
我看到的输出是
2.98077e+113 -2.06992e+289 -inf
Run Code Online (Sandbox Code Playgroud)
我不明白为什么c是无穷大。我的理解是,无论最小的非无穷大浮点数是多少,它都应该更接近实际值,a*b因为-inf最小非无穷大浮点数是有限的,并且任何有限数都比负无穷更接近任何其他有限数。为什么这里会输出无穷大呢?
它在 64 位 x86 上运行,并且程序集使用 SSE 指令。它是用 -O0 编译的,并且在 clang 和 gcc 中都会发生。
如果对浮点使用向零舍入模式,则结果是最小有限浮点。我的结论是这个问题与四舍五入有关。
舍入不是这里的主要问题。结果无限大是由于溢出造成的。
\n此答案遵循 IEEE 754-2019 中的规则。1.EFC7F0001 16 \xe2\x80\xa22 376和 \xe2\x88\x921.0FDFD 961 \xe2\x80\xa22 16的实数算术乘积约为 \xe2\x88\x921.07430C8649FEFE8 16 \xe2\ x80\xa22 1335。在正常情况下,如果浮点运算首先生成一个精确到无限精度且范围无界的中间结果,然后对该结果进行舍入,则它会生成结果 \xe2\x80\x9cas,然后舍入该结果\xe2\x80\xa6\xe2\x80\x9d (IEEE 754-2019 4.3)。然而,我们不具备正常的条件。IEEE 754-2019 7.4 说:
\n\n\n当且仅当目标格式\xe2\x80\x99 的最大有限数的大小超出了指数范围无界\xe2\x80 的舍入浮点结果(参见 4)时,才会发出溢出异常信号\xa6
\n
换句话说,如果我们对结果进行四舍五入,就好像我们可以有任何指数一样(因此我们只是对有效数字进行四舍五入),结果将是 \xe2\x88\x921.07430C8649FF+964 16 \xe2\x80\xa22 1338。但其大小超出了double可以表示的最大有限数 \xc2\xb11.FFFFFFFFFFFFF 16 \xe2\x80\xa22 1023。因此,会发出溢出异常信号,并且由于您没有捕获该异常,因此会传递默认结果:
\n\n\xe2\x80\xa6 默认结果由舍入方向属性和中间结果的符号确定,如下所示:
\na) roundTiesToEven 和 roundTiesToAway 将所有溢出携带到 \xe2\x88\x9e 以及中间结果的符号\xe2\x80\xa6
\n