2009-10-20 91 views
27

Làm thế nào để chuyển đổi chuỗi hex sau thành float (độ chính xác đơn 32 bit) bằng Python?Chuyển đổi hex sang float

"41973333" -> 1.88999996185302734375E1 

"41995C29" -> 1.91700000762939453125E1 

"470FC614" -> 3.6806078125E4 

Trả lời

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 

Cập nhật: xem bình luận về làm thế nào để làm điều này bằng Python 3.

+12

Trong python3 bạn phải sử dụng 'bytes.fromhex ('41973333')' thay vì '' 41973333'.decode ('hex') ' –

5

Tôi đoán câu hỏi này liên quan đến this one và bạn đang làm việc với 4 byte thay vì 8 chữ số thập phân.

"\x41\x91\x33\x33" là một chuỗi 4 byte mặc dù có vẻ như 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) 

Nếu bạn cần để đối phó với các chuỗi hexdigits chứ không phải là các byte thực tế, bạn có thể sử dụng struct.pack để chuyển đổi nó, như thế này

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

Tôi khuyên bạn nên sử dụng the ctypes module mà về cơ bản cho phép bạn làm việc với các loại dữ liệu cấp thấp. Trong trường hợp của bạn, bạn có thể nói

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 

Tôi tin rằng các mô-đun ctypes có ý nghĩa ở đây, bởi vì bạn đang chủ yếu hỏi làm thế nào để thực hiện đúc chút ở mức độ thấp. Câu hỏi của bạn về cơ bản, làm thế nào để tôi nói với Python để lấy một số dữ liệu và giải thích dữ liệu đó như thể những bit chính xác đó là một kiểu dữ liệu khác nhau?

Trong C nếu bạn đã có một int và muốn giải thích bit của nó như là một phao, bạn sẽ làm khoảng điều tương tự, lấy một con trỏ và sau đó đúc và dereferencing nó:

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

và đó chính xác mã Python sử dụng thư viện ctypes đang làm gì trong ví dụ của tôi.

4

Cắt các chuỗi hex thành các khối 2 ký tự (byte), tạo từng đoạn thành byte bên phải với định dạng int, struct.unpack khi hoàn tất. Ví dụ:

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] 

phát ra, như mong muốn:

18.8999996185 18.8999996185 
19.1700000763 19.1700000763 
36806.078125 36806.078125 
0

Gentelmen ... Kìa:

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 

xin lỗi vì ".value" nhỏ tại t anh ấy kết thúc ...
mã này đã được sử dụng làm lớp học trong chương trình của tôi trong gần 2 năm nay.
(với một chút chỉnh sửa, bạn có thể dễ dàng biến nó thành một hàm)

tín dụng cho PyTony qua tại DaniWeb cho mã.

không giống như máy tính không động,
mã không cứng có dây đến một kích thước phao cố định,
và làm việc với bất kỳ byte kích thước.

mặc dù tôi đoán chúng tôi vẫn còn một vài lỗi để giải quyết.XDD
(Tôi sẽ sửa mã này sau đó (nếu tôi có thể) với bản cập nhật)

tất cả là tốt dù cho bây giờ mặc dù ...
tôi havn't có vấn đề chuyển đổi mô hình trò chơi 3D với nó. :)

+0

Wow mã đó không thể hiểu được ... – SamB

-1

Phương pháp tiếp cận ctypes không hoạt động khi chuỗi hex chứa số 0 đứng đầu. Không sử dụng nó.

Các vấn đề liên quan