hexa to binary python
Convertir hexadecimal a flotar (6)
¿Cómo convertir la siguiente cadena hexadecimal a flotar (precisión única de 32 bits) en Python?
"41973333" -> 1.88999996185302734375E1
"41995C29" -> 1.91700000762939453125E1
"470FC614" -> 3.6806078125E4
Corte las cadenas hexadecimales en trozos de 2 caracteres (bytes), convierta cada trozo en el byte derecho con el 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]
emitiendo, según se desee:
18.8999996185 18.8999996185
19.1700000763 19.1700000763
36806.078125 36806.078125
El enfoque de ctypes no funciona cuando la cadena hexadecimal contiene ceros iniciales. No lo uses
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
lo siento por el pequeño ".valor" al final ...
este código ha sido utilizado como una clase en mi programa durante casi 2 años.
(Con un poco de edición, puedes convertirlo fácilmente en una función)
crédito a PyTony en DaniWeb por el código.
a diferencia de la computación no dinámica,
el código no está cableado a un tamaño flotante fijo,
y funciona con cualquier tamaño de byte.
aunque supongo que todavía tenemos algunos errores que resolver. XDD
(Editaré este código más tarde (si puedo) con la actualización)
todo está bien aunque por ahora aunque ...
No he tenido problemas para convertir modelos de juegos en 3D con él. :)
Recomiendo usar el módulo ctypes que básicamente le permite trabajar con tipos de datos de bajo nivel. En tu caso podrías 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 conversión de 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 fueran exactamente un tipo de datos diferente?
En C si tuvieras un int y quisieras interpretar sus bits como un flotador, harías más o menos lo mismo, tomando un puntero y luego lanzándolo y desreferiéndolo:
int i = 0x41973333;
float f = *((float*)&i);
y eso es exactamente lo que hace el código Python que usa la biblioteca ctypes
en mi ejemplo.
Supongo que esta pregunta se relaciona con esta y usted está trabajando con 4 bytes en lugar de 8 dígitos hexadecimales.
"/x41/x91/x33/x33"
es una cadena de 4 bytes, aunque se parece a 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 necesitas lidiar con la cadena de hexdigits en lugar de los bytes reales, puedes usar 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
>>> 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: ver comentario sobre cómo hacer esto en Python 3.