How to convert 4 byte IEEE (little endian) float binary representation to float
Question: I am decoding a binary file, which has decimal numbers represented by four
bytes, little endian. For example, `94 53 F0 40` represents 7.510202.
Unfortunately, Python is giving me 7.51020240784.

When I try to parse this data using `unpack("<f",sampledata)[0]` I don't get
exact representations of the original, due to the way Python stores values
(for more information, see <http://bugs.python.org/issue4114>).

Unfortunately, I _do_ need to get the _exact_ same representation- regardless
of discussions about the inaccuray of floats, because I need to write these
values to a text file, with the same number of decimal places as they were
initially written to the binary file with.

I'd rather stick to Python if possible, but am happy to implement a solution
in C if necessary. The reason I cannot simply truncate the return of the
unpack function, is that I cannot guarantee how many decimal places the
original float had, for example `0C 02 0F 41` represents 8.938 according to my
hex editor, from the original binary file, which only has 3 decimal places.

To be clear, I need to take four hex bytes as my input, and output either a
text/ASCII or number representation of the IEEE 32-bit floating point number,
that has the same number of decimal places as was intended by the creator of
the file. The output I will use to create a CSV of the original binary data
file, not for actually performing any calculations.

Any suggestions?

Example:

    
    
    from __future__ import print_function
    from struct import *
    
    print("Should print 7.510202")
    
    hexbytes = b"\x94\x53\xF0\x40"
    
    # 01101001 11001000 11110001 01000000
    # should print 7.510202
    
    print(unpack("<f",hexbytes)[0])
    


Answer: A 4-byte IEEE format floating point number holds approximately 7 digits. What
you want to do is round the result of `unpack` to a total of 7 digits. From
there the normal Python conversion from float to string will hide all the
floating point nastiness from you.

    
    
    def magnitude(x):
        return 0 if x==0 else int(math.floor(math.log10(abs(x)))) + 1
    
    def round_total_digits(x, digits=7):
        return round(x, digits - magnitude(x))
    
    >>> round_total_digits(struct.unpack('<f', '\x94\x53\xF0\x40')[0])
    7.510202
    >>> round_total_digits(struct.unpack('<f', '\x0C\x02\x0F\x41')[0])
    8.938
    >>> x = struct.unpack('<f', struct.pack('<f', 12345.67))[0]
    >>> x
    12345.669921875
    >>> round_total_digits(x)
    12345.67
    

Note that if your numbers did not originate from a direct conversion of a
decimal number but were the result of a calculation, this could _reduce_ the
total accuracy. But not by much.

