Floating point 使用浮点减法将圆与偶数连用

Floating point 使用浮点减法将圆与偶数连用,floating-point,Floating Point,四舍五入的工作方式与浮点减法不同 IEEE754-2008,4.3.1说“四舍五入即使……如果包含不可表示的无限精确结果的两个最近的浮点数相等接近,则应交付具有偶数最低有效位的浮点数” 英特尔文档称这是默认模式,并对其进行了更明确的定义: 我将首先介绍浮点加法——正如我所期望的那样——以验证我的假设。然后,我将稍微修改我的测试用例,以显示我的理解哪里出了问题 让我们看两个单浮点数,在这里以“binary32”格式表示: S Exponent Significand 0 100000

四舍五入的工作方式与浮点减法不同

IEEE754-2008,4.3.1说“四舍五入即使……如果包含不可表示的无限精确结果的两个最近的浮点数相等接近,则应交付具有偶数最低有效位的浮点数”

英特尔文档称这是默认模式,并对其进行了更明确的定义:

我将首先介绍浮点加法——正如我所期望的那样——以验证我的假设。然后,我将稍微修改我的测试用例,以显示我的理解哪里出了问题

让我们看两个单浮点数,在这里以“binary32”格式表示:

S Exponent       Significand
0 10000010 00000000000000000000001  (0x41000001)
    130

0 01111111 00000000000000000000100  (0x3F800004)
    127
要添加它们,我将指数较小的数字(第二个操作数)的有效位向右移动3位(这里我还添加了隐式前导1):

由于移出值介于两个值(100)之间,因此应四舍五入至偶数值之和:

1.00100000000000000000010
在二进制中,完整值为:

0 10000010 00100000000000000000010 (0x41100002)
我可以证实这一点:

#include <stdint.h>
#include <stdio.h>

union uval {
   float fval;
   int32_t ival;
};

int main()
{
    union uval a, b, c;
    a.ival = 0x41000001;
    b.ival = 0x3F800004;
    c.fval = a.fval + b.fval;
    printf("%08x\n", c.ival);
}
如果向第一个操作数添加一个:

    a.ival = 0x41000002;
我得到同样的东西。它已四舍五入到平均结果:

./a.out
41100002
到目前为止,一切顺利。但是,如果我使用原始值并通过将符号位设置为1将第二个参数修改为负值:

a.ival = 0x41000001;
b.ival = 0xBF800004;
我得到:

./a.out
40E00001
即:

0 10000001 11000000000000000000001
    129

第二个参数对齐后,结果仍应在两个值之间的中间。在这种情况下,为什么不舍入为偶数?

要理解最终结果,重要的是要记住舍入是IEEE 754算法的最后一步。通过标准化,它看起来很精确,然后四舍五入

查看这两个计算的高意义端,两个操作数的显式位中都有零。
b
中的隐式一位右移三位以匹配指数:

1.000
0.001
将这些值相加得到1.001,因此指数保持与
a
相同,并且结果中有一个明确的一位

减去它们得到0.111。标准化将其左移一位,以去掉前导0,得到1.110。结果中存储两个显式1位


现在看看低端。原始减法将在“中间”位置保留一位。由于标准化而产生的左移位将其转换为最低有效存储位,结果是准确的。

为什么您希望最终结果介于中间而不是完全可表示?因为在对齐第二个操作数时,我将数字“100”移出了第二个操作数(源操作数的指数相差3).您是否考虑过在高显著性端发生的情况以及结果指数的变化?
0 10000001 11000000000000000000001
    129
1.000
0.001