Go Down

Topic: Convert IEEE 754 32 to float (Read 11712 times) previous topic - next topic

joey120373

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

michinyon

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.

michinyon

You will need something like this code ( not tested )
Code: [Select]

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.

michinyon

This would work on the same principle

Code: [Select]


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

u.a=0x3F322E3F ;

Serial.println( u.b ) ;




joey120373

@ michinyon,

Quote
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.

AWOL

#5
Jul 10, 2015, 08:44 am Last Edit: Jul 10, 2015, 09:26 am by AWOL
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.

Code: [Select]
uint32_t x = 0x3f322e3f;
float y = *(float*)&x;
Serial.print (y, 6);

michinyon

Quote
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.
Quote
I have researched a little
You obviously haven't.

You are spouting complete nonsense.

Quote
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 https://en.wikipedia.org/wiki/Single-precision_floating-point_format







michinyon

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

AWOL

#8
Jul 10, 2015, 11:19 am Last Edit: Jul 10, 2015, 11:20 am by AWOL
Almost any time you see a 4-byte data item starting with 3F or 3E,   it is probably a float.
?Wtf

(0x3f577466)

michinyon

Quote
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 ?

AWOL

Quote
Are you sure it is supposed to be 0.69 whatever ?
My Xeon sees 0x3f322e3f as 0.6960181.

I think your arithmetic is off.

michinyon

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.

michinyon

Quote
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






michinyon

Quote
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.


jurs

#14
Jul 10, 2015, 12:50 pm Last Edit: Jul 10, 2015, 12:51 pm by jurs
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:
Code: [Select]

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?

Go Up