python3如何将字节转换为浮点数?

时间:2016-05-04 11:02:28

标签: python

我想了解python如何将字节转换为浮点数 让我们创建一个只包含一个浮点数23.0的二进制文件:

~> echo 23 > 23.a  
~> a2b < 23.a n1=1 > 23.b

现在让我们编写一个python3代码23.py:

~> cat 23.py  
import struct
f='23.b'                                            
fd=open(f,'rb')                                      # Open the file
value_bytes=fd.read()                                # Read file, 4 bytes in total
                                                     # Output:
print("Bytes =",value_bytes)                         # Bytes = b'\x00\x00\xb8A'
print("Float =",struct.unpack("<f",value_bytes))     # Float = (23.0,)

执行代码:

~> python3.5 23.py  
Bytes = b'\x00\x00\xb8A'  
Float = (23.0,)

所以,我想知道python如何将字节'\ x00 \ x00 \ xb8A'转换为float 23.0?这与DEC-BIN-HEX-ASCII表示有关,但我已经打破了我的大脑试图理解这一点。

DEC = 23  
BIN = 0000 0000 0001 0111  
HEX =    0    0    1    7

我们如何从中获得'\ x00 \ x00 \ xb8A'?反之亦然,'\ x00 \ x00 \ xb8A'如何转换为23.0?
任何人都可以一步一步解释我吗?感谢。

1 个答案:

答案 0 :(得分:3)

这显然是documented in the format table

  

对于'f''d'转换代码,压缩表示使用IEEE 754二进制32(对于'f')或二进制64(对于'd')格式,而不管平台使用的浮点格式。

要理解该格式,请参考IEEE floating point standard;您使用了f代码,因此请查找binary32, or single precision format

此格式由32位组成,分为:

  • 符号位:1位
  • 指数宽度:8位
  • 有效精度:24位(明确存储23位)

将二进制数据视为位,(您将其视为小端,因此我将其反转以匹配维基百科的大端排序):

>>> ('{:08b}' * 4).format(*b'\x00\x00\xb8A'[::-1])
'01000001101110000000000000000000'

我们看到符号为0,指数宽度为131(在2&#39; s补码中,因此减去127为4),有效位数精度或尾数为1.4375(1 + 1/4 + 1/8) + 1/16,每个二进制分数是一个启用位。)

>>> ('{:08b}' * 4).format(*b'\x00\x00\xb8A'[::-1])[:1]  # sign
'0'
>>> ('{:08b}' * 4).format(*b'\x00\x00\xb8A'[::-1])[1:9]  # exponent, signed
'10000011'
>>> int(('{:08b}' * 4).format(*b'\x00\x00\xb8A'[::-1])[1:9], 2) - 127  # exponent, signed
4
>>> ('{:08b}' * 4).format(*b'\x00\x00\xb8A'[::-1])[9:]  # mantissa
'01110000000000000000000'
>>> # That's the 1/4 bit plus the 1/8th bit plus the 1/16th bits all enabled.
...
>>> 1 + 1/4 + 1/8 + 1/16
1.4375

这些形成了实际的浮点值:

>>> 1 * 2 ** 4 * 1.4375 (sign, positive, times 2 to the power exponent, times fractions)
23.0

换句话说,用二进制表示整数和小数点后的值;您可能必须近似非整数部分,因为二进制分数不能表达所有可能的实数。 23.0没有非整数组件,因此这里很容易,我们只需要将整数组件转换为二进制:

>>> format(23, 'b')
'10111'

因此实数的二进制表示为10111.0。然后,您将小数点向上或向下移动以获得1和分数;在这里你需要将小数点向上移动4个点到1.0111。这给出了指数(4)和有效值(0111加上未使用的分数的另外19个零)。值为正,因此您将符号编码为0,将指数编码为有符号值(添加127 == 131,将131编码为二进制== 10000011),并添加有效值:

0 10000011 01110000000000000000000

将其分成4组8位(4字节),可以得到0x41 0xB8 0x00 0x00。 Python的repr()字节输出为可能的字节提供可打印的ASCII字符,0x41是ASCII表中的字母A

>>> bytes([0b01000001, 0b10111000, 0b00000000, 0b00000000])
b'A\xb8\x00\x00'

将这些字节反转为小端表示:

>>> bytes([0b01000001, 0b10111000, 0b00000000, 0b00000000])[::-1]
b'\x00\x00\xb8A'

您可以看到IEEE binary32格式如何与this online converter一起使用。