使用浮点减法进行圆形连接

时间:2017-06-18 14:53:57

标签: floating-point

舍入不会像我期望的浮点减法那样工作。

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

在第二个参数对齐后,结果应该仍然在两个值之间。在这种情况下,为什么它没有达到均值呢?

1 个答案:

答案 0 :(得分:6)

要理解最终结果,重要的是要记住舍入是IEEE 754算法的最后一步。它完全按照标准化完成,然后舍入。

查看两次计算的高有效性结束时,两个操作数在显式位中都为零。 b中隐含的一位右移三位以匹配指数:

1.000
0.001

添加这些给出1.001,因此指数保持与a相同,并且结果中有一个显式位。

减去它们给出0.111。归一化将此左移一位,以消除前导0,给出1.110。结果中存储了两个显式的一位。

现在看一下低意义的结局。原始减法将在“中间”位置留下一位。由归一化引起的左移将其转换为最低有效存储位,结果是精确的。