舍入不会像我期望的浮点减法那样工作。
IEEE754-2008,4.3.1表示" roundTiesToEven ...如果包含无法代表的无限精确结果的两个最近的浮点数同样接近,那么具有偶数最低位数的那个将被传递&#34 ;
英特尔文档称这是默认模式并更明确地定义:
https://software.intel.com/en-us/node/503710
我首先要完成浮点加法 - 这正如我所期望的那样 - 来验证我的假设。然后,我会稍微修改我的测试用例,以显示我的理解中断的地方。
让我们取两个单一的浮点数,在这里用二进制32'表示。格式:
S Exponent Significand
0 10000010 00000000000000000000001 (0x41000001)
130
0 01111111 00000000000000000000100 (0x3F800004)
127
要添加它们,我将数字的有效位数用较小的指数(第二个操作数)移动到右边的3个位置(我还在这里添加了隐含的前导1):
1.00000000000000000000001
+ 0.00100000000000000000000 100
----------------------------
1.00100000000000000000001
因为移出的值在两者之间的中间位置(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.out
41100002
如果我在第一个操作数中添加一个:
a.ival = 0x41000002;
我得到同样的东西。它将 down 舍入到偶数结果:
./a.out
41100002
到目前为止,这么好。但是,如果我使用原始值并通过将符号位设置为1来修改第二个参数为负:
a.ival = 0x41000001;
b.ival = 0xBF800004;
我明白了:
./a.out
40E00001
这是:
0 10000001 11000000000000000000001
129
在第二个参数对齐后,结果应该仍然在两个值之间。在这种情况下,为什么它没有达到均值呢?
答案 0 :(得分:6)
要理解最终结果,重要的是要记住舍入是IEEE 754算法的最后一步。它完全按照标准化完成,然后舍入。
查看两次计算的高有效性结束时,两个操作数在显式位中都为零。 b
中隐含的一位右移三位以匹配指数:
1.000
0.001
添加这些给出1.001,因此指数保持与a
相同,并且结果中有一个显式位。
减去它们给出0.111。归一化将此左移一位,以消除前导0,给出1.110。结果中存储了两个显式的一位。
现在看一下低意义的结局。原始减法将在“中间”位置留下一位。由归一化引起的左移将其转换为最低有效存储位,结果是精确的。