浮点舍入不正确

时间:2013-12-06 23:38:04

标签: c++ floating-point floating-accuracy floating-point-precision

在gcc 4.7.3上,我的fegetround()函数返回FE_TONEAREST。根据{{​​3}},这意味着从零开始四舍五入。本质上,它意味着在乘法后调整尾数的精度时保存移出的最后一位(因为它将是它应该的两倍)。然后,将保存的位添加到最终的尾数结果中。

例如,浮点乘法给出以下结果:

0x38b7aad5 * 0x38b7aad5 = 0x3203c5af

乘法后的尾数是

  1011 0111 1010 1010 1101 0101
x 1011 0111 1010 1010 1101 0101
-------------------------------
1[000 0011 1100 0101 1010 1110] [1]000 0101 1001 0101 0011 1001

[23'b]集保存有效数字,而[1'b]集保留最后一位向外移位。请注意,结果的尾数是

[000 0011 1100 0101 1010 1111]

最后一位切换为1,因为由于舍入模式,[1'b1]集已添加到拼接的尾数([23'b]集)中。

这是一个让我感到困惑的例子,因为它让我觉得硬件没有正确舍入。

0x20922800 * 0x20922800 = 0x1a6e34c (check this on your machine)

  1010 0110 1110 0011 0100 1101
x 1010 0110 1110 0011 0100 1101
-------------------------------
01[01 0011 0111 0001 1010 0110 0][1]00 0000 0000 0000 0000 0000

Final Mantissas:       
Their Result:      01 0011 0111 0001 1010 0110 0
Correct Result(?): 01 0011 0111 0001 1010 0110 1

我整天都在处理二进制文件,所以我可能会错过这里简单的东西。给定的舍入模式,哪个答案是正确的?

2 个答案:

答案 0 :(得分:6)

当舍入到最近时,IEEE指定关系为偶数。 0是偶数,1是奇数,所以英特尔是正确的。

答案 1 :(得分:2)

首先舍入到最近的在这里缺少一个细节。 舍入到最近(偶数)

  

IEEE 754标准(第4.3.1节)引用:

     

roundTiesToEven,最接近无限精确结果的浮点数应为   交付使用;如果两个最接近的浮点数无限代表包含无法代表的数字   精确的结果同样接近,具有最低有效数字的结果将被传递

在第一个示例中,您计算​​的平方(8.75794e-5)(如果表示为32位浮点数)具有以下十六进制模式:0x38b7aad5

(8.75794e-5)的所有24个有效位位是:

0xb7aad5 = 1.0110111_10101010_11010101

现在,你得到了:

1.0000011_11000101_10101110_10000101_10010101_00111001

值得注意的是,在99%的情况下,您的计算将在FPU(可能是x87)上执行,它以80位浮点格式运行。

  

英特尔®64和IA-32架构软件开发人员手册

     

(使用X87 FPU进行编程):

     

当浮点,整数或压缩BCD整数时   值从内存加载到任何x87 FPU数据寄存器中,值为   自动转换为双扩展精度浮点格式(如果它们   不是那种格式。)

现在您想将结果存储在32位浮点数中:

1.[0000011_11000101_10101110]10000101_10010101_00111001

这里是舍入模式很重要的地方。 IEEE 754定义了其中的4个,但让我们关注默认的(舍入到最近(偶数)),我们在这里讨论这个。

既然你的FPU有结果(整个 - 我们有80位格式的64个有效位),它必须执行舍入以适应32位(24个有效位和24位)内的数字。需要显式存储的所有23位都放在上面的括号内。

现在四舍五入到最近与甚至在这种特殊情况下无关,因为括号右边的位是中途之间:

1.[0000011_11000101_10101111]
and
1.[0000011_11000101_10101110]

但他们离

更近了
1.[0000011_11000101_10101111]

这就是你的结果有效数为0x3203C5AF的原因。

现在有问题的结果是平方2.4759832E-19 0x20922800

2.4759832E-19的24个有效位是:

0x922800 = 1.0010010_00101000_0000_0000

和平方:

1.[0100110_11100011_01001100]10000000_00000000_0000000

这里甚至部分非常重要。现在你的价值恰好位于中间:

1.[0100110_11100011_01001101]
and
1.[0100110_11100011_01001100]

超过2个值据说可以包含您的价值。从他们那里你现在需要选择一个(后者因为lsb = 0)。

现在您知道为什么结果的24位是0xA6E34C最近的偶数)而不是0xA6E34D(最近但奇数)