0

NaNs can potentially have many different binary representations, which can often be used to provide more information about, say, what caused the NaN. Any IEEE 32-bit float in the format of x111 1111 1xxx xxxx xxxx xxxx xxxx xxxx is a NaN. Also, any comparison between 2 NaNs (of potentially different binary value) evaluates to false.

So given two floats:

float a = NaN1;
float b = NaN2;

Both are NaN, but may have different values for the x bits above, what is the most correct way to compare their binary contents (i.e. check that they are the same type of NaN)?

The most obvious way to me is perform c-style casts like: *(uint32_t*)&a == *(uint32_t*)&b however, the size of a float is not guaranteed to be 32 bits.

Niall
  • 30,036
  • 10
  • 99
  • 142
Ponkadoodle
  • 5,777
  • 5
  • 38
  • 62
  • For float to integer conversions: http://stackoverflow.com/questions/2544394/c-floating-point-to-integer-type-conversions – 9dan Oct 01 '14 at 07:56
  • 1
    What non-32-bit size floats that support NaNs are you expecting to encounter? I think it's unlikely that you'll encounter any non-IEEE 754 format that supports NaNs in practice. I suppose it's possible that `float` could be the 64-bit IEEE 754 double-precision type, though that would be a bit perverse. – Mark Dickinson Oct 01 '14 at 08:20
  • @MarkDickinson This is code for an embedded application. My main target is the Raspberry Pi, but I aim to support any semi-powerful microcontroller with a c compiler. I would be totally unsurprised to come across a 16-bit half-precision type float. I can't imagine such an architecture where the default float will not be 16, 32 or 64 bits over the next decade, but I prefer to avoid unnecessary constraints when practical. – Ponkadoodle Oct 01 '14 at 08:34
  • Ah yes, 16-bit would do it. Thanks. – Mark Dickinson Oct 01 '14 at 08:34
  • Casting a pointer to a `uint32_t *` is UB per strict-aliasing rules. `mmecmp`, as the answerer said, is the way to go. – tmyklebu Oct 01 '14 at 15:38

1 Answers1

5

I guess the second most obvious is to use memcmp(), which is the standard function to compare two blocks of memory bit for bit:

const bool equal = memcmp(&a, &b, sizeof a) == 0;

Also, as suggested in a comment, it's a good idea to verify that the sizes are the same:

const bool equal = (sizeof a == sizeof b) && (memcmp(&a, &b, sizeof a) == 0);

I'm not sure using static_assert() is a win here, but I'm not a C++11 expert, either.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • Since this is C++, you can add a `static_assert(sizeof(a) == sizeof(b))`. – John Zwinck Oct 01 '14 at 07:44
  • Seems like overkill, but it should solve all portability issues. I wonder if a modern gcc is capable of optimizing that to a simple int or long comparison in the common cases where sizeof(float) <= sizeof(int). – Ponkadoodle Oct 01 '14 at 07:48
  • @Wallacoloo It is capable of that. `memcmp` is an intrinsic on all major compilers I'm aware of. – Sneftel Oct 01 '14 at 08:27