Python 32位浮点数转换

1 投票
2 回答
8865 浏览
提问于 2025-04-17 13:27

在Redhat 6.3上使用Python 2.6

我有一个设备,它把32位浮点数分成两个内存寄存器来保存,一个是高位字,一个是低位字。我需要把这两个寄存器的值转换成一个浮点数。

我一直在使用在StackOverflow上找到的以下代码,这段代码和我在其他地方看到的很相似。

#!/usr/bin/env python
import sys
from ctypes import *
first  = sys.argv[1]
second = sys.argv[2]

reading_1 = str(hex(int(first)).lstrip("0x"))
reading_2 = str(hex(int(second)).lstrip("0x"))

sample = reading_1 + reading_2

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(sample)

寄存器的值的一个例子是:

寄存器-1;16282 寄存器-2;60597

这会产生一个浮点数:

1.21034872532

这是一个完全合理的数字,但有时候内存的值会是这样的:

寄存器-1;16282 寄存器-2;1147

使用这个函数时,结果是:

1.46726675314e-36

这是一个非常小的数字,看起来不太对。这个设备应该输出的读数大约在1.2到1.3之间。

我想弄清楚的是,这个设备是不是在输出错误的值,还是我得到的值是正确的,但我使用的函数不能正确地转换它们。

另外,有没有更好的方法,比如用numpy或者类似的工具?我承认我只是从网上的例子中复制了这段代码,对它的工作原理了解得很少,但在我当时可用的测试案例中,它似乎是有效的。

谢谢。

2 个回答

1

你现在把两个 int 转换的方式,隐含了一些关于 字节序 的假设,我觉得这些假设是不对的。

所以,我们先退一步。你知道第一个参数是最重要的部分,第二个参数是最不重要的部分。那么,不如我们不去琢磨怎么把它们合并成一个合适的十六进制字符串,直接这样做:

import struct
import sys

first  = sys.argv[1]
second = sys.argv[2]

sample = int(first) << 16 | int(second)

现在我们可以这样转换:

def convert(i):
    s = struct.pack('=i', i)
    return struct.unpack('=f', s)[0]

如果我用你的输入来试试:

$ python floatify.py 16282 60597
1.21034872532
$ python floatify.py 16282 1147
1.20326173306
7

如果你有原始的字节数据(比如从内存中读取、从文件中读取,或者通过网络获取),你可以使用 struct 来处理这些数据:

>>> import struct
>>> struct.unpack('>f', '\x3f\x9a\xec\xb5')[0]
1.2103487253189087

这里,\x3f\x9a\xec\xb5 是你的输入寄存器,16282(十六进制表示为 0x3f9a)和 60597(十六进制表示为 0xecb5)以字节的形式表示在一个字符串中。> 是字节顺序标记。

所以,根据你获取寄存器值的方式,你可能可以使用这种方法(例如,将你的输入整数转换为字节字符串)。你也可以用 struct 来实现这个,下面是你的第二个例子:

>>> raw = struct.pack('>HH', 16282, 1147)    # from two unsigned shorts
>>> struct.unpack('>f', raw)[0]              # to one float
1.2032617330551147

撰写回答