Come convertire la seguente stringa esadecimale in float (precisione singola a 32 bit) in Python?Converti esadecimale in virgola mobile
"41973333" -> 1.88999996185302734375E1
"41995C29" -> 1.91700000762939453125E1
"470FC614" -> 3.6806078125E4
Come convertire la seguente stringa esadecimale in float (precisione singola a 32 bit) in Python?Converti esadecimale in virgola mobile
"41973333" -> 1.88999996185302734375E1
"41995C29" -> 1.91700000762939453125E1
"470FC614" -> 3.6806078125E4
>>> 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: vedi commento su come fare questo in Python 3.
Sto indovinando questa domanda si riferisce a this one e si sta lavorando con 4 byte invece di 8 cifre esadecimali.
"\x41\x91\x33\x33"
è una stringa di 4 byte, anche se sembra che 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)
Se si ha bisogno di trattare con la stringa di hexdigits piuttosto che i byte effettivi, è possibile utilizzare struct.pack
per convertirlo, come questo
>>> for hx in ["41973333","41995C29","470FC614"]:
... print(struct.unpack(">f",struct.pack(">i",int(hx,16)))[0])
...
18.8999996185
19.1700000763
36806.078125
mi consiglia di utilizzare the ctypes module che consente in pratica di lavorare con i tipi di dati di basso livello. Nel tuo caso si potrebbe dire
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
Credo che il modulo ctypes
ha un senso qui, perché si sta chiedendo in sostanza come eseguire a basso livello di bit casting. La tua domanda è fondamentalmente, come faccio a dire a Python di prendere alcuni dati e interpretare quei dati come se quegli stessi bit fossero un tipo di dati diverso?
In C se si ha un int e ha voluto interpretare i suoi pezzi come un galleggiante, faresti più o meno la stessa cosa, prendendo un puntatore e poi colata e dereferenziazione esso:
int i = 0x41973333;
float f = *((float*)&i);
e questo è esattamente cosa sta facendo il codice Python usando la libreria ctypes
nel mio esempio.
Taglia le stringhe esadecimali in blocchi di 2 caratteri (byte), trasforma ciascun blocco nel byte corretto con la formattazione int, struct.unpack al termine. Vale a dire:
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]
che emette, se lo desideri:
18.8999996185 18.8999996185
19.1700000763 19.1700000763
36806.078125 36806.078125
Gentelmen ... Ecco:
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
scusa per il piccolo ".valore" at finisce ...
questo codice è stato usato come una classe nel mio programma per quasi 2 anni.
(con un po 'di editing, si può facilmente fare in una funzione)
credito per PyTony sopra a DaniWeb per il codice.
differenza di calcolo non dinamico,
il codice non è cablato a una dimensione fissa galleggiante,
e funziona con qualsiasi byte-size.
anche se penso che abbiamo ancora alcuni bug da risolvere.XDD
(Io modificare questo codice in seguito (se posso) con l'aggiornamento)
tutto è buono se per ora però ...
havn't avuto un problema di conversione modelli di gioco 3D con esso. :)
Wow quel codice è impenetrabile ... – SamB
L'approccio ctypes non funziona quando la stringa esadecimale contiene zeri iniziali. Non usarlo
In python3 devi usare 'bytes.fromhex ('41973333')' invece di ''41973333'.decode (' hex ')' –