You may be able to control the 'payload' bits by passing appropriate strings to the C99 nan
, nanf
, nanl
functions, but these will only generate quiet NaNs, and the interpretation of the string is left unspecified (most implementations treat it as a hexadecimal number).
Alternatively, use a union:
#ifndef __STDC_IEC_559__
#error "This program requires IEEE floating point arithmetic"
#endif
#include <stdint.h>
#include <assert.h>
static_assert(sizeof(float) == sizeof(uint32_t),
"This program requires float to be 32 bits exactly");
float nanf_with_payload_bits(uint32_t payload)
{
if (payload & 0x7FA00000) abort();
union ieee_single {
float f;
uint32_t i;
} nan;
nan.i = 0x7FA00000 | payload;
return nan.f;
}
Writing to one member of a union and then reading from another, when both types are exactly the same size, does NOT provoke undefined behavior in C99+errata. (It was undefined behavior in C89, but most compilers defined it to do what you would expect. It may still be undefined behavior in C++, I'm not sure; however, again, most compilers define it to do what you would expect.)
If you use this function to create signaling NaNs, be aware that their behavior is explicitly left undefined in C99/C11 Annex F.
DO NOT attempt to break down the i
component of the union into a structure with bit-fields. The memory layout of bit-fields within a structure is partially implementation-defined and partially unspecified, and in particular a sequence of bit-fields is not necessarily packed into a word in the same order as the CPU endianness (or, indeed, properly packed at all).
Standards citations (all C99):
- this use of a union is only unspecified behavior: 6.2.6.1p7; J.1
- the layout of bitfields within a structure is unpredictable: 6.2.6.1p1,2; 6.7.2.1p10,11,13; J.3.9
- the behavior of signaling NaNs is undefined: F.2.1