Converting IBM Floats..Help..

Anton Vredegoor anton at vredegoor.doge.nl
Fri Mar 26 06:35:00 EST 2004


"Ian Sparks" <Ian.Sparks at etrials.com> wrote:

>I'm trying to read from a file which contains numbers encoded in IBM360 (Big-Endian) Floating point format. The IBM stores its numbers in the following format :
>
>*
>* IBM format:
>* 6       5                 0
>* 3       1                 0
>*
>* SEEEEEEEMMMM ......... MMMM
>*
>* Sign bit, 7 bit exponent, 56 bit fraction. Exponent is
>* excess 64. The fraction is multiplied by a power of 16 of
>* the actual exponent. Normalized floating point numbers are
>* represented with the radix point immediately to the left of
>* the high order hex fraction digit.
>
>I know what's in this file so :
>
> data = list(file.read(8))
> print data
> 
> 155 = ['B', '\x9b', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'] 
>  77 = ['B', 'M', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00']
>   1 = ['A', '\x10', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00']
>   0 = ['\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00']

Some time ago there was a question on this group about 4-bytes IBM
floats, and maybe questions about other formats will follow in the
future. Here's a flexible -but possibly slow?- approach to handle
these kind of problems. It uses a stream of bytes (a file for example)
as input and returns a series of floats.

from itertools import islice

def _bits(i):
    return [('01'[i>>j & 1]) for j in range(8)][::-1] 

_table = dict([(chr(i),_bits(i)) for i in range(256)])

def bitstream(bytes):
    for byte in bytes:
        for bit in _table[byte]:
            yield bit
            
def groupby(gen,sizes):
    while 1:
        for size in sizes:
            yield islice(gen,size)

def tolongs(gen):
    def tolong(x): return long(''.join(x),2)
    for g in gen:
        try: yield map(tolong,g)
        except ValueError: break

def decode(gen):
    for sign, exponent, mantissa in gen:        
        sign = [1,-1][sign] 
        exponent = 16**(exponent & 0x7f -64)
        mantissa = mantissa/float(16**14)
        yield sign*exponent*mantissa
    
def float_decode(bytes):
    bits = bitstream(bytes)       # turn it into a stream of bits
    gb_1 = groupby(bits,[1,7,56]) # make groups of size 1,7 and 56
    gb_2 = groupby(gb_1,[3])      # group again, take 3 at a time
    gl = tolongs(gb_2)            # turn it into groups of three longs
    for f in decode(gl):          # turn 3 longs into a float
        yield f
        
def test():
    bytes = ('B\x9b\x00\x00\x00\x00\x00\x00'
        'BM\x00\x00\x00\x00\x00\x00'
        'A\x10\x00\x00\x00\x00\x00\x00'
        '\x00\x00\x00\x00\x00\x00\x00\x00')
    for f in float_decode(bytes):
        print f

if __name__ == '__main__': 
    test()

output:

155.0
77.0
1.0
0.0

Anton






More information about the Python-list mailing list