2009-10-20 73 views
27

Cómo convertir la siguiente cadena hexadecimal a float (precisión simple de 32 bits) en Python?Convertir hex a flotante

"41973333" -> 1.88999996185302734375E1 

"41995C29" -> 1.91700000762939453125E1 

"470FC614" -> 3.6806078125E4 

Respuesta

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 

Actualización: véase el comentario sobre la manera de hacer esto en Python 3.

+12

En python3 tiene que usar 'bytes.fromhex ('41973333')' en lugar de ''41973333'.decode (' hex ')' –

5

supongo esta pregunta se refiere a this one y se trabaja con 4 bytes en lugar de 8 dígitos hexadecimales.

"\x41\x91\x33\x33" es una cadena de 4 bytes a pesar de que parece que 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) 

Si es necesario para hacer frente a la cadena de hexdigits en lugar de los bytes reales, puede utilizar struct.pack para convertirlo, como este

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

recomiendo el uso de the ctypes module que básicamente le permite trabajar con tipos de datos de bajo nivel. En su caso se podría decir

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 

Creo que el módulo ctypes tiene sentido aquí, porque básicamente estás preguntando cómo realizar la fundición bits de bajo nivel. Su pregunta es, básicamente, ¿cómo le digo a Python que tome algunos datos e interprete esos datos como si esos mismos bits exactos fueran un tipo de datos diferente?

En C si tuviera un int y quería interpretar sus bits como un flotador, que haría más o menos lo mismo, teniendo un puntero y luego fundición y derreferenciándolo:

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

y eso es exactamente lo que el código de Python que usa la biblioteca ctypes está haciendo en mi ejemplo.

4

Cortar las cadenas hexagonales en trozos de 2 caracteres (bytes), convertir cada fragmento en el byte derecho con formato int, struct.unpack cuando haya terminado. Es decir:

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] 

emisor, según se desee:

18.8999996185 18.8999996185 
19.1700000763 19.1700000763 
36806.078125 36806.078125 
0

Gentelmen ... He aquí:

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 

perdón por el pequeño ".value" en t él termina ...
este código ha sido usado como clase en mi programa por casi 2 años.
(con un poco de edición, puede convertirlo fácilmente en una función)

crédito a PyTony en DaniWeb para el código.

a diferencia de la computación no dinámico,
el código no está cableada duro para un tamaño fijo flotador,
y funciona con cualquier bytes de tamaño.

aunque creo que todavía tenemos algunos errores que resolver.XDD
(Voy a editar el código más tarde (si puedo) con la actualización)

todo es bueno, aunque por el momento, aunque ...
havn't I tenían un problema de convertir los modelos de juegos 3D con él. :)

+0

Vaya, ese código es impenetrable ... – SamB

-1

El enfoque de ctypes no funciona cuando la cadena hexadecimal contiene los ceros a la izquierda. No lo uses