Funkcja struct.pack() umożliwia konwertowanie liczb całkowitych do 64 bitów na ciągi bajtów. Jaki jest najbardziej efektywny sposób na spakowanie jeszcze większej liczby całkowitej? Wolałbym nie dodawać zależności od niestandardowych modułów, takich jak PyCrypto (która zapewnia num_to_bytes()).Efektywne pakowanie liczb całkowitych o dowolnej wielkości w Pythonie
Odpowiedz
Zgodnie z sugestią S.Lott w komentarzu, po prostu przekonwertuj liczbę na ciąg i spakuj ten ciąg. Na przykład,
x = 2 ** 12345
struct.pack("40s", str(x))
Jest to jeszcze mniej wydajne niż przechowywanie reprezentacji łańcuchowej liczby całkowitej, z powodu dopełnienia int bajtami zerowymi. –
Pytanie nie jest jasne, jaki rodzaj wydajności jest wymagany? Czy szukamy najbardziej efektywnego wykorzystania przestrzeni kosmicznej? A może najmniej czasu na spakowanie struktury? Jeśli o to chodzi, czy efektywność to nawet wielka sprawa? Pytanie wymagało najbardziej efektywnej odpowiedzi, ale ludzie często optymalizują się przedwcześnie. –
Zakładając plakat chce pakować dużą liczbę całkowitą jako ciąg binarny, czyli nie używać jeden bajt pamięci za cyfrę w numerze. Jednym ze sposobów na osiągnięcie tego wydaje się być:
import marshal
a = 47L
print marshal.dumps(a)
Drukuje:
'l\x01\x00\x00\x00/\x00'
Nie mogę powiedzieć, że rozumiem, jak interpretować te bity, teraz ...
To idzie w dobrym kierunku, ale wciąż ma dwa nadmiarowe bajty z przodu. –
@Mike: Właściwie więcej - myślę, że cyfry "l" i pierwsze 4 cyfry to tylko liczba zawartości, po której następuje jeden bajt ("/" == chr (47)) i zero na końcu. Wygląda również na to, że marszałek wykonuje bardziej złożony schemat kodowania, włączając w to surowe bajty (spójrz na zrzuty (2 ** 64-1) na przykład, a nie na 0x7f bajtów w środku. – Brian
I wziąć to masz na myśli, że chcesz tylko użyć tyle bajtów, ile potrzebujesz, aby reprezentować numer? na przykład jeśli liczba jest:
- 255 lub mniej byłoby użyć tylko 1 bajt
- 65535 lub mniej 2 bajty
- 16777215 lub mniej 3 bajty
- etc etc
Na Psion PDA zwykle mają trochę schematu pakowania, w którym czytasz pierwszy bajt, wykrywają, czy ma on najwyższy ustawiony bit, a następnie odczytuje inny bajt, jeśli ma. W ten sposób po prostu przeczytasz bajty, dopóki nie przeczytasz "pełnego" numeru. Ten system działa całkiem dobrze, jeśli większość liczb, z którymi masz do czynienia, jest dość mała, ponieważ normalnie używasz tylko jednego lub dwóch bajtów na liczbę.
Alternatywą jest mieć jeden (lub więcej) bajtów reprezentujących liczbę całkowitych bajtów używanych, ale w tym momencie to w zasadzie ciąg w Pythonie tak. tj. jest ciągiem 256 znaków bazowych.
Czy oznacza coś takiego:
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))
która zwraca:
1 01 1
16 10 16
256 0100 256
257 0101 257
1234567890987654321 112210f4b16c1cb1 1234567890987654321
ja po prostu nie wiem, co zrobić z negatywów ... Nie jestem aż tak obeznany z twidlingiem bitowym.
EDIT: Innym rozwiązaniem (które trwa około 30% szybszy od moich testów):
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)
Tak, to właśnie mam na myśli, i Napisałem taką funkcję jakiś czas temu, chciałem jednak coś, co łatwiej jest "portować", jak sztuczkę ze zrozumieniem listy lub (lepiej) funkcję biblioteczną, o której po prostu nie wiedziałem: – noamtm
Właśnie napisałem kolejną wersję z wbudowanym transkodowanie int/hex i transkodowanie hex/str ... Trochę szybciej! –
@noamtm: Proszę zaktualizować pytanie o dodatkowe fakty. Nie ukrywaj informacji w komentarzach. –
Jest to nieco hacky, ale można przejść przez reprezentację ciąg szesnastkowy, a tam do binarnych kodek hex:
>>> 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
łamie trochę bo kodek hex wymaga parzystą liczbę cyfr, więc trzeba za to pad, i trzeba ustawić flagę obsłużyć liczb ujemnych.Oto generic pakietu/rozpakować:
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
ze wszystkimi błahy dla dopełnienia itp wymagane, nie jestem pewien, że to o wiele lepiej niż ręcznie walcowane rozwiązanie chociaż.
- 1. Odczytanie wiersza liczb całkowitych w Pythonie
- 2. Scalenie dwóch liczb całkowitych w Pythonie
- 3. Efektywne czytanie liczb w Haskell
- 4. konwersji listę liczb całkowitych w zakresie w Pythonie
- 5. Przekazywanie liczb całkowitych o dowolnych rozmiarach od Prolog do C
- 6. Efektywne wyliczanie uporządkowanych podzbiorów w Pythonie
- 7. Podział liczb całkowitych w Javie
- 8. Efektywne rozdzielanie danych w Pythonie
- 9. Java: grupowanie liczb całkowitych
- 10. Stream liczb całkowitych
- 11. Dzielenie liczb całkowitych
- 12. Generowanie losowych liczb całkowitych w zakresie o rozkładzie prawdopodobieństwa
- 13. m liczb całkowitych brakujących w tablicy o rozmiarze n
- 14. Zaokrąglanie liczb całkowitych do najbliższej wielokrotności
- 15. Uzyskiwanie liczb losowych z listy liczb całkowitych
- 16. Określanie liczb parzystych/nieparzystych (liczb całkowitych)?
- 17. C: Reprezentacja dużych liczb całkowitych
- 18. Jak podsumować tablicę liczb całkowitych w C#
- 19. Sprawdź, czy lista liczb całkowitych zwiększa się o jeden
- 20. Konwersja Java do liczb całkowitych
- 21. Porównanie liczb całkowitych dowolnych typów
- 22. Wstawianie przecinków do liczb całkowitych
- 23. Przekraczanie dwóch liczb całkowitych bitowych
- 24. Reguły konwersji liczb całkowitych C++
- 25. python: Generowanie partycji liczb całkowitych
- 26. Przechowywanie bardzo dużych liczb całkowitych w MySQL
- 27. Podział liczb całkowitych zwraca 0
- 28. Podział na seq liczb całkowitych
- 29. Jak bezpiecznie używać liczb całkowitych?
- 30. Efektywne tasowanie bitów wektora liczb binarnych
Nie jestem pewien, o czym mówisz. Czy chcesz wstawić tekstową wersję Pythona do struktury? Łańcuchowa wersja długiej jest ciągiem; pakujesz go jak każdy inny ciąg. Jakie jest twoje prawdziwe pytanie? –
PO chciałby spakować, tak efektywnie, jak to możliwe, dowolnie wybraną liczbę całkowitą do reprezentacji w rozsądnym łańcuchu bajtowym. –