What numbers are they? : IEEE 754(Arduino float)

Hi,

I’m wondering what number each byte is in IEEE754(Arduino float). Though I know that float consists of 4byte, I don’t know how they could be expressed in decimal or hex.

Like float pi = 3.141592, could you tell me each byte in decimal or hex.

Also, by containing those numbers in uint32_t data[4], I think I can reconstruct pi as follows. Right?

    float result = (float) (
          (((uint32_t)data[0] << 24) & 0xFF000000)
        | (((uint32_t)data[1] << 16) & 0x00FF0000)
        | (((uint32_t)data[2] <<  8) & 0x0000FF00)
        | (((uint32_t)data[3] <<  0) & 0x000000FF)
    );

Thank you,

Much love

Just try to use a "typedef union" like this, to immediately get how that float is stored ad 4 bytes:

typedef union
{
  float value;
  uint8_t b[4];
} dual_t;

dual_t pi;
void setup() {
  Serial.begin(9600);
  pi.value = 3.141592;
  for(int i=0; i<=3; ++i) {
    if (pi.b[i] < 16) Serial.print("0");
    Serial.print(pi.b[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

void loop() {

}

did the internet break?

1 Like

just like in the other thread:

https://wokwi.com/projects/343234739828687443

your pi will give

3.14
D8 F 49 40 
D8 F 49 40 
3.14

Thank you sir,
but I can not reconstruct pi using my code. Could you tell where is wrong?

   float re_pi = (float) (
          (((uint32_t)0xd8 << 24) & 0xFF000000)
        | (((uint32_t)0x0f << 16) & 0x00FF0000)
        | (((uint32_t)0x49 <<  8) & 0x0000FF00)
        | (((uint32_t)0x40 <<  0) & 0x000000FF)
    );

Actually yes. Thanks

Thank you!
I think [D8 F 49 40 ]simply stand for[ 0xD8 0x0F 0x49 0x40 ].
If I'm not wrong, why could not I get pi again using this code?

   float re_pi = (float) (
          (((uint32_t)0xd8 << 24) & 0xFF000000)
        | (((uint32_t)0x0f << 16) & 0x00FF0000)
        | (((uint32_t)0x49 <<  8) & 0x0000FF00)
        | (((uint32_t)0x40 <<  0) & 0x000000FF)
    );

The value you're building is NOT directly converted to a float as if the 4 bytes representing the value you need. The "or"s you use just build a "long" integer represented internally as 0xD80F4940, and when you try casting it to float it just use that 4 bytes as a whole number, not a float IEEE representation. In fact, that hex value is equivalent to the decimal 3624880448, and the "float" value you get is exactly that one.

If you want to get the original float from 4 bytes, you can use the reverse method I have shown you to get the 4 bytes out of the float:

  // Reconstructing PI from hex values
  pi.b[0] = 0xD8;
  pi.b[1] = 0x0F;
  pi.b[2] = 0x49;
  pi.b[3] = 0x40;
  Serial.println(pi.value, 6);

This is not the only way to do it, but the others involve addresses and pointers, less intuitive and straightforward than this one.

If you search this forum, you'll find many discussions explaining why this invokes undefined behavior in C++.

thank you!!!,
Actually, my aim is to receive 4byte from another device(RPi), and reconstruct it to float value.
So I want the code to reconstruct pi from the 4bytes. Could you give me any tip to make it?

(Resend)

you are shifting 0xd8 by 24 bytes ... but 0xD8 is byte[0] not byte[3]
Furthermore your casts will not work or better - will not do what you need.
See again the wokwi example, there are both lines ... one from float to byte[4], and one from byte[4] to float.
two simple lines ... just with memcpy

Thank you!
I think I could not use the memcpy example cus there is difference between SEEING the content of creceived and RECEIVING values then including into the content of creceived.

//just SEEING
 for (int i = 0; i < 4; i++)
  {
    Serial.print(byte(creceived[i]), HEX);  // what have we got
    Serial.print(' ');
  }
//RECEIVING
creceived[0] =0xD8
creceived[1] = 0x0F
creceived[2] =0x49
creceived[3] =0x40

Just asking ... are you sure floats on an RPI are in fact 4 bytes and they use the same endianness as your target Arduino?

memcpy() is exactly what you need to use. Neither the "union method" nor type punning with a pointer are valid C++ code.

You have to search pretty hard to find anything other than little-endian CPUs, these days.

 40490fd8 s 0 e 01 m c90fd8
 c90fcd
 800000  1   2.00000000   2.00000000
 400000  1   1.00000000   3.00000000
 200000  0   0.50000000   3.00000000
 100000  0   0.25000000   3.00000000
  80000  1   0.12500000   3.12500000
  40000  0   0.06250000   3.12500000
  20000  0   0.03125000   3.12500000
  10000  1   0.01562500   3.14062500
   8000  0   0.00781250   3.14062500
   4000  0   0.00390625   3.14062500
   2000  0   0.00195312   3.14062500
   1000  0   0.00097656   3.14062500
    800  1   0.00048828   3.14111328
    400  1   0.00024414   3.14135742
    200  1   0.00012207   3.14147949
    100  1   0.00006104   3.14154053
     80  1   0.00003052   3.14157104
     40  1   0.00001526   3.14158630
     20  0   0.00000763   3.14158630
     10  1   0.00000381   3.14159012
      8  1   0.00000191   3.14159203
      4  0   0.00000095   3.14159203
      2  0   0.00000048   3.14159203
      1  0   0.00000024   3.14159203
#include <stdio.h>
#include <math.h>

int main ()
{
    unsigned long Val = 0x40490fd8;

    int s = (Val >> 31) & 1;
    int e = ((Val >> 23) & 0xff) - 127;
    int m = (Val & 0x7fffff) + (1 << 23);


    printf (" %x", Val);
    printf (" s %x",   s);
    printf (" e %02x", e);
    printf (" m %06x", m);
    printf ("\n");

    printf (" %06x\n", m + 2^23);

    float f = 0;
    for (int i = 23; 0 <= i; i--)  {
        int   k = 1 << i;
        float d = pow(2, e);
        if (m & k)
            f += pow(2, e);
        printf (" %6x %2d %12.8f %12.8f\n", k, m&k ? 1 : 0, d, f);
        e--;
    }

    return 0;
}
1 Like

Actually, Rpi just sends as follows so I think the transmitter has no problem.
'''
spi.write([0xD8])
spi.write([0x0F])
spi.write([0x49])
spi.write([0x40])
'''

Thank you,
your code seems essential!! Could I use it with 4byte got from another device(Raspi)?,
Like

Raspi

spi.write([0xD8])
spi.write([0x0F])
spi.write([0x49])
spi.write([0x40])

Arduino contain them into uint32_t data[4]

uint32_t data[4]      
//  is equal to [ 216, 15, 73, 64]

Why are you using an array of 4 'uint32_t' to hold just four bytes? Use an array of 4 'uint8_t'.

You're really making this much harder than it needs to be. Again assuming a float on the RPI is 4 bytes just do:

uint8_t data[4];
float f;

void setup() {
  
  //
  // First read 4 bytes from RPI into data array here.
  //

  // Then:
  memcpy(&f, data, 4);
  // DONE!!!

}

void loop() {
}

As I pointed out above, neither the "union method" nor type punning with a pointer are valid C++ code.

intel pentiums? since 8086

No, but apparently Motorola 680x0 is/was:
Endianness - Wikipedia.