Reading floating point numbers

I'm doing some serial communication and sending floating point numbers. I think I have my pointers correct, but don't know how to convert the 4 bytes that have been sent back to a digital floating point number. Is there an app that will take 8 hex numbers and display them in digital?

Alternatively, what is the representation of a floating point number in the C++ in the Arduino? How many bits in the mantissa and how many in the exponent?

For example, I see the bytes as transmitted as 46 BC 42 04, which if the IDE uses little endian, the full floating point hex number would be 0442BC46, which I think is 70.1

Dr.Q

Serial communication between an arduino and what? Your PC? some sensor or widget?

If you are just sending floating point back to your PC, just format it as an ascii string when sending it.

If the arduino is receiving, then you can use a union

union Data
   {
       float floatValue;
       unsigned char Bytes[4];
   }

and then put your received bytes into 'Bytes' in the correct order to achieve your desired floatValue.

The exponent limit for a 4-byte (32 bits) floating point number is e+38. If 6 bits are reserved for the exponent, with one as the sign bit, the remaining 5 bits only get you to +31.

Am I thinking in decimal and missing some magic in getting more precision out of the bits available?

The exponent is 8 bits biased by -127. IEEE 754 single precision floating point summary

Communication is between two Arduinos. I realize I can do the ASCII string thing, or since I'm only interested in numbers from -30.00 to +130.99, I can x100 and send 16-bit integers, then convert back to FP in the receiving unit.

But I'd much rather do the "union" thing and use pointers to send the 4 bytes and then stick them back together with pointers in the receiving unit.

As an aside, a billion years ago I made my own floating point algorithms for a Z-80, which had two sets of swappable registers. It was fast, but precision was limited by the number of bits in each FP number. But I knew exactly which bits did what.

I've looked all over the web for a depiction of the bit assignments for an FP in the Arduino and I can't find one.

Dr.Q

I'd much rather do the "union" thing

That works fine, although you might be chastised by the C++ priests. Pointers work too.

Mr Remington,

:slight_smile: :slight_smile: :slight_smile: :slight_smile: I knew I was missing the obvious, eg, 10exp38 is 2exp127, or nearly so.

Thanks, 8 bits it is, in twos compliment.

Dr.Q

I am 80% sure the Arduino uses IEEE floating-point format. Technically it is the compiler and not the chip. The 8-bit Arduinos have no hardware support for floating point.

It is a very interesting format, suitable for a wide variety of calculations. There are a few "magic" numbers such as zero and NaN (not a number) which are useful to know about.

Dr_Quark:
I've looked all over the web for a depiction of the bit assignments for an FP in the Arduino and I can't find one.

Arduino UNO contains the ATmega328P MCU which does not contain 'Floating Point Unit (FPU)' hardware like the 80486 which contains a FPU to accelerate numeric calculation. When we declare a variable like this: float x = 0.15625;, the compiler consults the following template of Fig-1 known as IEEE-754/binary32 Standard to compute a 32-bit pattern (in hex it is: 0x3E200000) for the number 0.15625; the value is saved into four consecutive memory locations in little endianess (Fig-2, lower byte is stored in lower memory location). To see the details of manual calculation on how to arrive at the given bit pattern, please see attached file.

ieee754.png

ieee754-2.png
Figure-1:

ieee754-3.png
Figure-2:

Codes : (to pint the content of Fig-2);

unsigned lon *ptr;
ptr = (unsigned long*) &x;
unsigned long m = *ptr;
Serial.print(m. HEX);  //shows: 3E200000

ieee754.png

ieee754.pdf (197 KB)

ieee754-2.png

ieee754-3.png

Golam..., thanks, this is just what I was looking for. I find it a little odd, however, that the mantissa sign bit is separated from the unsigned part and that the exponent isn't signed (it must be, but from the graphics it appears to be "signed" by the -127 offset, which I interpret to be two's compliment).

Dr.Q

It's called "excess 127" format (amongst other things)
Useful search term.

If you are passing the four raw bytes of a float between machines that share a floating point format - two Arduinos for instance, you can simply reassemble them into a float using pointers and casting. In such an instance, the detail of what makes up the float representation is irrelevant.

If the machines don't share the same format, I'd be inclined to pass the numbers as text, although there may be simple endian issues that you can fix by swapping the byte order.

//union
union uFloatToByte 
{
    float   fVal;
    unsigned char bArray[sizeof(float)];
};

uFloatToByte V;

//cast
unsigned char chArray[4] = { 0x33, 0x33, 0x8c, 0x42 };    
float *fPtr;

void setup() 
{
    Serial.begin(9600);

    //cast approach
    Serial.print( "Cast approach: " );
    fPtr = (float *)chArray;
    Serial.println( *fPtr );

    //union approach
    Serial.print( "Union approach: " );
    V.bArray[0] = 0x33;
    V.bArray[1] = 0x33;
    V.bArray[2] = 0x8c;
    V.bArray[3] = 0x42;
    Serial.println( V.fVal );
   
}//setup

void loop() 
{

}//loop

Is there any benefit of writing the following when the size of float is always 4-byte?

sizeof(float)

GolamMostafa:
Is there any benefit of writing the following when the size of float is always 4-byte?

sizeof(float)

Meh. If I wrote:

unsigned char bArray[4];

someone would bitch about "mystery numbers".

Blackfin:
Meh. If I wrote:

unsigned char bArray[4];

someone would bitch about "mystery numbers".

We are living with "mystery numbers" -- 0, 1, 2, ..., 9 and is fine?

GolamMostafa:
We are living with "mystery numbers" -- 0, 1, 2, ..., 9 and is fine?

Actually I would be one of those barking :slight_smile: at the union not being standard (but works in simple cases with GCC) and would just deal with the address of the float, cast as a byte to store the information in the right order.

I would also recommend for sake of documentation and clarity and possibly long term maintenance to explicitly use sizeof(float). That won’t take any run time cycle, so why not doing so...

wildbill:
If you are passing the four raw bytes of a float between machines that share a floating point format - ...the detail of what makes up the float representation is irrelevant.

If the machines don't share the same format, I'd be inclined to pass the numbers as text, although there may be simple endian issues that you can fix by swapping the byte order.

Dear Wild, so true, but then us newbies face the pointers/union learning curve which, in my case, has been steeper than it should be.

Awol, "excess 127"? What, are mathematicians becoming like physicists and cosmologists, needing names that veer toward the indecipherable?

Thanks to all. This whole thread has raised the level of discourse (not once has anyone said "post ALL your code") and has kept my interest!

Dr.Q

Dr_Quark:
Awol, "excess 127"? What, are mathematicians becoming like physicists and cosmologists, needing names that veer toward the indecipherable?

"Becoming"?
This is a term I learned over forty years ago...

Not sure if it is a mathematical term, or a CS term.

@Dr_Quark - look it up, it’s part of the IEEE Floating Point Format standard... so indeed coined 40+ years ago