【问题标题】:Convert a 64 bit integer into 8 separate 1 byte integers in python在python中将64位整数转换为8个单独的1字节整数
【发布时间】:2020-03-12 00:52:21
【问题描述】:

在 python 中,我得到了一个 64 位整数。这个整数是通过取几个不同的 8 位整数并将它们混合成一个巨大的 64 位整数而创建的。我的工作是再次将它们分开。

例如:

Source number: 2592701575664680400
Binary (64 bits): 0010001111111011001000000101100010101010000101101011111000000000
int 1: 00100011 (35)
int 2: 11111011 (251)
int 3: 00100000 (32)
int 4: 01011000 (88)
int 5: 10101010 (170)
int 6: 00010110 (22)
int 7: 10111110 (190)
int 8: 00000000 (0)

所以我想做的是获取我的源编号2592701575664680373 并返回一个长度为 8 的数组,其中数组中的每个 int 都是上面列出的 int。

我本来打算使用struct,但老实说,阅读documentation 并没有完全清楚我将如何实现这一点。

【问题讨论】:

  • 你试过divmod()吗?
  • 该死,你是对的@PadraicCunningham。我正在使用一个快速的脏工具,它不支持足够大的数字,并且它用 0 截断了最后一部分。现在我已经运行了bin = '{0:064b}'.format(source),我发现你是对的。
  • n 的事实很奇怪,最后没有 1 确实让我感到困惑
  • 我更改了源编号(根据答案似乎比更改二进制文件更好)
  • struct 文档并没有那么糟糕,您只需将数字加载到字符串中,然后再将其拆分为字节即可。

标签: python bitmask


【解决方案1】:

解决方案

不将数字转为字符串的解决方案:

x = 0b0010001111111011001000000101100010101010000101101011111000000000

numbers = list((x >> i) & 0xFF for i in range(0,64,8))
print(numbers)                    # [0, 190, 22, 170, 88, 32, 251, 35]
print(list(reversed(numbers)))    # [35, 251, 32, 88, 170, 22, 190, 0]

说明

在这里,我使用了列表推导,在i 上以 8 为增量进行循环。所以i 取值0, 8, 16, 24, 32, 40, 48, 56。 每次,位移运算符>> 都会临时将数字x 向下移动i 位。这相当于除以256^i

所以得到的数字是:

i = 0:   0010001111111011001000000101100010101010000101101011111000000000
i = 8:           00100011111110110010000001011000101010100001011010111110
i = 16:                  001000111111101100100000010110001010101000010110
i = 24:                          0010001111111011001000000101100010101010
i = 32:                                  00100011111110110010000001011000
i = 40:                                          001000111111101100100000
i = 48:                                                  0010001111111011
i = 56:                                                          00100011

通过使用& 0xFF,我选择了这个数字的最后8位。示例:

x >> 48:           001000111111101100100000
0xff:                              11111111
(x >> 48) & 0xff:  000000000000000000100000

由于前导零无关紧要,因此您有所需的数字。

结果被转换为列表并以正常和相反的顺序打印(就像 OP 想要的那样)。

性能

我将此结果的时间安排与该线程中提出的其他解决方案进行了比较:

In: timeit list(reversed([(x >> i) & 0xFF for i in range(0,64,8)]))
100000 loops, best of 3: 13.9 µs per loop

In: timeit [(x >> (i * 8)) & 0xFF for i in range(7, -1, -1)]
100000 loops, best of 3: 11.1 µs per loop

In: timeit [(x >> i) & 0xFF for i in range(63,-1,-8)]
100000 loops, best of 3: 10.2 µs per loop

In: timeit reversed(struct.unpack('8B', struct.pack('Q', x)))
100000 loops, best of 3: 3.22 µs per loop

In: timeit reversed(struct.pack('Q', x))
100000 loops, best of 3: 2.07 µs per loop

结果:我的解决方案不是最快的! 目前,直接使用struct(由 Mark Ransom 提出)似乎是最快的 sn-p。

【讨论】:

  • 你也可以[(n >> (i * 8)) & 0xFF for i in range(7, -1, -1)]忘记倒车
  • 由于某种原因,我得到了不同的计时结果。我在 32 位 Python 3.4.2 上使用 iPython 2.0.0。在 64 位 Windows 机器上。
  • 有一个简单的答案,你在第一个代码中什么都不做,你在列表中有一个生成器表达式
  • 您仍然需要反转列表,[(x >> (i * 8)) & 0xFF for i in range(7, -1, -1)] 会以正确的顺序为您提供输出
  • 使用struct 大约快三倍。
【解决方案2】:

在 Python 2.x 中,struct.pack 返回一个字节字符串。将其转换为整数数组很容易。

>>> bytestr = struct.pack('>Q', 2592701575664680400)
>>> bytestr
'#\xfb X\xaa\x16\xbd\xd0'
>>> [ord(b) for b in bytestr]
[35, 251, 32, 88, 170, 22, 189, 208]

python 中的struct 模块用于将python 对象转换为字节字符串,通常根据C 结构打包规则打包。 struct.pack 采用格式说明符(描述结构字节应如何布局的字符串)和一些 python 数据,并将其打包成字节字符串。 struct.unpack 则相反,采用格式说明符和字节字符串,并以 python 对象的格式再次返回解包数据的元组。

使用的格式说明符有两个部分。前导字符指定字符串的字节顺序(字节顺序)。以下字符指定被打包或解包的结构的字段类型。所以'>Q' 意味着将给定的数据打包为大端unsigned long long。要以相反的顺序获取字节,您可以使用 < 代替 little-endian。

最后的操作是一个列表推导,它遍历字节字符串的字符并使用ord 内置函数来获取该字符的整数表示。

最后说明:Python 实际上没有整数大小的概念。在 2.x 中,int 限制为 32 位,long 无限大小。在 3.x 中,这两个被统一为一个类型。所以即使这个操作保证给出只占用一个字节的整数,如果你在其他操作中使用它们,注意 python 将强制结果整数保持这种状态。

【讨论】:

  • 非常感谢您的解释!这不仅解决了我的问题,而且我对从现在开始使用struct 模块的能力更有信心。
  • @JHixson 你可以感谢 zstewart 在我回答代码后添加了整个解释。
【解决方案3】:
bn = "0010001111111011001000000101100010101010000101101011111000000000"

print([int(bn[i:i+8], 2) for i in range(0,len(bn), 8)])
[35, 251, 32, 88, 170, 22, 190, 0]

如果您使用 n 的二进制表示,那么输出会有所不同:

n = 2592701575664680373
bn = bin(n)

print([int(bn[i:i+8], 2) for i in range(0,len(bn), 8)])
[35, 251, 32, 88, 170, 22, 189, 181]

一些时间安排:

In [16]: %%timeit                                                
numbers = list((n >> i) & 0xFF for i in range(0,64,8))
list(reversed(numbers))
   ....: 
100000 loops, best of 3: 2.97 µs per loop

In [17]: timeit [(n >> (i * 8)) & 0xFF for i in range(7, -1, -1)]
1000000 loops, best of 3: 1.73 µs per loop

In [18]: %%timeit                                                
bn = bin(n)
[int(bn[i:i+8], 2) for i in range(0,len(bn), 8)]
   ....: 
100000 loops, best of 3: 3.96 µs per loop

你也可以只用 divmod:

out = []
for _ in range(8):
    n, i = divmod(n, 256)
    out.append(i) 
out = out[::-1]

这几乎同样有效:

In [31]: %%timeit
   ....: n = 2592701575664680411
   ....: out = []
   ....: for _ in range(8):
   ....:     n, i = divmod(n, 1 << 8)
   ....:     out.append(i)
   ....: out[::-1]
   ....: 
100000 loops, best of 3: 2.35 µs per loop

使用 python 进行位移几乎没有什么优势,我更倾向于使用你和其他人认为更易读的任何东西。

【讨论】:

    【解决方案4】:

    这是使用struct的版本:

    import struct
    n = 2592701575664680400
    bytes = struct.unpack('8B', struct.pack('Q', n))
    

    bytes 的返回顺序与您在问题中显示的顺序相反。

    以下是性能统计数据:

    python -m timeit -s "import struct" "struct.unpack('8B', struct.pack('Q', 2592701575664680400))"
    1000000 loops, best of 3: 0.33 usec per loop
    

    在我的电脑上,这比字节移位解决方案快三倍。

    【讨论】:

    • 您可能可以通过指定 64 位整数的字节顺序来控制返回字节的顺序(例如 big-endian,使用 &gt;)。
    【解决方案5】:

    对于一堆unit64来说,这似乎更快。使用 numpy。

    from cytpes import *
    import numpy as np
    l1 = c_uint64 * 512
    payload64 = l1(0)
    payload8 = np.frombuffer(payload64, dtype=np.uint8)
    

    payload8 是一个 np.unit8 数组,其大小是 payload64 大小的 8 倍,其中包含转换后的字节。

    对我来说它比结构变体更快...

    for i in range(len(payload64)):
           payload8[i*8:i*8+8] = struct.unpack('8B', struct.pack('Q', payload64[i]))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-21
      • 2021-03-06
      • 1970-01-01
      • 2014-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-17
      相关资源
      最近更新 更多