2009-09-03 14 views

Odpowiedz

13

Pracujesz w języku skryptowym wysokiego poziomu; z natury natywne typy danych systemu, na którym pracujesz, nie są widoczne. Nie można rzutować na natywną intację z takim kodem.

Jeśli wiesz, że chcesz przeliczonej wartości do 32-bitowej liczby całkowitej - niezależnie od platformy - można po prostu zrobić konwersję z prostej matematyki:

iv = 0xDEADBEEF 
if(iv & 0x80000000): 
    iv = -0x100000000 + iv 
+0

To nie jest dokładne: wszystkie obliczenia, które pasują do słowa maszyny, są wykonywane na tym poziomie. Na przykład ~ 1 == -2. Poszukuję więc sposobu na wymuszenie wyniku na typ int (co nie jest zgodne z tym, co int() najwyraźniej). –

+0

~ 1 == -2 w języku Python na * wszystkich * systemach. Jeśli tak nie jest w systemie natywnym, to implementacja Pythona musi je emulować. (Zobacz http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy.) Jedyny przypadek, w którym natywna wielkość słowa może przeniknąć do Pythona, występuje wtedy, gdy rozmiar int jest większy niż 32-bity , co oznacza, że ​​robisz transtion z int na długo później. –

+0

Nie można zmusić Pythona do konwersji długich na int, gdy wartość nie mieści się w int; nie możesz pisać kodu Pythona tak, jakbyś był w C.Jeśli chcesz przekonwertować niepodpisaną 32-bitową wartość int 0xFFFFFFFF do 32-bitowej liczby całkowitej ze znakiem, reprezentowanej przez ten sam ciąg bitów, to dałem ci kod. W przeciwnym razie nie jestem pewien, co próbujesz zrobić. –

5

Możesz użyć struct biblioteka do konwersji takich wartości. Jest brzydki, ale działa:

from struct import pack, unpack 
signed = unpack('l', pack('L', lv & 0xffffffff))[0] 
+0

To działa na komputerach 32-bitowych i kończy się niepowodzeniem na 64-bitowym – nkrkv

+3

To może być przenośne, jeśli używasz jednego z znaków zamówienia/rozmiaru/linii trasowania. Na przykład jako ciągi formatów użyj ''= l'' i '' = L''. – SamB

19
import ctypes 

number = lv & 0xFFFFFFFF 

signed_number = ctypes.c_long(number).value 
6

mogę zaproponować to:

def getSignedNumber(number, bitLength): 
    mask = (2 ** bitLength) - 1 
    if number & (1 << (bitLength - 1)): 
     return number | ~mask 
    else: 
     return number & mask 

print iv, '->', getSignedNumber(iv, 32) 
5

Zasadniczo, problem jest do podpisania rozciągają się od 32 bitów do ... nieskończonej liczby bitów, ponieważ Python ma dowolnie duże liczby całkowite. Zwykle rozszerzenie znaczników jest automatycznie wykonywane przez instrukcje procesora podczas rzutowania, więc interesujące jest to, że jest to trudniejsze w Pythonie, niż byłoby to na przykład, powiedzmy, C.

Podczas zabawy znalazłem coś podobnego do funkcji BreizhGatcha, ale to nie wymaga instrukcji warunkowej. n & 0x80000000 wyodrębnia 32-bitowy bit znaku; następnie - zachowuje tę samą 32-bitową reprezentację, ale znak - rozszerza ją; w końcu bity rozszerzonych znaków są ustawione na n.

def toSigned32(n): 
    n = n & 0xffffffff 
    return n | (-(n & 0x80000000)) 

Bit Twiddling Hacks sugeruje inne rozwiązanie, które być może działa bardziej ogólnie. n^0x80000000 odwraca 32-bitowy bit znaku; następnie - 0x80000000 zapisze w znaku-przedłużenie przeciwnego bitu. Innym sposobem myślenia o tym jest to, że początkowo liczby ujemne są powyżej liczb dodatnich (oddzielone przez 0x80000000); ^ zamienia swoje pozycje; potem - zmiany liczb ujemnych poniżej 0.

def toSigned32(n): 
    n = n & 0xffffffff 
    return (n^0x80000000) - 0x80000000 
+0

+1 za niestosowanie warunkowych. Prawdopodobnie nie robi dużej różnicy w Pythonie, ale z pewnością jest bardziej satysfakcjonujący. – zneak

0

szybkie i brudne rozwiązania (x nie jest większe niż 32-bit w moim przypadku).

if x > 0x7fffffff: 
    x = x - 4294967296 
Powiązane problemy