浮点乘法即使四舍五入到最接近也会产生无穷大

Floating point multiplication results in infinity even though rounding to nearest

提问人:Heygard Flisch 提问时间:2/1/2023 最后编辑:Heygard Flisch 更新时间:2/1/2023 访问量:343

问:

请考虑以下 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;
}

我看到的输出是

2.98077e+113 -2.06992e+289 -inf

我不明白为什么是无穷大。我的理解是,无论最小的非无穷浮点数是多少,它都应该更接近 than 的实际值,因为最小非无穷浮点数是有限的,任何有限数都比负无穷大更接近任何其他有限数。为什么这里输出无穷大?ca*b-inf

这是在 64 位 x86 上运行的,程序集使用 SSE 指令。它是用 -O0 编译的,并且与 clang 和 gcc 一起发生。

如果对浮点使用趋零舍入模式,则结果是最小有限浮点数。我的结论是,这个问题与四舍五入有关。

C++ 浮点 无穷大 舍入误差

评论

0赞 tadman 2/1/2023
这些数字似乎确实超出了合理处理的极限。double
0赞 tadman 2/1/2023
检查不同浮点类型的可用范围。也许你需要一个 128 位浮点数,或者用 C++ 的话说。long double
0赞 chtz 2/1/2023
我认为舍入和溢出行为是有区别的(虽然我不太了解标准......
1赞 Heygard Flisch 2/1/2023
@chtz当我将浮点放入四舍五入的零模式时,问题就消失了。我得出的结论是,这与四舍五入有关
1赞 Adrian Mole 2/1/2023
我认为您将数学/现实世界的无穷大概念与称为“无穷大”的 IEEE-754/计算机浮点值混淆了。它是一种表示;而已。

答:

1赞 Adrian Mole 2/1/2023 #1

您注意到的行为(使用舍入模式时)符合 IEEE-754(或等效的 ISO/IEC/IEEE 60559:2011)标准。(您的示例表明您的平台使用 IEEE-754 表示形式,就像现在许多(如果不是大多数)平台一样。FE_TONEAREST

来自此维基百科页面的脚注 #18,其中引用了 IEEE-754 §4.3.1,处理“舍入到最接近”模式:

在以下两个舍入方向属性中,一个无限 量级至少为 bemax(b-1/2b(1-p) 的精确结果应四舍五入为 (无穷大),符号没有变化。

您的计算结果的“无限精确”结果确实大于指定值,因此舍入符合标准。a * b


我找不到类似的 IEEE-754 对“四舍五入到零”模式的引用,但这个 GNU libc 手册是这样说的:

向零四舍五入。
所有结果均四舍五入到最大值 其大小小于结果的可表示值。 换句话说,如果结果为负数,则四舍五入;如果是 正数,则向下舍入。

因此,同样,在使用该模式时,四舍五入是适当/一致的。-DBL_MAX

评论

0赞 Heygard Flisch 2/1/2023
谢谢,似乎“四舍五入到最接近”根本没有定义为总是四舍五入到最接近。
2赞 Eric Postpischil 2/1/2023
@HeygardFlisch:根据 IEEE 754-2019 4.3,四舍五入到最接近定义为始终四舍五入到最接近。结果不是由四舍五入引起的;它是由溢出异常的默认结果引起的。换句话说,该操作没有“四舍五入到最接近”以获得无穷大。它四舍五入到最接近,确定不适合该格式,生成溢出异常,并且由于溢出异常被屏蔽(不生成中断/陷阱),因此提供了默认结果。
5赞 Eric Postpischil 2/1/2023 #2

四舍五入不是这里的主要问题。无限的结果是由溢出引起的。

此答案遵循 IEEE 754-2019 中的规则。1.EFC7F000116•2376 和 −1.0FDFD961•216 的实数算术乘积约为 −1.07430C8649FEFE816•21335。在正常情况下,浮点运算会产生一个结果,“就好像它首先产生了一个精确到无限精度且范围无限的中间结果,然后将该结果四舍五入......”(IEEE 754-2019 4.3)。但是,我们没有正常条件。IEEE 754-2019 7.4说道:

当且仅当目标格式的最大有限数在量级上超过四舍五入浮点结果(参见 4)时,才会发出溢出异常信号,前提是指数范围是无界的......

换句话说,如果我们将结果四舍五入,就好像我们可以有任何指数一样(所以我们只是对有效数四舍五入),结果将是 −1.07430C8649FF+96416•21338。但其幅度超过了可以表示的最大有限数,±1.FFFFFFFFFFFFF16•21023。因此,会发出溢出异常信号,并且由于您未捕获异常,因此会传递默认结果:double

...默认结果应由舍入方向属性和中间结果的符号确定,如下所示:

a) roundTiesToEven 和 roundTiesToAway 将所有溢出带到 ∞,并带有中间结果的标志...