How to convert Hex to IEEE 754 32 bit float in C++

0

I am trying to convert hex values stored as int and convert them to floatting point numbers using the IEEE 32 bit rules. I am specifically struggling with getting the right values for the mantissa and exponent. The hex is stored from in a file in hex. I want to have four significant figures to it. Below is my code.

float floatizeMe(unsigned int myNumba ) {
    //// myNumba comes in as 32 bits or 8 byte  

    unsigned int  sign = (myNumba & 0x007fffff) >>31;
    unsigned int  exponent = ((myNumba & 0x7f800000) >> 23)- 0x7F;
    unsigned int  mantissa = (myNumba & 0x007fffff) ;
    float  value = 0;
    float mantissa2; 

    cout << endl<< "mantissa is : " << dec << mantissa << endl;

    unsigned    int m1 = mantissa & 0x00400000 >> 23;
    unsigned    int m2 = mantissa & 0x00200000 >> 22;
    unsigned    int m3 = mantissa & 0x00080000 >> 21;
    unsigned    int m4 = mantissa & 0x00040000 >> 20;

    mantissa2 = m1 * (2 ^ -1) + m2*(2 ^ -2) + m3*(2 ^ -3) + m4*(2 ^ -4);

    cout << "\nsign is: " << dec << sign << endl;
    cout << "exponent is : " << dec << exponent << endl;
    cout << "mantissa  2 is : " << dec << mantissa2 << endl;

    // if above this number it is negative 
    if ( sign  == 1)
        sign = -1; 

    // if above this number it is positive 
    else {
        sign = 1;
    }

    value = (-1^sign) * (1+mantissa2) * (2 ^ exponent);
    cout << dec << "Float value is: " << value << "\n\n\n";

    return value;
}




  int main()
{   
    ifstream myfile("input.txt");
    if (myfile.is_open())
    {
        unsigned int a, b,b1; // Hex 
        float c, d, e; // Dec
        int choice; 

        unsigned int ex1 = 0;
        unsigned int ex2 = 1;
        myfile >> std::hex;
        myfile >> a >> b ;
        floatizeMe(a);
myfile.close();
return 0;

}

c++
c
floating-point
ieee-754
asked on Stack Overflow Apr 30, 2016 by Sam Arnold

6 Answers

4

I suspect you mean for the ^ in

mantissa2 = m1 * (2 ^ -1) + m2*(2 ^ -2) + m3*(2 ^ -3) + m4*(2 ^ -4);

to mean "to the power of". There is no such operator in C or C++. The ^ operator is the bit-wise XOR operator.

answered on Stack Overflow Apr 30, 2016 by Jfevold
3

Considering your CPU follows the IEEE standard, you can also use union. Something like this

  union
  {
    int num;
    float fnum;
  } my_union;

Then store the integer values into my_union.num and read them as float by getting my_union.fnum.

answered on Stack Overflow Apr 30, 2016 by polfosol ఠ_ఠ
2

We needed to convert IEEE-754 single and double precision numbers (using 32bit and 64bit encoding). We were using a C compiler (Vector CANoe/Canalyzer CAPL Script) with a restricted set of functions and ended up developing the function below (it can easily be tested using any on-line C compiler):

#include <stdio.h>
#include <math.h>

double ConvertNumberToFloat(unsigned long number, int isDoublePrecision)
{
    int mantissaShift = isDoublePrecision ? 52 : 23;
    unsigned long exponentMask = isDoublePrecision ? 0x7FF0000000000000 : 0x7f800000;
    int bias = isDoublePrecision ? 1023 : 127;
    int signShift = isDoublePrecision ? 63 : 31;

    int sign = (number >> signShift) & 0x01;
    int exponent = ((number & exponentMask) >> mantissaShift) - bias;

    int power = -1;
    double total = 0.0;
    for ( int i = 0; i < mantissaShift; i++ )
    {
        int calc = (number >> (mantissaShift-i-1)) & 0x01;
        total += calc * pow(2.0, power);
        power--;
    }
    double value = (sign ? -1 : 1) * pow(2.0, exponent) * (total + 1.0);

    return value;
}

int main()
{
    // Single Precision 
    unsigned int singleValue = 0x40490FDB; // 3.141592...
    float singlePrecision = (float)ConvertNumberToFloat(singleValue, 0);
    printf("IEEE754 Single (from 32bit 0x%08X): %.7f\n",singleValue,singlePrecision);

    // Double Precision
    unsigned long doubleValue = 0x400921FB54442D18; // 3.141592653589793... 
    double doublePrecision = ConvertNumberToFloat(doubleValue, 1);
    printf("IEEE754 Double (from 64bit 0x%016lX): %.16f\n",doubleValue,doublePrecision);
}
answered on Stack Overflow Nov 6, 2018 by Ken • edited Sep 10, 2019 by Ken
0

There are a number of very basic errors in your code.

The most visible is repeatedly using ^ for "power of". ^ is the XOR-operator, and for "power" you must use the function pow(base, exponent) in math.h.

Next, "I want to have four significant figures" (presumably for the mantissa), but you only extract four bits. Four bits can encode only 0..15, which is about a digit-and-a-half. To get four significant digits, you'd need at least log(10,000)/log(2) ≈ 13.288, or at least 14 bits (but preferably 17, so you get one full extra digit to get better rounding).

You extract the wrong bit for sign, and then you use it the wrong way. Yes, if it is 0 then sign = 1 and if 1 then sign = -1, but you use it in the final calculation as

value = (-1^sign) * ...

(again with a ^, although even pow does not make any sense here). You ought to have used sign * .. straight away.

exponent was declared an unsigned int, but that fails for negative values. It needs to be signed for pow(2, exponent) (corrected from your (2 ^ exponent)).

On the positive side, (1+mantissa2) is indeed correct.

With all of those points taken together, and ignoring the fact that you actually ask for only 4 significant digits, I get the following code. Note that I rearranged the initial bit shifting and extracting for convenience – I shift mantissa to the left, rather than the right, so I can test against 0 in its calculation.

(Ah, I missed this!) Using sign straight away does not work because it was declared as an unsigned int. Therefore, where you think you give it the value -1, it actually gets the value 4294967295 (more precise: the value of UINT_MAX from limits.h).

The easiest way to get rid of this is not multiplying by sign but only test it, and negate value if it is set.

float floatizeMe (unsigned int myNumba )
{
    //// myNumba comes in as 32 bits or 8 byte  

    unsigned int  sign = myNumba >>31;
    signed int  exponent = ((myNumba >> 23) & 0xff) - 0x7F;
    unsigned int  mantissa = myNumba << 9;
    float  value = 0;
    float mantissa2;

    cout << endl << "input is : " << hex << myNumba << endl;
    cout << endl << "mantissa is : " << hex << mantissa << endl;

    value = 0.5f;
    mantissa2 = 0.0f;
    while (mantissa)
    {
        if (mantissa & 0x80000000)
            mantissa2 += value;
        mantissa <<= 1;
        value *= 0.5f;
    }

    cout << "\nsign is: " << sign << endl;
    cout << "exponent is : " << hex << exponent << endl;
    cout << "mantissa 2 is : " << mantissa2 << endl;

    /* REMOVE:
       if above this number it is negative 
    if ( sign  == 1)
        sign = -1; 

    // if above this number it is positive 
    else {
        sign = 1;
    } */

    /* value = sign * (1.0f + mantissa2) * (pow (2, exponent)); */
    value = (1.0f + mantissa2) * (pow (2, exponent));
    if (sign) value = -value;
    cout << dec << "Float value is: " << value << "\n\n\n";

    return value;
}

With the above, you get correct results for values such as 0x3e4ccccd (0.2000000030) and 0x40490FDB (3.1415927410).

All said and done, if your input is already in IEEE-754 format (albeit in hex), then a simple cast ought to be enough.

answered on Stack Overflow Apr 30, 2016 by Jongware • edited May 1, 2016 by Jongware
0

Just do the following (but of course make sure you have the right endianness when reading bytes into the integer in the first place):

float int_bits_to_float(int32_t ieee754_bits) {
    float flt;
    *((int*) &flt) = ieee754_bits;
    return flt;
}

Works for me... this of course assumes that float has 32 bits, and is in IEEE754 format, on your architecture (which is almost always the case).

answered on Stack Overflow Aug 16, 2019 by Luke Hutchison
-1

As well as being much simpler, this also avoids any rounding/precision errors.

float value = reinterpret_cast<float&>(myNumba)

If you still want to inspect the parts separately, use the library function std::frexp afterwards. Of if you don't like the type punning, at least use std::ldexp to apply the exponent rather than your explicit maths, which is vulnerable to rounding/precision errors and overflow.

An alternate to both of these is to use a union type, as described in this answer.

answered on Stack Overflow Apr 30, 2016 by OrangeDog • edited May 23, 2017 by Community

User contributions licensed under CC BY-SA 3.0