Extract double in binary file

Francis Avila francisgavila at yahoo.com
Fri Nov 28 10:45:31 CET 2003


Dennis Lee Bieber wrote in message ...
>Pascal fed this fish to the penguins on Thursday 27 November 2003 01:07
>am:
>>
>> Some precisions:
>> 0.00 > 00-00-00-00-00-00-7F-00
>> 1.00 > 00-00-00-00-00-00-00-81
>> 2.00 > 00-00-00-00-00-00-00-82
>> 3.00 > 00-00-00-00-00-00-40-82
>> 4.00 > 00-00-00-00-00-00-00-83
>>
>> 10.00 > 00-00-00-00-00-00-20-84
>> 1000.00 > 00-00-00-00-00-00-7A-8A
>>
>> 1.11 > 14-AE-47-E1-7A-14-0E-81
>converting exponents excess 81...
>

>        0 1 00 00 00 00 00 00 00
>        1 1 00 00 00 00 00 00 00
>        1 1 40 00 00 00 00 00 00
>        2 1 00 00 00 00 00 00 00
>        3 1 20 00 00 00 00 00 00


That is a bizarre format, and of course I had to implement it. (Even C is
more pleasant in Python!).

It works for the cases given, but do find out where the sign bit is for the
mantissa. (This code assumes it's the MSB of the mantissa.)

Also tease out the NaN and +-Infinity cases.

--- Code ---
#! /usr/bin/env python
# by Francis Avila
#
# Decode a peculiar binary floating point encoding
# used by 'multilog', an old dos spreadsheet.

import struct

_known = (('0.00', '\x00\x00\x00\x00\x00\x00\x7F\x00'),
         ('1.00', '\x00\x00\x00\x00\x00\x00\x00\x81'),
         ('2.00', '\x00\x00\x00\x00\x00\x00\x00\x82'),
         ('3.00', '\x00\x00\x00\x00\x00\x00@\x82'),
         ('4.00', '\x00\x00\x00\x00\x00\x00\x00\x83'),
         ('10.00','\x00\x00\x00\x00\x00\x00 \x84'),
         ('1000.00','\x00\x00\x00\x00\x00\x00z\x8a'),
         ('1.11', '\x14\xaeG\xe1z\x14\x0e\x81'))

def _test():
    tests = [(str(float(i)),str(dectofloat(j))) for i,j in _known]
    results = [expect==got for expect,got in tests]

    failed = [tests[i] for i, passed in enumerate(results) if not passed]

    if failed: return failed
    else: return 'Passed'

def bin(I):
    """Return list of bits of int I in little endian."""
    if I < 0:
        raise ValueError, "I must be >= 0"
    bits = []
    if I == 0:
        bits = [0]
    while I>0:
        r = (I & 0x1)
        if r: r = 1
        bits.append(r)
        I >>= 1
    bits.reverse()
    return bits

def binaryE(n, exp):
    """Return result of a binary n*10**exp.

    As n*10**exp is to decimal, so binaryE(n, exp) is to binary.
    """
    return sum([2**(exp-i) for i,bit in enumerate(bin(n)) if bit])


#Add special cases here:
SPECIAL = {'\x00\x00\x00\x00\x00\x00\x7f\x00':0.0}

def dectofloat(S):
    """Return float value of 8-byte 'decimal' string."""
    if S in SPECIAL:
        return SPECIAL[S]

    # Convert to byteswapped long.
    N, = struct.unpack('<Q', S)

    # Grab exponent and mantissa parts using bitmasks.
    # The eight MSBs are exponent; rest mantissa.
    exp, mant = (N&(0xffL<<56))>>56, N&~(0xffL<<56)

    exp -= 0x81 # Exponential part is excess 0x81 (e.g., 0x82 is 1).

    msign = mant & (0x80L<<48) # MSB of mantissa is sign bit. 0==positive.
    if not msign:
        msign = 1
    else:
        msign = -1

    mant |= (0x80L<<48) # Add implied 1 to the MSB of mantissa.

    # Now, binary scientific notation:

    return float(msign * binaryE(mant, exp))






More information about the Python-list mailing list