4

In my C++ code I have declared a union:

typedef union U_FloatParse {
    float float_data;
    unsigned char byte_data[4];
} U_FloatConvert;

Then, I set the byte_data array to the values 0, 0, 192, 127:

U_FloatConvert depth_data;

depth_data.byte_data[0] = 0;
depth_data.byte_data[1] = 0;
depth_data.byte_data[2] = 192;
depth_data.byte_data[3] = 127;

printf("\n\nFloat = %f\n\n", depth_data.float_data);

As output I get NaN. Why don't I get a normal float value? When I pass the values: 56, 137, 33, 63. I get the float value 0.631000.

Test code: http://codepad.org/Q8ds1V0F

timrau
  • 22,578
  • 4
  • 51
  • 64
moffeltje
  • 4,521
  • 4
  • 33
  • 57

3 Answers3

7

By writing the said bytes into the array, you get a memory layout of 00 00 c0 7f, which, in little endian, reads as 7fc00000. Interpreting this as an IEEE float gives you

  • a sign of 0 (positive, but irrelevant for NaN)
  • an exponent of 0xFF
  • a mantissa of 0x400000 (> 0 and has the most significant bit set → silent)

which gets you a (silent) NaN value.

At least, this counts for C. In C++, it is not defined what you do, but if you nevertheless get NaN as a result, your compiler treats it if it was C (not recommended nevertheless to rely on undefined behaviour!).

moffeltje
  • 4,521
  • 4
  • 33
  • 57
glglgl
  • 89,107
  • 13
  • 149
  • 217
6

NaN is a normal float value, and the bytes you set are correctly interpreted as a valid NaN.

That being said, you could have got the output "there is no spoon NaN", since using a union in this manner has undefined behaviour in C++. You may only use one of the union's members at any given time. It's not a shortcut for reinterpret-casting!

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

NaN(not a number) error generally occurs if the ouput is indeterminate i.e whose value couldn't be determined such as 0/0.

But I wouldn't use unions anyway (personally don't like them), when you use a union, it is undefined behavior to set one member and extract a different member.

For one thing, floating-point values are basically split into bit fields, with so many bits holding the mantissa, so many holding the exponent, and one holding the sign. And integer, on the other hand is simply a base-2 representation of a number. Their bits just aren't arranged the same.

You could do like this:

unsigned long int l = byte_data[0] | (byte_data[1] << 8) | (byte_data[2] << 16) | (byte_data[3] << 24);
  • 1
    You can't build a float like that though – harold Dec 16 '16 at 14:03
  • Ah, yes obviously... Does it have to be a float? ^^ – Alen Hadzic Dec 16 '16 at 14:19
  • 1
    Well maybe, I just think it's odd to answer this question with how to build an integer, that's not really what the question is about – harold Dec 16 '16 at 14:30
  • True. Well i though the code line would just be extra, my answer was really the text i wrote. Sorry for inconvenience. What i meant was that using float, you will get 0x7fc00000 from the char array, what you really want is 0x0000c07f, which i was trying to explain. – Alen Hadzic Dec 16 '16 at 14:47