在python中解析十六进制格式的DEC 32位单精度浮点值

在python中解析十六进制格式的DEC 32位单精度浮点值,python,floating-point,Python,Floating Point,我在python中解析十六进制格式的DEC 32位单精度浮点值时遇到问题,我正在解析的值在十六进制中表示为D44393DB。原始浮点值为~108,从发送单元的显示器读取 格式指定为: 1位符号+8位指数+23位尾数。 字节2包含符号位+指数的7个最高有效位 字节1包含指数的最低有效位+尾数的起始最高有效位 我发现在这两种格式中唯一不同的是指数的偏差,DEC32是128,IEEE-754是127() 使用不会产生预期的结果 /克里斯托弗它肯定是DEC32的值吗?符号位似乎为1,表示此格式为负数。但

我在python中解析十六进制格式的DEC 32位单精度浮点值时遇到问题,我正在解析的值在十六进制中表示为D44393DB。原始浮点值为~108,从发送单元的显示器读取

格式指定为: 1位符号+8位指数+23位尾数。 字节2包含符号位+指数的7个最高有效位 字节1包含指数的最低有效位+尾数的起始最高有效位

我发现在这两种格式中唯一不同的是指数的偏差,DEC32是128,IEEE-754是127()

使用不会产生预期的结果


/克里斯托弗

它肯定是DEC32的值吗?符号位似乎为1,表示此格式为负数。但是,如果忽略这一点,并假设指数偏差为15,尾数上保留0.1因子,则得到的结果非常接近108值:

def decode(x):
    exp = (x>>30) & 0xff
    mantissa = x&((2**24)-1)
    return 0.1 * mantissa * (2**(exp-15))

>>> decode(0xD44393DB)
108.12409668

有没有可能是字节被洗牌了?您描述的位的排列(字节2中的符号位,字节1中的指数LSB)与您链接到的附录O不同。看起来字节1和2被交换了

我假设字节3和4也进行了交换,因此实际的十六进制值是43D4DB93。这在二进制中转换为0100 0011 1101 0100 1101 1011 1001 0011,因此符号位为0,表示正数。指数为10000111(二进制)=135(十进制),表示系数为2^(135-128)=128。最后,尾数是0.1100100 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;
input=0xD44393DB;
重新洗牌=((输入&0x00FF00FF00)>>8)|((输入&0x00FF00FF)>31;
指数=((重组&0x7F800000)>>23)-128;
尾数=浮动((重新调整&0x007FFFFF)| 0x00800000)/2**24;
结果=(-1)**符号位*尾数*2**指数;
这将产生
结果=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。通过d定义,这等于
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(二进制)的值,因此我们可以通过除以
(reshuffed&0x007fff)找到尾数| 0x00800000
2^24。

从我的“微型计算机和存储器”(1981年12月)副本中,您对这两种格式之间的差异是正确的。DEC尾数标准化为
0.5,在RHS的“相关”下找到:


其中一个参考有助于理解“有线”(奇怪?)字节2字节1符号。

我认为尾数的表示方式也不同(IEEE格式添加了隐式0.5).我家里有一本LSI-11/02手册-如果我今晚发现了什么,我会发布一个答案。符号位必须在一个结束字节中,字节2不能在结束处,无论你是算1023还是1234。哪个字节先传输,D4还是DB?更好的是,告诉我们每个字节的传输顺序。你真的只有一个已知值吗?received顺序是B1B2B3B4或实际十六进制:D44393DB要分析的顺序是B2B1B4B3,在本例中是:43D4DB93,符号位是B2的MSB。偏差不太可能是15。0.1F给出了12月的起始值0.5,而IEEE 1.F给出了起始值1感谢您给出了好的答案,它为我指明了正确的方向!您似乎已在原始十六进制值(43D4DB93)的二进制转换中切换中间字节的顺序,应该是:0100 0011 1101 0100 1101 1011 1001 0011。我不确定你是如何想出尾数的二进制到十进制转换的,所以我试着在维基百科上解释:哪个游戏让我这样做:使用0.1F,其中F=101 0100 1101 1011 1001 0011,使用:0.0+2^-n…,其中n=位位置((2^-1)+(2^-2)+(2^-4)+(2^-6)+(2^-9)+(2^-10)+(2^-12)+(2^-13)+(2^-15)…=0.832466125….*128=~106.5556这是你计算尾数的方式吗?正如你所说,我把十六进制值翻译成二进制时犯了一个错误。而尾数确实是按照你所说的方式计算的。有没有一种从二进制到十进制计算尾数的方法,而不必像“手册”中那样循环每一位上面的计算?@Jitse:像
((reshuffled&0x7f80000)>>23)
这样不需要传播符号位的字段提取被更清晰地编码为
((reshuffled>>23)&0xFF)
…更容易获得正确的掩码,更容易理解,如果用C编写,可能运行得更快(如果较小的掩码可以通过比较大掩码更快的指令完成)。