在Python中解析十六进制格式的DEC 32位单精度浮点值
我在用Python解析一个十六进制格式的DEC 32位单精度浮点值时遇到了问题,我要解析的值是D44393DB(十六进制)。这个浮点值大约是108,从发送设备的显示屏上读取的。
这个格式是这样的: 1位表示符号 + 8位表示指数 + 23位表示尾数。 第二个字节包含符号位和指数的7个最高有效位。 第一个字节包含指数的最低有效位和尾数的最高有效位。
我发现这两种格式唯一不同的地方是指数的偏移量,DEC32是128,而IEEE-754是127(http://www.irig106.org/docs/106-07/appendixO.pdf)。
使用http://babbage.cs.qc.edu/IEEE-754/32bit.html并没有得到预期的结果。
/Kristofer
4 个回答
在右侧的“相关”部分找到了:上个月的这些回答
其中一个参考资料有助于理解“wired”(奇怪的?)的 byte2 byte1 表示法。
根据我手头的《微型计算机与内存》(DEC,1981年)的资料,你说的两种格式之间的区别是对的。DEC格式的尾数是规范化到 0.5<=f<1
,而IEEE格式的尾数是规范化到 1<=f<2
,这两种格式的最高有效位(MSB)都是隐含的,并没有存储。所以它们的尾数位布局是一样的。Jitse Niesens的假设看起来是合理的,因为D44393DB的值大约是 -0.7639748 乘以 2的40次方(也就是 -8.3999923E11)。
有可能字节顺序被打乱了吧?你描述的比特排列(第二个字节的符号位,第一字节的指数的最低有效位)和你链接的附录O不一样。看起来第一个和第二个字节的位置换了。
我假设第三个和第四个字节也换了位置,所以实际的十六进制值是43D4DB93。这个值转换成二进制是0100 0011 1101 0100 1101 1011 1001 0011,符号位是0,表示这是一个正数。指数是10000111(二进制)= 135(十进制),这表示有一个2的幂次因子2^(135-128) = 128。最后,尾数是0.1101 0100 1101 1011 1001 0011(二进制),根据附录O的说明,前面要加上0.1,这大约等于0.8314(十进制)。所以在我的假设下,你的数字是0.8314 * 128 = 106.4。
补充:一些Python 2的代码可能会更清楚:
input = 0xD44393DB;
reshuffled = ((input & 0xFF00FF00) >> 8) | ((input & 0x00FF00FF) << 8);
signbit = (reshuffled & 0x80000000) >> 31;
exponent = ((reshuffled & 0x7F800000) >> 23) - 128;
mantissa = float((reshuffled & 0x007FFFFF) | 0x00800000) / 2**24;
result = (-1)**signbit * mantissa * 2**exponent;
这段代码的结果是 result = 106.42885589599609
。
这里解释一下计算尾数的那一行。首先,reshuffled & 0x007FFFFF
得到编码尾数的23位:101 0100 1101 1011 1001 0011。然后 ... | 0x00800000
设置了隐藏位,得到1101 0100 1101 1011 1001 0011。现在我们需要计算小数0.1101 0100 1101 1011 1001 0011。根据定义,这等于 1*2^(-1) + 1*2^(-2) + 0*2^(-3) + ... + 1*2^(-23) + 1*2^(-24)
。这也可以写成 (1*2^23 + 1*2^22 + 0*2^21 + ... + 1*2^1 + 1*2^0) / 2^24
。括号里的表达式就是1101 0100 1101 1011 1001 0011(二进制)的值,所以我们可以通过将 (reshuffled & 0x007FFFFF) | 0x00800000
除以2^24来找到尾数。