Je possède ce code Python pour ce faire:Existe-t-il un moyen plus rapide de convertir un grand nombre arbitraire en une grande suite d'octets?
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
Cela prend environ 174 USEC pour convertir 2**9700 - 1
à une chaîne d'octets sur ma machine. Si je suis prêt à utiliser la méthode spécifique Python 2.7 et Python 3.x bit_length
, je peux raccourcir cela à 159 usecs en pré-allouant le tableau l
pour avoir exactement la bonne taille au début et en utilisant la syntaxe l[something] =
au lieu de l.append
.
Y a-t-il quelque chose que je puisse faire pour accélérer le processus? Cela sera utilisé pour convertir de grands nombres premiers utilisés en cryptographie ainsi que certains nombres plus petits (mais pas beaucoup).
Modifier
C'est actuellement l'option la plus rapide en Python < 3.2, il faut environ la moitié du temps ou l'autre direction que la réponse acceptée:
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
En Python 3.2 la classe int
a to_bytes
et from_bytes
des fonctions qui peuvent accomplir cela beaucoup plus rapidement que la méthode donnée ci-dessus.
Que fait «pad»? Un docstring serait utile pour comprendre l'utilisation. –
@Scott Autant que je sache, la sortie est remplie de zéros à l'avant du nombre d'octets du multiple-pad suivant. –
Si vous utilisez une variable locale, vous éviterez d'utiliser un nom de variable comme "l" - il ressemble trop à "1" sur la plupart des polices pour garder la lisibilité. – jsbueno