python: распаковать 32-битную точку с плавающей точкой IBM - PullRequest
12 голосов
/ 19 августа 2011

Я читал двоичный файл в 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 с плавающей запятой, мои данные это 32-битные числа с плавающей запятой IBM

Мой вопрос: Как я могу заставить мой unpack распаковать 32-битные числа типа с плавающей запятой IBM?

Я не против использовать ctypes для расширения Python для повышения производительности.

РЕДАКТИРОВАТЬ: Я сделал некоторые поиски: http://mail.scipy.org/pipermail/scipy-user/2009-January/019392.html

Это выглядит очень многообещающе, но я хочу стать более эффективным: есть потенциальные десятки тысяч циклов.

РЕДАКТИРОВАТЬ: опубликовал ответ ниже. Спасибо за совет.

1 Ответ

4 голосов
/ 22 августа 2011

Мне кажется, я понял: сначала распакуйте строку в 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 Floating Point Architecture, как кодировать и декодировать: http://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture

Мое решение: Я написал класс, я думаю, таким образом, это может быть немного быстрее, потому что используется объект Struct, так чтораспакованный fmt компилируется только один раз.РЕДАКТИРОВАТЬ: также потому, что он распаковывает размер * байтов все сразу, и распаковка может быть дорогой операцией.

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