Search code examples
mathfloating-pointbinaryieee-754

Is there a way to find what kind of Floating-point arithmetic is used


I have this binary number 11000000110011000001011001111101 which should have this decimal representation 0.0736327171325684.

Is there a smart way to figure out how to interpret the binary value as the given decimal value?

Some background

I have a binary file which contain REAL*4 datatype from fortran (I believe fortfran 77). I found this from the fortran language reference:

A REAL element has a sign bit, an 8-bit exponent, and a 23-bit fraction. These REAL elements in f77 conform to the IEEE standard.

Though, trying to apply the IEEE standard i get this decimal value -6.37774515152, which is incorrect. I've been experimenting with big/little-endian and 64-bit. I also tried every offset in my binary data to make sure I wasn't looking at the wrong place, but no luck (closest I could get was still 0.011872760951519054 of, which I believe would be much larger than a precision error).

UPDATE: I'm sorry if this was unclear: I don't have the original fortran code that generated the binary file.

Some extra information that might be helpful:

  • The code is about 20 years old.
  • From code in the same project I found mentions of conversion between IEEE and microsoft binary format.
  • I also found mentions of REAL*4 which should be an alias for REAL according to the language reference.
  • I have successfully decoded the type INTEGER and INTEGER2 from the same file. The INTEGER type is an 8-bit integer. The INTEGER2 type is an 16-bit integer with little endianness. Could this be a hint that the REAL*4 is also little endian?
  • As pointed out in the comments the reference linked above is to a compiler for fortran, and we can't be sure that the code that generated the binary used the same compiler. Therefore it's possible that the REAL*4 type isn't using the IEEE standard at all.

Solution

  • This is quite an exercise in reverse-engineering. It appears your number is in little-endian, and it's stored in the so-called Microsoft binary format. According to wikipedia, this format first stores the 8-bit exponent, with a bias of 128; then 1-bit sign, and then the 23-bit significand, with an implicit 1. If the exponent is 0, the number itself represents 0. The binary point is assumed to be before the entire significand. This format does not have representations for infinity or NaN values, nor it supports subnormals.

    Let's follow this description. The input you have is

    11000000110011000001011001111101
    

    which, in HEX is:

    C0 CC 16 7D
    

    Converting from little-endian, the bit pattern is:

    7D 16 CC C0
    

    Back to binary, and laid out in the 8-1-23 formation, we get:

    01111101 0 00101101100110011000000
    

    The value of the stored exponent is 0b01111101, which is 125 in decimal. The bias in this format is 128; so we have an exponent value of -3.

    The sign is 0, so it's a positive number.

    The significand has an implicit one, and the radix point is assumed to be before the whole significand. So it is: 0.100101101100110011000000 in binary. Which corresponds to:

    2^-1 + 2^-4 + 2^-6 + 2^-7 + 2^-9 + 2^-10 + 2^-13 + 2^-14 + 2^-17 + 2^-18
    

    The final value, then, is:

    2^-3 * (2^-1 + 2^-4 + 2^-6 + 2^-7 + 2^-9 + 2^-10 + 2^-13 + 2^-14 + 2^-17 + 2^-18)
    

    which evaluates mathematically (i.e., without any rounding/truncation) to:

    0.07363271713256836
    

    which I believe is the value you were looking for in the first place.