将十六进制转换为浮点数

Posted

技术标签:

【中文标题】将十六进制转换为浮点数【英文标题】:Convert hex to float 【发布时间】:2010-12-08 05:00:14 【问题描述】:

如何在 Python 中将以下十六进制字符串转换为浮点数(单精度 32 位)?

"41973333" -> 1.88999996185302734375E1

"41995C29" -> 1.91700000762939453125E1

"470FC614" -> 3.6806078125E4

【问题讨论】:

【参考方案1】:

Python 3 中:

>>> import struct
>>> struct.unpack('!f', bytes.fromhex('41973333'))[0]
18.899999618530273
>>> struct.unpack('!f', bytes.fromhex('41995C29'))[0]
19.170000076293945
>>> struct.unpack('!f', bytes.fromhex('470FC614'))[0]
36806.078125

Python 2 中:

>>> 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

【讨论】:

在python3中你必须使用bytes.fromhex('41973333')而不是'41973333'.decode('hex') print(struct.unpack('!f', bytes.fromhex('D'))[0]) ValueError: non-hexadecimal number found in fromhex() arg at position 1 有什么原因吗? @VaradarajuG 'D' 位于位置 0,位置 1 指向字符串的末尾。每个十六进制编码字节由 2 个字符组成,因此字符串的长度必须是偶数。你是说bytes.fromhex('0D') struct.unpack('!f', bytes.fromhex('9f780441ccb646'))[0] 输出:error: unpack requires a buffer of 4 bytes【参考方案2】:

我推荐使用the ctypes module,它基本上可以让您使用低级数据类型。在你的情况下,你可以说

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

我相信ctypes 模块在这里很有意义,因为您本质上是在询问如何执行低级位转换。您的问题基本上是,我如何告诉 Python 获取一些数据并解释该数据,就好像那些完全相同的位是不同的数据类型一样?

在 C 中,如果你有一个 int 并且想将它的位解释为浮点数,你会做大致相同的事情,获取一个指针,然后强制转换并取消引用它:

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

这正是我的示例中使用 ctypes 库的 Python 代码所做的。

【讨论】:

【参考方案3】:

我猜这个问题与this one 相关,您使用的是 4 个字节而不是 8 个十六进制数字。

"\x41\x91\x33\x33" 是一个 4 字节的字符串,尽管它看起来像 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)

如果你确实需要处理十六进制数字的字符串而不是实际的字节,你可以使用struct.pack来转换它,像这样

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

【讨论】:

【参考方案4】:

将十六进制字符串分割成 2 个字符的块(字节),用 int 格式将每个块变成正确的字节,完成后 struct.unpack。即:

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]

根据需要发射:

18.8999996185 18.8999996185
19.1700000763 19.1700000763
36806.078125 36806.078125

【讨论】:

【参考方案5】:

从字符串工作且无需对值进行切片或索引时。

import struct
...
q = int('0x425c0000',16)
b8 = struct.pack('i', q)
dec, = struct.unpack('f', b8)

【讨论】:

【参考方案6】:

先生们......看哪:

    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

对不起,最后的小“.value”...... 这段代码已经在我的程序中作为一个类使用了将近 2 年了。 (稍加编辑,你就可以很容易地把它变成一个函数)

感谢 DaniWeb 上的 PyTony 提供代码。

与非动态计算不同, 代码没有硬连线到固定的浮点大小, 并且适用于任何字节大小。

虽然我猜我们仍有一些错误需要解决。 XDD (我会稍后(如果可以的话)使用更新编辑此代码)

虽然现在一切都很好...... 用它转换 3D 游戏模型时我没有遇到任何问题。 :)

【讨论】:

以上是关于将十六进制转换为浮点数的主要内容,如果未能解决你的问题,请参考以下文章

在 SciLab 中将十六进制转换为浮点数

如果以十进制形式收到的值是一个空字符串,我该如何将其转换为浮点数?

从代表二进制的字符串转换为浮点数

怎么将4字节16进制转化成浮点数

将字节转换为浮点数?

excel表格如何将十六进制转换成浮点数