我需要能够将4个浮动数字打包成一个整数,然后将整数解压缩到我的4个浮点数中。
浮点数的例子(精度不超过8位):
-0.02513393, -0.02394553, 0.04248389, 0.02388026
所以,我认为首先我需要通过将每个浮点数乘以1000000000来将这些浮点数转换为整数。
floats = [-0.02513393, -0.02394553, 0.04248389, 0.02388026]
integers = list(map(lambda i: int(i * 1000000000), floats))
# output: [-25133930, -23945530, 42483890, 23880260]
然后使用按位运算将四个数字合并为一个,如下所示:
a, b, c, d = integers
packed = (a << 24) | (b << 16) | (c << 8) | d
但是,这似乎不正确,因为我试图打包的值已签名。
请您提供正确的解决方案,将这些已签名的浮点数打包成一个整数,并以正确的方式解压缩它们吗?
我想在每个负值的末尾添加1
并在每个正值的末尾添加0
并将整数恢复为浮点数我会先检查是否有{{1}我否定了价值,然后除以1000000000.但这根本不优雅。
答案 0 :(得分:2)
使用NumPy,您可以查看 dtype float16
的4元素数组,作为dtype int64
的整数数组:
In [125]: np.array([-0.02513393, -0.02394553, 0.04248389, 0.02388026], dtype=np.float16).view(np.int64)
Out[125]: array([2746396911566169711])
要解压缩int,您可以使用view(np.float16)
:
In [126]: np.array([2746396911566169711]).view(np.float16)
Out[126]: array([-0.02513123, -0.02394104, 0.04248047, 0.02388 ], dtype=float16)
请注意,精度有所下降。
使用Python3.2(或更高版本)而不使用NumPy,可以将浮点数打包成字节,然后使用int.from_bytes
将字节转换为int。要解压缩,请使用int.to_bytes
和struct.unpack
:
import struct
def floats_to_int(floats):
return int.from_bytes(struct.pack('4d', *floats), 'big')
def int_to_floats(packed):
return struct.unpack('4d', packed.to_bytes(4*8, 'big'))
floats = [-0.02513393, -0.02394553, 0.04248389, 0.02388026]
print(floats)
packed = floats_to_int(floats)
print(packed)
result = int_to_floats(packed)
print(result)
打印
[-0.02513393, -0.02394553, 0.04248389, 0.02388026]
3995686615650679380069295189325600154682811585786433559914521688689786263615
(-0.02513393, -0.02394553, 0.04248389, 0.02388026)
答案 1 :(得分:1)
如果根据评论,打包数据的宽度无关紧要,那么您的一般方法可以通过一些调整来实现。
首先,每个数字的8位是不够的;你会在每一个之间重叠。您的浮点数只有8个位精度,但这并不意味着它们在二进制表示中只有8个重要的位。找出它们需要的宽度的一个好方法是考虑一个你知道它们都低于(在你的情况下,1000000000)的数字,那么该数字的位长度(30)就足够了。所以我们有:
packed = a&lt;&lt; 90 | b&lt;&lt; 60 | c&lt;&lt; 30 | d
正如您所怀疑的那样,这仍然存在负数问题。从上面开始,我可以使用d
成功恢复packed & 2**30-1
,c
成功恢复(packed & 2**30-1 << 30 ) >> 30
,但a
和b
做同样的事情会让我感到高兴废话。所以减少它已经解决的问题。如果你为每一个添加足够大的数字以使它们都是正数,你可以将它们视为无符号 - 再一次,你知道它们小于1000000000,所以这是一个神奇的数字。乱码的数字现在都小于2000000000,所以我们需要调整我们的场宽。所以我们有:
上限= 1000000000 packed =(a + ceiling)&lt;&lt; 31 * 3 | (b +上限)&lt;&lt; 31 * 2 | (c +上限)&lt;&lt; 31 | d
我们可以将a
恢复为((packed & 2**31-1<< 31*3) >> 31*3) - ceiling
。为了便于阅读,您可能需要考虑将其写为循环。
答案 2 :(得分:1)
正如评论中所提到的,您当前的策略不起作用,因为您将8 十进制数字精度与8 位精度混合在一起。
(a << 24) | (b << 16) | (c << 8) | d
如果那些变量包含8位数据,即范围(256)中的整数,将起作用。您需要大约32位来将浮点数据存储为8 十进制数字精度。
请注意,标准Python(又名CPython)使用IEEE 754 binary64 double precision作为其浮点数。
但是您可以使用32位单精度浮点数近似浮点数据,并使用标准struct
模块打包它们。这是一个简短的演示:
from struct import pack, unpack
# Make a list of 4 Python floats.
a = [i**0.5 for i in range(5, 9)]
print(a)
# Convert the Python floats to 32 bit floats and pack them into 16 bytes, big endian
fmt = '>ffff'
b = pack(fmt, *a)
print(b, len(b))
# Unpack the bytes back into floats
z = unpack(fmt, b)
print(z)
print([u*u for u in z])
# Pack the bytes into an int, using big-endian packing
num = int.from_bytes(b, 'big')
print(num)
# Convert the int back to bytes
newb = num.to_bytes(16, 'big')
print(newb, newb == b)
<强>输出
[2.23606797749979, 2.449489742783178, 2.6457513110645907, 2.8284271247461903]
b'@\x0f\x1b\xbd@\x1c\xc4q@)S\xfd@5\x04\xf3' 16
(2.2360680103302, 2.4494898319244385, 2.6457512378692627, 2.8284270763397217)
[5.00000014682206, 6.000000436701214, 6.999999612686736, 7.999999726171666]
85149038802136470295784196693032240371
b'@\x0f\x1b\xbd@\x1c\xc4q@)S\xfd@5\x04\xf3' True
请注意,.from_bytes
和.to_bytes
是Python 3的功能; Python 2中的相同操作稍微冗长一点。