gpt4 book ai didi

python - 有没有更快的方法将任意大整数转换为大端字节序列?

转载 作者:太空狗 更新时间:2023-10-29 20:37:34 25 4
gpt4 key购买 nike

我有这个 Python 代码来执行此操作:

from struct import pack as _pack

def packl(lnum, pad = 1):
if lnum < 0:
raise RangeError("Cannot use packl to convert a negative integer "
"to a string.")
count = 0
l = []
while lnum > 0:
l.append(lnum & 0xffffffffffffffffL)
count += 1
lnum >>= 64
if count <= 0:
return '\0' * pad
elif pad >= 8:
lens = 8 * count % pad
pad = ((lens != 0) and (pad - lens)) or 0
l.append('>' + 'x' * pad + 'Q' * count)
l.reverse()
return _pack(*l)
else:
l.append('>' + 'Q' * count)
l.reverse()
s = _pack(*l).lstrip('\0')
lens = len(s)
if (lens % pad) != 0:
return '\0' * (pad - lens % pad) + s
else:
return s

在我的机器上,将 2**9700 - 1 转换为字节串大约需要 174 微秒。如果我愿意使用 Python 2.7 和 Python 3.x 特定的 bit_length 方法,我可以通过将 l 数组预分配为在一开始就使用正确的大小并使用 l[something] = 语法而不是 l.append

我能做些什么来加快速度吗?这将用于转换密码学中使用的大质数以及一些(但不是很多)较小的数。

编辑

这是目前 Python < 3.2 中最快的选项,它在任一方向上花费的时间大约是公认答案的一半:

def packl(lnum, padmultiple=1):
"""Packs the lnum (which must be convertable to a long) into a
byte string 0 padded to a multiple of padmultiple bytes in size. 0
means no padding whatsoever, so that packing 0 result in an empty
string. The resulting byte string is the big-endian two's
complement representation of the passed in long."""

if lnum == 0:
return b'\0' * padmultiple
elif lnum < 0:
raise ValueError("Can only convert non-negative numbers.")
s = hex(lnum)[2:]
s = s.rstrip('L')
if len(s) & 1:
s = '0' + s
s = binascii.unhexlify(s)
if (padmultiple != 1) and (padmultiple != 0):
filled_so_far = len(s) % padmultiple
if filled_so_far != 0:
s = b'\0' * (padmultiple - filled_so_far) + s
return s

def unpackl(bytestr):
"""Treats a byte string as a sequence of base 256 digits
representing an unsigned integer in big-endian format and converts
that representation into a Python integer."""

return int(binascii.hexlify(bytestr), 16) if len(bytestr) > 0 else 0

在 Python 3.2 中,int 类具有 to_bytesfrom_bytes 函数,可以比上面给出的方法。

最佳答案

这是一个通过ctypes 调用Python/C API 的解决方案。目前,它使用 NumPy,但如果 NumPy 不是一个选项,它可以完全使用 ctypes 来完成。

import numpy
import ctypes
PyLong_AsByteArray = ctypes.pythonapi._PyLong_AsByteArray
PyLong_AsByteArray.argtypes = [ctypes.py_object,
numpy.ctypeslib.ndpointer(numpy.uint8),
ctypes.c_size_t,
ctypes.c_int,
ctypes.c_int]

def packl_ctypes_numpy(lnum):
a = numpy.zeros(lnum.bit_length()//8 + 1, dtype=numpy.uint8)
PyLong_AsByteArray(lnum, a, a.size, 0, 1)
return a

在我的机器上,这比你的方法快 15 倍。

编辑:这是仅使用 ctypes 并返回字符串而不是 NumPy 数组的相同代码:

import ctypes
PyLong_AsByteArray = ctypes.pythonapi._PyLong_AsByteArray
PyLong_AsByteArray.argtypes = [ctypes.py_object,
ctypes.c_char_p,
ctypes.c_size_t,
ctypes.c_int,
ctypes.c_int]

def packl_ctypes(lnum):
a = ctypes.create_string_buffer(lnum.bit_length()//8 + 1)
PyLong_AsByteArray(lnum, a, len(a), 0, 1)
return a.raw

这又快了两倍,在我的机器上总计加速因子为 30。

关于python - 有没有更快的方法将任意大整数转换为大端字节序列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4358285/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com