请考虑以下示例。
import struct
floats = [3.14, 2.7, 0.0, -1.0, 1.1]
s = struct.pack('f'*len(floats), *floats)
print("The bytes:")
print(s)
struct.pack函数应该输出列表中每个值的'bytes-representation'。该列表由64位浮点数组成(我的计算机是64位),所以我希望每个浮点数由8个字节表示:
3.14 -> 0x40 0x09 0x1E 0xB8 0x51 0xEB 0x85 0x1F
2.7 -> 0x40 0x05 0x99 0x99 0x99 0x99 0x99 0x9A
0.0 -> 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
-1.0 -> 0xBF 0xF0 0x00 0x00 0x00 0x00 0x00 0x00
1.1 -> 0x3F 0xF1 0x99 0x99 0x99 0x99 0x99 0x9A
顺便说一下,我使用以下网站进行了正确的转换:http://babbage.cs.qc.cuny.edu/IEEE-754.old/Decimal.html
不幸的是,Python没有输出我期望的那些字节。相反,Python会输出一些非常神秘的字节列表。但这真的是一个字节列表吗? Python输出的东西很奇怪:
b'\xc3\xf5H@\xcd\xcc,@\x00\x00\x00\x00\x00\x00\x80\xbf\xcd\xcc\x8c?'
请帮助我理解Python在这里做了什么。
修改
显然我应该使用'd'
而不是'f'
,因为我在我的机器上使用双精度浮点数。谢谢先生。 Rad雷克萨斯为您的答案。但我仍然对Python输出感到有些困惑。让我澄清一下。
我从您给我的以下代码开始:
import struct
floats = [3.14, 2.7, 0.0, -1.0, 1.1]
s = []
for f in floats:
s.append(struct.pack('d', f))
在继续之前,我会检查对象s
以掌握正在发生的事情。这是我从s
得到的:
>>> s
[ b'\x1f\x85\xebQ\xb8\x1e\t@',
b'\x9a\x99\x99\x99\x99\x99\x05@',
b'\x00\x00\x00\x00\x00\x00\x00\x00',
b'\x00\x00\x00\x00\x00\x00\xf0\xbf',
b'\x9a\x99\x99\x99\x99\x99\xf1?' ]
s
中的某些条目长度为8个字节。这就是我所期待的。但有些参赛作品更短。无论如何,没有条目给出相应浮点数的正确8字节表示 - 浮点数0.0
除外。
您的代码继续使用一些魔法来提取每个浮点数实际正确的8个字节:
print("The bytes:")
for floatInHex in s:
for byteval in floatInHex:
print ('%02x' % byteval, end="")
现在我们得到了正确的结果。但是为什么s
对象每个浮点数还没有包含正确的8个字节?为什么需要这种额外的魔力?
答案 0 :(得分:2)
f
适用于32位浮点数,您需要使用d
来表示64位浮点数(双精度)。请参阅Format characters - struct
>
to get same result with the site (big-endian) binascii.hexlify
将二进制字符串转换为十六进制表示。>>> binascii.hexlify(struct.pack('>d', floats[0]))
b'40091eb851eb851f'
>>> import struct
>>> import binascii
>>>
>>> floats = [3.14, 2.7, 0.0, -1.0, 1.1]
>>> s = struct.pack('>' + 'd'*len(floats), *floats)
>>> binascii.hexlify(s)
b'40091eb851eb851f400599999999999a0000000000000000bff00000000000003ff199999999999a'
如果要分别获取每个浮点表示,则需要迭代它们并转换它们。 (使用循环或列表理解,..)
>>> for f in floats:
... print(' '.join('0x{:02x}'.format(c) for c in struct.pack('>d', f)))
...
0x40 0x09 0x1e 0xb8 0x51 0xeb 0x85 0x1f
0x40 0x05 0x99 0x99 0x99 0x99 0x99 0x9a
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xbf 0xf0 0x00 0x00 0x00 0x00 0x00 0x00
0x3f 0xf1 0x99 0x99 0x99 0x99 0x99 0x9a
答案 1 :(得分:1)
您想要解压缩为double
但在程序中使用float
:f
的说明符。这就是你得到的:
c3 f5 48 40 for 3.14
(有关您看到某些ASCII字符的原因,请参阅python struct pack double。)
此代码将为每个数字打印出一行十六进制:
import struct
floats = [3.14, 2.7, 0.0, -1.0, 1.1]
s = []
for f in floats:
s.append(struct.pack('d', f))
print("The bytes:")
for floatInHex in s:
for byteval in floatInHex:
print ('%02x' % byteval, end=""),
print ()
结果:
The bytes:
1f85eb51b81e0940
9a99999999990540
0000000000000000
000000000000f0bf
9a9999999999f13f
答案 2 :(得分:0)
Python正在输出打印中的“奇怪”行为,因为 print
函数将尝试将任何ASCII可打印字符打印为ASCII,而不是不是十六进制。
它可以用binascii
正确打印,因为从不只能打印ASCII字符,只打印十六进制字符。
也让我上当了!正要问同样的问题,然后在这里找到: Python Bytearray Printing