La función struct.pack() permite convertir enteros de hasta 64 bits a cadenas de bytes. ¿Cuál es la forma más eficiente de empacar un número entero aún mayor? Prefiero no agregar una dependencia en módulos no estándar como PyCrypto (que proporciona num_to_bytes()).Empaquetado de enteros de tamaño arbitrario eficiente en Python
Respuesta
Según lo sugerido por S.Lott en un comentario, simplemente convierta el número en una cadena y empaquete esa cadena. Por ejemplo,
x = 2 ** 12345
struct.pack("40s", str(x))
Eso es incluso menos eficiente que simplemente almacenar la representación de cadena del entero, debido al relleno de int con bytes nulos. –
La pregunta no está clara qué tipo de eficiencia se requiere? ¿Estamos buscando el uso más eficiente del espacio? ¿O quizás el menor tiempo de procesamiento para empacar la estructura? Para el caso, ¿la eficiencia es incluso un gran problema? La pregunta fue la respuesta más eficiente, pero las personas a menudo optimizan prematuramente. –
Suponiendo que el cartel paquete de un entero grande como una cadena binaria, es decir, no utilizar un byte de almacenamiento por dígito del número. Una forma de hacer esto parece ser:
import marshal
a = 47L
print marshal.dumps(a)
Esta impresora:
'l\x01\x00\x00\x00/\x00'
No puedo decir que entiendo cómo interpretar estos bits, en este momento ...
Eso va en la dirección correcta, pero todavía tiene dos bytes redundantes en el frente. –
@Mike: en realidad, más que eso: creo que la "l" y los primeros 4 dígitos son solo un recuento del contenido, seguidos por un byte único ("/" == chr (47)) y un nulo al final. También parece que Marshal está haciendo un esquema de codificación más complejo que solo incluye los bytes sin procesar (vea los volcados (2 ** 64-1) por ejemplo y no los bytes 0x7f en el medio. – Brian
I tómelo, ¿quiere decir que solo quiere usar tantos bytes como necesite para representar el número? p.ej. si el número es:
- 255 o menos tendrá que utilizar solamente 1 byte
- 65535 o menos 2 bytes
- 16777215 o menos 3 bytes
- , etc, etc
Por Psion PDA por lo general tienen algunos de los planes de empaque en los que lee el primer byte, detecta si tiene el bit más alto establecido y luego lee otro byte si lo tiene. De esta forma, seguirías leyendo los bytes hasta que leas el número "completo". Ese sistema funciona bastante bien si la mayoría de los números con los que se trata son bastante pequeños, ya que normalmente solo usará uno o dos bytes por número.
La alternativa es tener uno (o más) bytes que representen la cantidad total de bytes utilizados, pero en ese punto, básicamente, es una cadena en Python. es decir, es una cadena de dígitos base-256.
Qué quiere decir algo así:
def num_to_bytes(num):
bytes = []
num = abs(num) # Because I am unsure about negatives...
while num > 0:
bytes.append(chr(num % 256))
num >>= 8
return ''.join(reversed(bytes))
def bytes_to_num(bytes):
num = 0
for byte in bytes:
num <<= 8
num += ord(byte)
return num
for n in (1, 16, 256, 257, 1234567890987654321):
print n,
print num_to_bytes(n).encode('hex'),
print bytes_to_num(num_to_bytes(n))
que devuelve:
1 01 1
16 10 16
256 0100 256
257 0101 257
1234567890987654321 112210f4b16c1cb1 1234567890987654321
que no estoy seguro de qué hacer con los negativos ... No soy tan familiarizados con un poco de twidling
EDIT: Otra solución (que se extiende alrededor del 30% más rápido por mis pruebas):
def num_to_bytes(num):
num = hex(num)[2:].rstrip('L')
if len(num) % 2:
return ('0%s' % num).decode('hex')
return num.decode('hex')
def bytes_to_num(bytes):
return int(bytes.encode('hex'), 16)
Sí, esto es lo que quiero decir, y Escribí tal función hace un tiempo. Sin embargo, quería algo que sea más fácil de "portar", como un truco de comprensión de listas o (mejor) una función de biblioteca que simplemente no sabía. – noamtm
Acabo de publicar otra publicación con built-in transcodificación int/hex y transconding hex/str ... ¡También va un poco más rápido! –
@noamtm: Actualice la pregunta con hechos adicionales. No solo oculte información en los comentarios. –
Esto es un poco hacky, pero se puede ir a través de la representación de cadena hexadecimal, y no a binario con el códec hexagonal:
>>> a = 2**60
>>> a
1152921504606846976L
>>> hex(a)
'0x1000000000000000L'
>>> hex(a).rstrip("L")[2:].decode('hex')
'\x10\x00\x00\x00\x00\x00\x00\x00' # 8bytes, as expected.
>>> int(_.encode('hex'), 16)
1152921504606846976L
se rompe un poco porque el códec hexagonal requiere un número par de dígitos, por lo que tendrá a la almohadilla para eso, y usted tendrá que establecer un indicador para manejar números negativos.He aquí un paquete genérico/deshacer las maletas:
def pack(num):
if num <0:
num = (abs(num) << 1) | 1 # Hack - encode sign as lowest bit.
else:
num = num << 1
hexval = hex(num).rstrip("L")[2:]
if len(hexval)%2 ==1: hexval = '0' + hexval
return hexval.decode('hex')
def unpack(s):
val = int(s.encode('hex'), 16)
sign = -1 if (val & 1) else 1
return sign * (val>>1)
for i in [10,4534,23467, 93485093485, 2**50, 2**60-1, -1, -20, -2**60]:
assert unpack(pack(i)) == i
Con todo el tocar el violín para el relleno etc requerido, no estoy seguro de que es mucho mejor que una solución hecha a mano sin embargo.
- 1. Cola FIFO eficiente para trozos de bytes de tamaño arbitrario en Python
- 2. Empaquetado de bits de una matriz de enteros
- 3. Endianness de enteros en Python
- 4. Tipo de datos de tamaño de bit arbitrario en C#
- 5. ¿Hay enteros de tamaño fijo en GCC?
- 6. Rangos enteros de Python
- 7. Crear lista aleatoria de enteros en Python
- 8. Aplicaciones de empaquetado de Python con archivos de configuración
- 9. Ecosistema de Empaquetado de Ruby Como terminología de Python
- 10. Empaquetado de OpenCV con una aplicación de Python
- 11. de estilo Python división de enteros y módulo en C
- 12. Contando duplicados enteros en Python
- 13. Fusionar dos enteros en Python
- 14. Cómo combinar un número arbitrario de tuplas en Python?
- 15. Número de longitud arbitrario en Ada
- 16. Limpio, algoritmo eficiente para envolver enteros en C++
- 17. ¿Cómo crear una matriz de enteros en Python?
- 18. SymPy - Número arbitrario de símbolos
- 19. cambio de programación en Python eficiente
- 20. Detección de bordes bidimensional eficiente en Python
- 21. Tamaño de imagen eficiente de memoria en Android
- 22. Lectura de enteros del archivo binario en Python
- 23. ¿Existe alguna forma más eficiente de organizar los resultados aleatorios por tamaño en Python?
- 24. Cómo convertir cadenas en enteros en Python?
- 25. empaquetado y desempaquetado array/string de longitud variable utilizando el módulo struct en python
- 26. Cómo encontrar el tamaño de matriz de enteros
- 27. suma de python() y valores no enteros
- 28. Grupo de datos MySQL en intervalos de tiempo de tamaño arbitrario
- 29. C#: Métodos de empaquetado en otros métodos
- 30. Empaquetado de múltiples rpms en un archivo
No estoy seguro de lo que está hablando. ¿Quieres poner la versión de cadena de un Python en una estructura? La versión de cadena de un largo es una cadena; lo empacas como cualquier otra cuerda. ¿Cuál es tu verdadera pregunta? –
El OP desea empacar, de la manera más eficiente posible, un entero de tamaño arbitrario en una representación razonable de cadenas de bytes. –