Python 32位浮点数转换
在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 个回答
你现在把两个 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
如果你有原始的字节数据(比如从内存中读取、从文件中读取,或者通过网络获取),你可以使用 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