machine424
machine424

Reputation: 155

Convert Bytes to Floating Point Numbers WITHOUT using STRUCT

I'm trying to write my "personal"(without using any modules or functions : struct,float....,int....,...) python version of STL binary file reader, according to WIKIPEDIA : A binary STL file contains :

--Floating-point numbers are represented as IEEE floating-point numbers and are assumed to be little-endian--

With the help of two saviors I discovered how unsigned integers are stored, I can figure out the number of triangular facets in the file with 3 methods (computed by hand ) :

def int_from_bytes(inbytes): # ShadowRanger's
     res = 0
     for i, b in enumerate(inbytes):
         res |= b << (i * 8)  
     return res

or

def int_from_bytes(inbytes): # ShadowRanger's
    res = 0
    for b in inbytes:
        res <<= 8  # Adjust bytes seen so far to make room for new byte
        res |= b   # Mask in new byte
    return res

or

def unsigned_int(s): # Robᵩ's
    result = 0
    for ch in s[::-1]:
        result *= 256
        result += ch
    return result

Now I have to convert the rest of the file (3rd item in the list):Floating-point numbers

for the first point the 50-bytes are :

b'\x9a'b'\xa3' b'\x14' b'\xbe' b'\x05' b'$' b'\x85' b'\xbe' b'N' b'b'  
b't' b'?' b'\xcd' b'\xa6' b'\x04' b'\xc4' b'\xfb' b';' b'\xd4' b'\xc1' 
b'\x84' b'w' b'\x81' b'A' b'\xcd' b'\xa6' b'\x04' b'\xc4' b'\xa5' b'\x15' 
b'\xd3' b'\xc1' b'\xb2' b'\xc7' b'\x81' b'A' b'\xef' b'\xa6' b'\x04' 
b'\xc4' b'\x81' b'\x14' b'\xd3' b'\xc1' b'Y' b'\xc7' b'\x81' b'A' b'\x00' 
b'\x00' 

How can I convert this by hand, What is the principle of the representation, what rules should I know to do the conversion by hand (some bytes don't start with \x ). ?

Thank you for your time.

Upvotes: 0

Views: 1415

Answers (1)

Matt Timmermans
Matt Timmermans

Reputation: 59174

Like this:

def int_from_bytes(inbytes):
    res = 0
    shft = 0
    for b in inbytes:
        res |= ord(b) << shft
        shft += 8
    return res

def float_from_bytes(inbytes):
    bits = int_from_bytes(inbytes)
    mantissa = ((bits&8388607)/8388608.0)
    exponent = (bits>>23)&255
    sign = 1.0 if bits>>31 ==0 else -1.0
    if exponent != 0:
        mantissa+=1.0
    elif mantissa==0.0:
        return sign*0.0
    return sign*pow(2.0,exponent-127)*mantissa


print float_from_bytes('\x9a\xa3\x14\xbe')
print float_from_bytes('\x00\x00\x00\x40')
print float_from_bytes('\x00\x00\xC0\xbf')

output:

-0.145155340433
2.0
-1.5

The format is IEEE-754 floating point. Try this out to see what each bit means: https://www.h-schmidt.net/FloatConverter/IEEE754.html

Upvotes: 2

Related Questions