web-dev-qa-db-fra.com

Convertir hex en flottant

Comment convertir la chaîne hexadécimale suivante en float (simple précision 32 bits) en Python?

"41973333" -> 1.88999996185302734375E1

"41995C29" -> 1.91700000762939453125E1

"470FC614" -> 3.6806078125E4
37
jack
>>> 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

Mise à jour: voir le commentaire sur la façon de procéder dans Python 3.

61
Denis Otkidach

Je recommande d'utiliser le module ctypes qui vous permet essentiellement de travailler avec des types de données de bas niveau. Dans votre cas, vous pourriez 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

Je pense que le module ctypes est logique ici, car vous demandez essentiellement comment effectuer une conversion de bits de bas niveau. Votre question est essentiellement, comment dire à Python de prendre des données et d'interpréter ces données comme si ces mêmes bits exacts étaient d'un type de données différent?

En C, si vous aviez un int et vouliez interpréter ses bits comme un flottant, vous feriez à peu près la même chose, en prenant un pointeur puis en le castant et en le déréférençant:

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

et c'est exactement ce que fait le code Python en utilisant la bibliothèque ctypes dans mon exemple.

13
Eli Courtwright

Je suppose que cette question concerne celle-ci et vous travaillez avec 4 octets plutôt que 8 chiffres hexadécimaux.

"\x41\x91\x33\x33" est une chaîne de 4 octets même si elle ressemble à 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 vous devez traiter la chaîne de chiffres hexadécimaux plutôt que les octets réels, vous pouvez utiliser struct.pack pour le convertir, comme ceci

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

Découpez les chaînes hexadécimales en morceaux de 2 caractères (octets), faites de chaque morceau dans le bon octet avec le formatage int, struct.unpack lorsque vous avez terminé. C'est à 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]

émettant, comme souhaité:

18.8999996185 18.8999996185
19.1700000763 19.1700000763
36806.078125 36806.078125
4
Alex Martelli