Convert IEEE 754 32 to float

Working on a project where I am receiving a 32bit packet from a device over I2C.

I am using an Arduino pro-mini

the 32 bit long is in the IEEE 754 32 bit floating point format.

How do I go about turning that into a standard float?

Example, data in (HEX) 3F322E3F (data read from device)
I want to convert it to (DEC) 0.6960186 ( may not need 7 digits past the decimal, I know Arduino is limited in this regard 3 or 4 is adequate)

I have looked at it and it gets complicated..... Wondering if any of the gurus here could point me in the right direction or maybe even give an example.

Thanks

I think it is already a float....

You do realise, that all numbers in the computer are binary numbers ?

The limit on the resolution of floating point numbers, is "about" 7 signficant digits in total - not just "beyond the decimal point". This is not a limitation of arduinos, it is a limitation of the precision of 32 bit floating point numbers, on any platform.

You will need something like this code ( not tested )

union 
{      byte b[4] ;
        float f ;'
} u ;


int j=0 ;
if ( Serial.available() >= 4 )
{
     for ( j=0 ; j<4 ; j++ )  u.b[j] = (byte) Serial.read() ;
}

Serial.println( u.f ) ;

What you are doing here , is writing your four data bytes into a piece of memory that is also shared with a float variable, and then accessing the data as a float.

This would work on the same principle

union
{   
    unsigned long a ;
    float b ;
} u ;

u.a=0x3F322E3F ;

Serial.println( u.b ) ;

@ michinyon,

You do realise, that all numbers in the computer are binary numbers ?

Thanks, yes i do realize that. The issue is that the 32 bit packet I am receiving from the target device is not directly converted to a float, or at least the float i need. Hence the "IEEE 754 32 bit floating point" designator in the thread title.

to illistrate : the example packet (brought into the arduino pro-mini as an unsigned long)

3f322e3f(hex) directly translates to 1060253247(DEC), it is clearly not a float and is clearly not simply dividable
to get the intended 0.6960186 result i need.

I am just now leaning about the "IEEE 754" standard, so please forgive me if i get this wrong, but with 32bit floating point numbers, the MSB (bit 31) is a sign bit indicating a positive or negative number, the next 7 bits are the exponent, and the remaining 24 bits are what is called the Mantissa.

the sign bit is easy, 1 is a negative and 0 is a positive, the tricky part is the exponent and the Mantissa, these two determine the number as well as the decimal place, that is why 3f322e3f (IEE 754) is 0.696018, not 106025347.

I have researched a little and there are a few videos/web pages on how to do the conversion on paper, using multiple binary and base 10 calculations to calculate the correct digits and decimal place, however i have yet to find anything on how to do this in a program. Parsing the Data is not terribly hard with bit shift commands, however applying the proper maths to obtain the correct result for any given 32 bit string is something completely different, witch is why i posted. I can hope with enough trial and error i can probably figure it out, but as this is a standard in the computer world, i was hoping not to have to re-invent the wheel and that more savvy programmers had already tackled the issue.

I will try the code you offered ( thanks ) but on the surface it looks to me as though it will simply generate 1060253247.000xxxxxx.

An Arduino "float" is already in IEEE-754 format.
There really is no need to perform any explicit conversion, just make sure you have any endian issues correct.

uint32_t x = 0x3f322e3f;
float y = *(float*)&x;
Serial.print (y, 6);

The issue is that the 32 bit packet I am receiving from the target device is not directly converted to a float, or at least the float i need. Hence the "IEEE 754 32 bit floating point" designator in the thread title.

to illistrate : the example packet (brought into the arduino pro-mini as an unsigned long)

3f322e3f(hex) directly translates to 1060253247(DEC), it is clearly not a float and is clearly not simply dividable
to get the intended 0.6960186 result i need.

I have researched a little

You obviously haven't.

You are spouting complete nonsense.

it is clearly not a float

It clearly IS a float.

0x3f322e3f is a 32 bit number.

0011 1111 0011 0010 0010 1110 0011 1111

The first bit is the sign bit 0. means positive

The next 8 bits are the exponent 0111 1110 = 7E hex = 126 decimal from which you subtract 127 to get -1

The next 23 bits is the mantissa. 0100 0101 1100 0111 111
You add a one to the most significant bit of this.

Then you start addiing up the fractions.

Then you multiply 2**-1 to get the answer.

It's a floating point number.

Read this Single-precision floating-point format - Wikipedia

Almost any time you see a 4-byte data item starting with 3F or 3E, it is probably a float.

michinyon:
Almost any time you see a 4-byte data item starting with 3F or 3E, it is probably a float.

?Wtf

(0x3f577466)

The next 23 bits is the mantissa. 0100 0101 1100 0111 111
You add a one to the most significant bit of this.

Just to prove I am not making this up, the value you have here is

1 + (0 x 1/2 ) + ( 1 x 1/4 ) + ( 0 x 1/8 ) + ( 0 x 1/16 ) + ( 0 x 1/32 ) + ( 1 x 1/64 ) + ( 0 x 1/128 ) + ( 1 x 1/256 ) + ( 1 / 512 )

( i am going to leave the rest out )

which is 1.271484375

Which has to be multiplied by 0.5 because of the exponent, 126

which is 0.635742

Are you sure it is supposed to be 0.69 whatever ?

Are you sure it is supposed to be 0.69 whatever ?

My Xeon sees 0x3f322e3f as 0.6960181.

I think your arithmetic is off.

The suggested methods in reply #2, #3 and #5 are all basically the same thing.

Potentially, with some device you might need to reverse the order of the bytes, in which case you would use method in reply #2, but put the bytes into the array b[4] in the reverse order.

3f322e3f

Let me try that again

0011 1111 0011 0010 0010 1110 0011 1111

Sign bit 0

Exponent 0111 1110 = 7E = 126 subtract 127 = -1

Mantissa = 011 0010 0010 1110 0011 1111 23 bits. Add 1 in most signficant position, get 24 bits

which are 1011 0010 0010 1110 0011 1111

Result = 1

  • 1/4
  • 1/8
  • 1/64
  • 1/1024
  • 1/4096
  • 1/8192
  • 1/16384 + very small numbers

1.39202880

multiply by 0.5 because the exponent was 126

0.6960144

however i have yet to find anything on how to do this in a program.

You almost never have to do this in a program.

I've only done it three times, and they were quite a long time ago.

joey120373:
Example, data in (HEX) 3F322E3F (data read from device)
I want to convert it to (DEC) 0.6960186 ( may not need 7 digits past the decimal, I know Arduino is limited in this regard 3 or 4 is adequate)

I have looked at it and it gets complicated..... Wondering if any of the gurus here could point me in the right direction or maybe even give an example.

I have looked at it and it seems to be easy.

The only skill needed is handling an array index in the range from zero up to three.

Example code:

void setup() {
  Serial.begin(9600);
  float x;
  ((byte*)&x)[3]= 0x3F;
  ((byte*)&x)[2]= 0x32;
  ((byte*)&x)[1]= 0x2E;
  ((byte*)&x)[0]= 0x3F;
  Serial.println(x,7);
}

void loop() {
}

OK?

1 Like

Your method will probably create the wrong result. Aren't you putting the bytes together in the wrong order ?

michinyon:
Your method will probably create the wrong result. Aren't you putting the bytes together in the wrong order ?

The byte order is platform dependent. Each platform might be either using

So perhaps when transferring bytes from one system to another system which are providing a different endianess, the bytes possibly needs to be changed: The byte order may be the same or the byte order may be reversed, or the highword may be mixed with the loword.

The example code I posted handles each byte seperately, so its easy to mix the byte order as needed. Just as the sending platform provides the bytes, you could use:

  ((byte*)&x)[3]= 0x3F;
  ((byte*)&x)[2]= 0x32;
  ((byte*)&x)[1]= 0x2E;
  ((byte*)&x)[0]= 0x3F;

or

  ((byte*)&x)[0]= 0x3F;
  ((byte*)&x)[1]= 0x32;
  ((byte*)&x)[2]= 0x2E;
  ((byte*)&x)[3]= 0x3F;

or

  ((byte*)&x)[2]= 0x3F;
  ((byte*)&x)[3]= 0x32;
  ((byte*)&x)[0]= 0x2E;
  ((byte*)&x)[1]= 0x3F;

Or as the transfer between different platforms requires.

So while the 4 bytes of a float are defined by IEEE 754, the byte order is defined by the computer platform. So byte order may be different for sender and receiver. Should be easy to find out when sending a known float value.

Did you bother to read any of the other posts in this thread ?

The OP has already posted the long value he is getting, and we have demonsrated that, contrary to OP's belief, it IS a float and DOES represent the float value he expects.

Your code in reply #14 is ** wrong ** for this OP's application.

@ michinyon,

You are correct, I did not research this as much as I needed to obviously, I did however do some research on the IEEE 754 format, with his led me to several pages on how to do the math conversions, the same ones you have provided.

Last night I did eventually find that Arduino uses the IEEE 754, my bad.

I want to thank you for all of the help you have provided I spite of my ignorance.

reminds me of some things I did a while ago - Arduino Playground - IEEE754tools -