我想了解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?
任何人都可以一步一步解释我吗?感谢。
答案 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位组成,分为:
将二进制数据视为位,(您将其视为小端,因此我将其反转以匹配维基百科的大端排序):
>>> ('{: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一起使用。