How to convert from IEEE Python float to Microsoft Basic float
I got Python float value and I need to convert it in to Microsoft Basic Float (MBF) format. Luckily, Got some code from internet that does the reverse.
def fm开发者_如何学运维sbin2ieee(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]
Now I need to reverse this process, but no success yet. Any help please.
If you're going to perform these conversions while running under Windows, faster might be to download and install mbf2ieee.exe and call the CVS
function offered by the resulting Mbf2ieee.dll
(e.g. via [ctypes][2]).
If you're keen to do it in pure Python, I think (but I can't test, having no MBF numbers at hand) that the following might work (I just ported it to Python from 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]
If this has problems, can you give some examples of input values and expected results?
Edit: if it's the reverse function you want, it should be:
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
Well, I tried float2mbf4byte()
and made 2 modifications:
- converting negative values is now working,
- for Python 2, ieee should be list of int's, not string
The snippet:
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))
The mbf2ieee failed to convert properly, try this one:
import struct
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
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', bytearray(ieee))[0]
print(mbf2ieee(bytearray(float2mbf4byte(52400126))))
... and you will get:
builtins.ValueError: byte must be in range(0, 256)
because the right answer is [0,E4,47,9A]
, but
float2mbf4byte gives [0, 228, 19527, 76]
.
3rd element is not a byte size value
#Converter between MSF and IEEE
import struct
def fmsbin2ieee(b):
as_int = struct.unpack('i', b)
if not as_int:
return 0.0
man = int(struct.unpack('H', b[2:])[0])
if not man:
return 0.0
exp = (man & 0xff00) - 0x0200
man = man & 0x7f | (man << 8) & 0x8000
man |= exp >> 1
bytes2 = bytes([b[0], b[1], (man & 255), ((man >> 8) & 255)])
return struct.unpack('f', bytes2)[0]
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 bytes(msbin)
if __name__ == '__main__':
key = bytes([0x13, 0x00, 0x10, 0x10])
print(type(key))
print(key)
# 4 bytes MBF to float IEEE
flIEEE = fmsbin2ieee(key)
print(type(flIEEE))
print("ieee=", flIEEE)
# float IEEE to 4 bytes MBF
msf = float2mbf4byte(flIEEE)
print(type(msf))
print(msf)
精彩评论