2010-02-15 4 views
3

Я получил значение float для Python, и мне нужно преобразовать его в формат Microsoft Basic Float (MBF). К счастью, у вас есть код из Интернета, который делает обратное.Как преобразовать из IEEE Python float в Microsoft Basic float

def fmsbin2ieee(self,bytes): 
    """Convert an array of 4 bytes containing Microsoft Binary floating point 
    number to IEEE floating point format (which is used by Python)""" 
    as_int = struct.unpack("i", bytes) 
    if not as_int: 
     return 0.0 
    man = long(struct.unpack('H', bytes[2:])[0]) 
    exp = (man & 0xff00) - 0x0200 
    if (exp & 0x8000 != man & 0x8000): 
     return 1.0 
     #raise ValueError('exponent overflow') 
    man = man & 0x7f | (man << 8) & 0x8000 
    man |= exp >> 1 
    bytes2 = bytes[:2] 
    bytes2 += chr(man & 255) 
    bytes2 += chr((man >> 8) & 255) 
    return struct.unpack("f", bytes2)[0] 

Теперь мне нужно отменить этот процесс, но пока не получилось. Любая помощь пожалуйста.

+0

Пожалуйста, подтвердите, что вы хотите ввод 8-байтового поплавком и выход 4-байтового MS поплавка Python, а не 8-байтовое MS поплавка. –

ответ

4

Если вы собираетесь выполнять эти преобразования во время работы под Windows, быстрее может быть, чтобы загрузить и установить mbf2ieee.exe и вызовите функцию CVS предложенную в результате Mbf2ieee.dll (например, с помощью [ctypes] [2]).

Если вы заинтересованы, чтобы сделать это в чистом Python, я думаю (но я не могу проверить, не имея номера MBF под рукой), что следующий может работать (я просто портировать его на Python от C code here):

def mbf2ieee(mbf_4bytestring): 
    msbin = struct.unpack('4B', mbf_4bytestring) 
    if msbin[3] == 0: return 0.0 

    ieee = [0] * 4 
    sign = msbin[2] & 0x80 
    ieee_exp = msbin[3] - 2 
    ieee[3] = sign | (ieee_exp >> 1) 
    ieee[2] = (ieee_exp << 7) | (msbin[2] & 0x7f) 
    ieee[:2] = msbin[:2] 

    return struct.unpack('f', ieee)[0] 

Если у вас есть проблемы, можете ли вы привести примеры входных значений и ожидаемых результатов?

Edit: если это обратная функция, которую вы хотите, это должно быть:

def float2mbf4byte(f): 
    ieee = struct.pack('f', f) 
    msbin = [0] * 4 
    sign = ieee[3] & 0x80 

    msbin_exp = (ieee[3] << 1) | (ieee[2] >> 7) 
    # how do you want to treat too-large exponents...? 
    if msbin_exp == 0xfe: raise OverflowError 
    msbin_exp += 2 

    msbin[3] = msbin_exp 
    msbin[2] = sign | (ieee[2] & 0x7f) 
    msbin[:2] = ieee[:2] 
    return msbin 
+0

Ummmmmm ..... это басард ... OP хочет перейти от python float (8-байтовый IEEE-float) к MS Basic float. –

+0

@ Джон, думаю, я запутался в коде, который он опубликовал, что делает mbf to ieee - позвольте мне добавить обратную функцию к моему ответу. –

+0

@Alex: переход от 8-байтового IEEE к 4-байтовым MS через 4-байтовый IEEE может потерять больше точности, чем потеряться, перейдя напрямую - считаете ли вы это? –

0

Ну, я попробовал float2mbf4byte() и сделал 2 модификации:

  1. конвертирования отрицательных значений в настоящее время работает,
  2. для Python 2, ieee должен быть список int's, а не строка

Сниппет:

def float2mbf4byte(f): 
    ieee = [ord(s) for s in struct.pack('f', f)] 
    msbin = [0] * 4 

    sign = ieee[3] & 0x80 
    ieee[3] &= 0x7f 

    msbin_exp = (ieee[3] << 1) | (ieee[2] >> 7) 
    # how do you want to treat too-large exponents...? 
    if msbin_exp == 0xfe: raise OverflowError 
    msbin_exp += 2 

    msbin[3] = msbin_exp 
    msbin[2] = sign | (ieee[2] & 0x7f) 
    msbin[:2] = ieee[:2] 
    return msbin 

def ieee2fmsbin(f): 
    return struct.pack('4B', *float2mbf4byte(f))