python:解包IBM 32位浮点数
我在用Python读取一个二进制文件,代码是这样的:
from struct import unpack
ns = 1000
f = open("binary_file", 'rb')
while True:
data = f.read(ns * 4)
if data == '':
break
unpacked = unpack(">%sf" % ns, data)
print str(unpacked)
然后我意识到,unpack(">f", str)
是用来解压IEEE浮点数的,而我的数据是IBM的32位浮点数。
我的问题是:我该怎么实现自己的unpack
来解压IBM的32位浮点数呢?
我不介意使用ctypes
来扩展Python,以获得更好的性能。
补充:我查了一些资料:
http://mail.scipy.org/pipermail/scipy-user/2009-January/019392.html这个看起来很有希望,但我想要更高效,因为可能会有成千上万次的循环。
补充:下面我会发布答案。谢谢你的建议。
1 个回答
5
我觉得我明白了:首先把字符串解压成无符号的4字节整数,然后使用这个函数:
def ibm2ieee(ibm):
"""
Converts an IBM floating point number into IEEE format.
:param: ibm - 32 bit unsigned integer: unpack('>L', f.read(4))
"""
if ibm == 0:
return 0.0
sign = ibm >> 31 & 0x01
exponent = ibm >> 24 & 0x7f
mantissa = (ibm & 0x00ffffff) / float(pow(2, 24))
return (1 - 2 * sign) * mantissa * pow(16, exponent - 64)
感谢所有帮助过我的人!
关于IBM浮点架构,如何编码和解码:http://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture
我的解决方案:我写了一个类,我觉得这样做可能会快一点,因为使用了Struct对象,这样解压格式只编译一次。
补充:还有因为它是一次性解压多个字节,解压操作可能比较耗费资源。
from struct import Struct
class StructIBM32(object):
"""
see example in:
http://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture#An_Example
>>> import struct
>>> c = StructIBM32(1)
>>> bit = '11000010011101101010000000000000'
>>> c.unpack(struct.pack('>L', int(bit, 2)))
[-118.625]
"""
def __init__(self, size):
self.p24 = float(pow(2, 24))
self.unpack32int = Struct(">%sL" % size).unpack
def unpack(self, data):
int32 = self.unpack32int(data)
return [self.ibm2ieee(i) for i in int32]
def ibm2ieee(self, int32):
if int32 == 0:
return 0.0
sign = int32 >> 31 & 0x01
exponent = int32 >> 24 & 0x7f
mantissa = (int32 & 0x00ffffff) / self.p24
return (1 - 2 * sign) * mantissa * pow(16, exponent - 64)
if __name__ == "__main__":
import doctest
doctest.testmod()