2009-10-20 21 views
27

Jak skonwertować następujący ciąg szesnastkowy na float (pojedyncza precyzja 32-bitowa) w Pythonie?Konwertuj hex na float

"41973333" -> 1.88999996185302734375E1 

"41995C29" -> 1.91700000762939453125E1 

"470FC614" -> 3.6806078125E4 

Odpowiedz

47
>>> import struct 
>>> struct.unpack('!f', '41973333'.decode('hex'))[0] 
18.899999618530273 
>>> struct.unpack('!f', '41995C29'.decode('hex'))[0] 
19.170000076293945 
>>> struct.unpack('!f', '470FC614'.decode('hex'))[0] 
36806.078125 

Aktualizacja: patrz komentarz na temat, jak to zrobić w Pythonie 3.

+12

W python3 musisz użyć 'bytes.fromhex ('41973333')' zamiast ''41973333'.decode (' hex ')' –

5

zgaduję to pytanie dotyczy this one i pracujesz z 4 bajty zamiast 8 cyfr szesnastkowych.

"\x41\x91\x33\x33" jest ciąg 4 bajtowy, mimo że wygląda jak 16

>>> len("\x41\x91\x33\x33") 
4 
>>> import struct 
>>> struct.unpack(">fff","\x41\x97\x33\x33\x41\x99\x5C\x29\x47\x0F\xC6\x14") 
(18.899999618530273, 19.170000076293945, 36806.078125) 

Jeśli trzeba zrobić, aby poradzić sobie z szeregiem hexdigits zamiast rzeczywistych bajtów, można użyć struct.pack aby przekształcić go, jak to

>>> for hx in ["41973333","41995C29","470FC614"]: 
...  print(struct.unpack(">f",struct.pack(">i",int(hx,16)))[0]) 
... 
18.8999996185 
19.1700000763 
36806.078125 
12

polecam korzystania the ctypes module które zasadniczo pozwala pracować z typów danych niskim poziomie. W twoim przypadku można powiedzieć

from ctypes import * 

def convert(s): 
    i = int(s, 16)     # convert from hex to a Python int 
    cp = pointer(c_int(i))   # make this into a c integer 
    fp = cast(cp, POINTER(c_float)) # cast the int pointer to a float pointer 
    return fp.contents.value   # dereference the pointer, get the float 

print convert("41973333") # returns 1.88999996185302734375E1 

print convert("41995C29") # returns 1.91700000762939453125E1 

print convert("470FC614") # returns 3.6806078125E4 

wierzę, że moduł ctypes sens tutaj, ponieważ jesteś w istocie do ustalenia, jak wykonać odlew bitowe niskopoziomowe. Twoje pytanie brzmi w zasadzie, w jaki sposób mogę nakazać Pythonowi pobranie pewnych danych i zinterpretowanie tych danych tak, jakby te same bity były innego typu?

W C jeśli miał int i chciał interpretować swoje bity jako pływaka, można zrobić mniej więcej to samo, biorąc wskaźnika, a następnie odlewanie i wyłuskania go:

int i = 0x41973333; 
float f = *((float*)&i); 

i to jest dokładnie jaki kod Pythona używa biblioteki ctypes w moim przykładzie.

4

Przełóż łańcuchy szesnastkowe na 2-znakowe porcje (bajty), ułóż każdy fragment w prawym bajcie z formatowaniem int, struct.unpack po zakończeniu. Tj:

import struct 

testcases = { 
"41973333": 1.88999996185302734375E1, 
"41995C29": 1.91700000762939453125E1, 
"470FC614": 3.6806078125E4, 
} 

def hex2float(s): 
    bins = ''.join(chr(int(s[x:x+2], 16)) for x in range(0, len(s), 2)) 
    return struct.unpack('>f', bins)[0] 

for s in testcases: 
    print hex2float(s), testcases[s] 

emitujących, zgodnie z życzeniem:

18.8999996185 18.8999996185 
19.1700000763 19.1700000763 
36806.078125 36806.078125 
0

Panowie ... Oto:

class fl: 
     def __init__(this, value=0, byte_size=4): 

      this.value = value 

      if this.value: # speedy check (before performing any calculations) 
       Fe=((byte_size*8)-1)//(byte_size+1)+(byte_size>2)*byte_size//2+(byte_size==3) 
       Fm,Fb,Fie=(((byte_size*8)-(1+Fe)), ~(~0<<Fe-1), (1<<Fe)-1) 

       FS,FE,FM=((this.value>>((byte_size*8)-1))&1,(this.value>>Fm)&Fie,this.value&~(~0 << Fm)) 
       if FE == Fie: this.value=(float('NaN') if FM!=0 else (float('+inf') if FS else float('-inf'))) 
       else: this.value=((pow(-1,FS)*(2**(FE-Fb-Fm)*((1<<Fm)+FM))) if FE else pow(-1,FS)*(2**(1-Fb-Fm)*FM)) 

       del Fe; del Fm; del Fb; del Fie; del FS; del FE; del FM 

      else: this.value = 0.0 

    print fl(0x41973333).value # >>> 18.899999618530273 
    print fl(0x41995C29).value # >>> 19.170000076293945 
    print fl(0x470FC614).value # >>> 36806.078125 
    print fl(0x00800000).value # >>> 1.1754943508222875e-38 (minimum float value) 
    print fl(0x7F7FFFFF).value # >>> 340282346638528859811704183484516925440L (maximum float value) 
    # looks like I've found a small bug o.o 
    # the code still works though (the numbers are properly formatted) 
    # the result SHOULD be: 3.4028234663852886e+38 (rounded) 
    print fl(0x3f80000000, 5).value # >>> 1.0 

Przepraszam za małą ".value" wt on koniec ...
ten kod został użyty jako klasa w moim programie od prawie 2 lat.
(z niewielką edycją, możesz z łatwością zamienić ją w funkcję)

Kredyt dla PyTony na DaniWeb za kod.

przeciwieństwie niedynamicznego informatyce
kod nie jest podłączone na stałe do stałej wielkości float
i działa z każdym bajt wielkości.

chociaż wydaje mi się, że nadal mamy kilka błędów do opracowania.XDD
(będę edytować ten kod później (jeśli mogę) z aktualizacją)

wszystko jest dobre, choć na razie jednak ...
havn't miał problem konwersji modeli 3D gry z nim. :)

+0

Wow, ten kod jest nieprzenikniony ... – SamB

-1

Podejście ctypes nie działa, gdy ciąg szesnastkowy zawiera początkowe zera. Nie używaj go.