关于浮点数的二进制十六进制表示及转换

 

记录一下如何将二进制、十六进制表示的浮点数转换成十进制。...



在开发

Fun-multiplier For WeChat 微信功能加强插件
时,查看了大量的微信反编译代码,其中涉及到浮点数的传值时,会发现其数值好像都很大,比如在32位arm汇编里的如下代码:

movs r2, 0x0
movt r2, 0x41B4
首先需要知道,
movs r2, 0x0
是把r2置为0,
movt r2, 0x41B4
是把r2的高16位置为0x41B4,因此最终r2的值为0x41B40000。如果把它看成一个32位整型,则其值为1102315520,而如果将其看成32位的浮点数,则其值为22.5,现就其二进制的表示方式和转换方法记录如下。

根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:

V = (-1)^S * M * 2^E


其中

  • (-1)^S 表示符号位,当S=0,V为正数,当S=0时,V为负数。
  • M表示有效数字,大于等于1,小于2。
  • 2^E 表示指数位。
因此,22.5的二进制浮点数为
1.01101 * 2^4
,下面以32位浮点数举例如何将0x41B40000转换成22.5这个浮点数。

首先,先将0x41B40000转换成二进制:

4    1    B    4    0    0    0    0

0100 0001 1011 0100 0000 0000 0000 0000
其次,IEEE 754规定,对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。因此,对以上二进制串重新排列:

S E        M
0 10000011 01101000000000000000000
第三,IEEE 754还规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。对于E,E为一个无符号整数(unsigned int)。这意味着,如果E为8位,它的取值范围为0~255;如果E为11位(64位浮点数),它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,E的真实值必须再减去一个中间数,对于8位的E,这个中间数是127。需要注意,如果E为全0,则有效数字M不沿用第二条说的规则前面加个1,而是还原为0.xxxxx的小数,主要目的是为了表示±0,以及接近于0的很小的数字。

因此,对于
0 10000011 01101000000000000000000
,S=0,E=10000011-01111111=00000100(十进制数为4),M=1.01101,则
V=1.01101 * 2^4 = 10110.1
,即为22.5。

因为经常需要将十六进制浮点数转换成十进制,于是便自己用Python个转换的小程序(注意由于是自己用的小程序,故没有对输入进行合法性判断,也没有考虑E全0或者全1的情况) :

query = str(bin(int(raw_input(), 16)))[2:]
[b]if[/b](len(query) < 32):

query = &#39;0&#39; * (32-len(query)) + query
s = 1 [b]if[/b] query[0] == &#39;0&#39; [b]else[/b] -1
e = int(query[1:9], 2) - 127
query = &#39;1&#39; + query[9:]
res, a = 0, 2**e
[b]for[/b] i [b]in[/b] query:
[b]    if[/b](i == &#39;1&#39;):

res += a

a /= 2.0
print(s*res)
如果还不错,可以支持一下我



欢迎关注我的公众号和博客。



点击阅读原文进行留言。


    关注 编程之道


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册