在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
我整天都在处理二进制文件,所以我可能会错过这里简单的东西。给定的舍入模式,哪个答案是正确的?
答案 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
(最近但奇数)