Converting from Microsoft Binary Format floats to Python Float



In the '80's, Microsoft had a proprietary binary structure to handle
floating point numbers, In a previous thread, Bengt Richter posted
some example code in how to convert these to python floats;

http://groups.google.com/group/comp.lang.python/browse_thread/thread/42150ccc20a1d8d5/4aadc71be8aeddbe#4aadc71be8aeddbe

I copied this code and modified it slightly, however, you will notice
that for one of the examples, the conversion isn't exact.

Can anyone advise me on how to modify this code to correct for this
situation ?
I think the problem may be related to the different lengths of the
mantissa. For double precision (8bytes) MBF format had 55 where as
Python floats (IEEE) has only 52 ??

Sample Code Below ----------------------
# Conversion of Microsoft Binary Format numbers to Python Floats

import binascii as bn
import struct as st


data = [(1234567890,'000000AF052C139F­'),
(4069954144,'00000060929672A0'­),
(999999.99, '703D0AD7FF237494'),
( 88888.88, '400ad7a3709c2d91'),
( 22222.22, '400ad7a3709c2d8f'),
( 33333.33, 'b047e17a54350290'),
( 1500.34, '7814ae47e18a3b8b'),
( 42345.00, '0000000000692590'),
]


def msd2float(bytes):
#take out values that don't make sense possibly the NaN and
Infinity ??
if sum(bytes) in [0,72,127]:
return 0.0
b = bytes[:]
sign = bytes[-2]&0x80
b[-2] |= 0x80 #hidden most sig bit in place of sign
exp = bytes[-1] - 0x80 - 56 #exponent offset
acc = 0L
for i,byte in enumerate(b[:-1]):
acc |=(long(byte)<<(i*8))
return (float(acc)*2.0**exp)*((1.,-1.­)[sign!=0])

for line in data:
inval = line[0]
binval = bn.unhexlify(line[1])
le_bytes = list(st.unpack('BBBBBBBB',binv­al))
outval = msd2float(le_bytes)
print " In:",inval, "\nOut:",outval,"\n"

Sample Output ------------------------
C:/Python24/pythonw.exe -u "C:/pytest/dms/Test MBF.pyw"
In: 1234567890
Out: 1234567895.5

In: 4069954144
Out: 4069954144.0

In: 999999.99
Out: 999999.99

In: 88888.88
Out: 88888.88

In: 22222.22
Out: 22222.22

In: 33333.33
Out: 33333.33

In: 1500.34
Out: 1500.34

In: 42345.0
Out: 42345.0
----End Sample Output ----

.