2009-10-20 24 views
27

Wie konvertiert man die folgende hexadezimale Zeichenfolge in Float (einzelne Genauigkeit 32-Bit) in Python?Konvertieren von hex in float

"41973333" -> 1.88999996185302734375E1 

"41995C29" -> 1.91700000762939453125E1 

"470FC614" -> 3.6806078125E4 

Antwort

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 

Update: siehe Kommentar auf, wie die 3.

+12

In Python3 müssen Sie 'bytes.fromhex ('41973333')' anstelle von ''41973333'.decode (' hex ')' –

5

ich diese Frage bin zu raten, bezieht sich auf this one und Sie arbeiten mit 4 Bytes statt 8 hexadezimalen Ziffern.

"\x41\x91\x33\x33" ist ein 4-Byte-String, obwohl es wie 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) 

Wenn Sie mit der Zeichenfolge von hexdigits beschäftigen müssen sieht, anstatt der tatsächliche Bytes, Sie struct.pack verwenden können, um es zu konvertieren, wie dies

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

ich empfehle the ctypes module verwendet, die im Grunde können Sie mit geringen Datentypen arbeiten. In Ihrem Fall könnten Sie

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 

sagen, dass ich glaube, dass der ctypes Modul Sinn hier macht, weil Sie im Wesentlichen ist zu fragen, wie Low-Level-Bit-Casting durchzuführen. Ihre Frage ist im Grunde, wie sage ich Python, um einige Daten zu nehmen und diese Daten so zu interpretieren, als wären diese genau dieselben Bits ein anderer Datentyp?

In C, wenn Sie einen int haben und wollten seine Bits als Schwimmer zu interpretieren, Sie ungefähr das gleiche tun würden, um einen Zeiger zu nehmen und dann Gießen und dereferencing es:

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

und das ist genau was der Python-Code mit der ctypes-Bibliothek in meinem Beispiel macht.

4

Die hexadezimalen Strings in 2-character Chunks (Bytes) zerlegen, jeden Chunk in das richtige Byte mit int-Formatierung bringen, struct.unpack, wenn das erledigt ist. Dh:

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] 

emittieren, je nach Wunsch:

18.8999996185 18.8999996185 
19.1700000763 19.1700000763 
36806.078125 36806.078125 
0

Gentelmen in Python zu tun ... Siehe:

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 

Entschuldigung für das kleine ".value" bei t Er endet ...
Dieser Code wurde seit fast 2 Jahren als Klasse in meinem Programm verwendet.
(mit ein wenig Bearbeitung, können Sie es leicht zu einer Funktion machen)

Kredit an PyTony über bei DaniWeb für den Code.

Im Gegensatz zu nicht-dynamischem computing,
der Code auf eine feste Größe Schwimmers nicht fest verdrahtet ist,
und arbeitet mit jeder Byte-Größe.

obwohl ich denke, wir haben noch ein paar Bugs zu erarbeiten.XDD
(später werde ich diesen Code bearbeiten (wenn ich kann) mit dem Update)

alles gut ist aber für jetzt aber ...
ich havn't damit ein Problem Umwandlung 3D-Spiel Modelle hatte. :)

+0

Wow, dass Code undurchdringlich ist ... – SamB

-1

Der Ctypes-Ansatz funktioniert nicht, wenn die Hexadezimalzahl führende Nullen enthält. Benutze es nicht.