How to covert 4 bytes to float?

I have 4 bytes coming from serial want to convert to float variable

could you please help me?

Thanks in Advance

uint8_t bytes[4] = { 0, 1, 2, 3 }; // fill this array with the four bytes you received
static_assert(sizeof(float) == 4, "float size is expected to be 4 bytes");
float f;
memcpy (&f, bytes, 4);

Pieter

void loop()
{
uint8_t bytes[4] = {0X81,0X11,0X99,0X9A}; // fill this array with the four bytes you received
static_assert(sizeof(float) == 4, "float size is expected to be 4 bytes");
float f;
memcpy (&f, bytes, 4);
Serial.println(f);
delay(1000);
}

the result is -0.00

it must be as 4.55

1 Like

Try the following codes with permissible value for the highest byte of the 4-byte data, which must agree with the template of IEEE-754 Standards (Fig-1).

void setup()
{
  Serial.begin(9600);
  uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X41}; //{0X81, 0X11, 0X99, 0X9A}; //
  long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
  union
  {
    long y;
    float z;
  }data;
  data.y = x;
  Serial.println(data.z,2);   //shows: 19.13
}

void loop() 
{

}

IEEE-754/binary32 Template for 32-bit Floating Point Number:


Figure-1:

1 Like
long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];

For safety, I'd always use "unsigned long" for the cast.

TheMemberFormerlyKnownAsAWOL:

long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];

For safety, I'd always use "unsigned long" for the cast.

Thanks! I have noted it down.

I am using this value :

uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X9A};

the result is -0.00

it is not correct

GolamMostafa:

void setup()

{
  Serial.begin(9600);
  uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X41}; //{0X81, 0X11, 0X99, 0X9A}; //
  long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
  union
  {
    long y;
    float z;
  }data;
  data.y = x;
  Serial.println(data.z,2);  //shows: 19.13
}

void loop()
{

}

Your code invokes undefined behavior. Using a union for type punning is not allowed:

C++ Core Guidelines: Don't use a union for type punning

float value 4.55 equal in HEX 0X81 0X11 0X99 0X9A

void setup()
{
  Serial.begin(2400);
  uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X9A};
  long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
  union
  {
    long y;
    float z;
  }data;
  data.y = x;
  Serial.println(data.z,2);   //shows: -0.00
}

void loop()
{

}

but the result I got is not correct -0.00

void setup() 
{
  Serial.begin (115200);
  float x = 4.55;
  const byte* px = (byte*) &x;
  
  Serial.print (F("Raw: ")); 
  Serial.println (x, 3);

  for (int i = 0; i < 4; i++) {
    Serial.print (F("Hex [")); 
    Serial.print (i);
    Serial.print (F("] = 0x"));
    if (px[i] < 16)
      Serial.print (0);
    Serial.println (px[i], HEX);
  }

  byte floatVal [4] = {0x9A, 0x99, 0x91, 0x40};
  float y;
  uint32_t* const py = (uint32_t*) &y;

  *py = ((uint32_t) floatVal [3] << 24) |
        ((uint32_t) floatVal [2] << 16) |
        ((uint32_t) floatVal [1] << 8) |
        ((uint32_t) floatVal [0] << 0);

  Serial.print (F("Reconstituted: ")); 
  Serial.println (y, 3);
}

void loop() 
{
}

Eleckits:
float value 4.55 equal in HEX 0X81 0X11 0X99 0X9A

No it's not. 4.55 as a 32-bit IEEE754 floating point number is 0x4091999a.
Also mind the Endianness.

Eleckits:

void setup()

{
 Serial.begin(2400);
 uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X9A};
 long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
 union
 {
   long y;
   float z;
 }data;
 data.y = x;
 Serial.println(data.z,2);   //shows: -0.00
}

void loop()
{

}




but the result I got is not correct -0.00

Don't use unions to convert from a long to a float, as mentioned above. Use memcpy instead.

TheMemberFormerlyKnownAsAWOL:

  float y;

uint32_t* const py = (uint32_t*) &y;

*py = ((uint32_t) floatVal [3] << 24) |
        ((uint32_t) floatVal [2] << 16) |
        ((uint32_t) floatVal [1] << 8) |
        ((uint32_t) floatVal [0] << 0);

This isn't any better than using a union. It still breaks the strict aliasing rule.
y is a float, you cannot alias it with a uint32 pointer.

PieterP:
This isn't any better than using a union. It still breaks the strict aliasing rule.
y is a float, you cannot alias it with a uint32 pointer.

Can you break it?

TheMemberFormerlyKnownAsAWOL:
Can you break it?

No. It's undefined behavior. I've been bitten by this before, everything worked in debug mode, but when enabling optimizations, I got invalid results. Adding print statements around it changed the outcome of the program entirely.

Here's an in-depth explanation: What is Strict Aliasing and Why do we Care? · GitHub

@TheMemberFormerlyKnownAsAWOL

the hex value of 4.55 is : 0X81 0X11 0X99 0X9A

![](http://C:\Users\hitro\Pictures\Ashampoo Snap 9\float to hex.png)

is there any mistake?

Eleckits:
@TheMemberFormerlyKnownAsAWOL

the hex value of 4.55 is : 0X81 0X11 0X99 0X9A

[img]http://C:\Users\hitro\Pictures\Ashampoo Snap 9\float to hex.png[/img]

is there any mistake?

The number you mention is
-6.33076×10-23 (Little Endian) or -2.67425×10-38 (Big Endian). Where did you get the number from?

Linking to images on your local hard drive won't work.

No mistake, just a misunderstanding (on your part) of endianess.
And sign bits.

PieterP:
It still breaks the strict aliasing rule.

It isn't a very strict "strict rule", is it? :smiley:

Eleckits:
I am using this value :

uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X9A};

the result is -0.00

it is not correct

No. -0.00 is the correct result. Let us see that this is indeed correct (considering little endianess).

From Fig-1 of Post#3, the float value for your 4-byte data:
9A991181 (1 00110101 00110010001000110000001)

==> (-1)1*(1+ Si=1 to 23*b23-i*2-i)*2e-127
==> -1 (1+ Si=1 to 23*b23-i*2-i)*200110101 - 127
==> -1 (1+Si=1 to 23*b23-i*2-i)*2-74
==> -1 (1+Si=1 to 23*b23-i*2-i) 1/274
==> -1 (1+Si=1 to 23*b23-i*2-i)*0.00000000000..........
==> -0.00

this is the code from proton pic basic it is sending float value 4.55 via serial then I see it on LCD as Hex as :

9A991181

Dim SerData As Float 

Main:
SerOut PORTA.2, 396, [SerData]
SerData = 4.55
Print At 1,1, Hex SerData 
DelayMS 2000
Cls
GoTo Main

so could you please tell me what is the problem?