Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I manually set the bit value of a float that equates to NaN?

I'm trying to run some tests with conversions and castings of floats to other types and I want to set my float variable to different values of nan.

"a bit-wise example of a IEEE floating-point standard single precision (32-bit) NaN would be: s111 1111 1axx xxxx xxxx xxxx xxxx xxxx where s is the sign (most often ignored in applications), a determines the type of NaN, and x is an extra payload (most often ignored in applications). If a = 1, it is a quiet NaN; if a is zero and the payload is nonzero, then it is a signaling NaN"

Basically I want to find a way to set the payload or xxxx's of the representation. Is there any way to do this in c?

like image 499
Chris Avatar asked Dec 06 '22 15:12

Chris


2 Answers

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
like image 168
zwol Avatar answered May 15 '23 20:05

zwol


Use memcpy:

int32_t i = 0x7FC00000;
float f;
memcpy(&f, &i, sizeof(f));

You could also assert that sizeof(f) == sizeof(i), but if you know that floats are IEEE then presumably you also know what size the basic types are.

like image 21
Steve Jessop Avatar answered May 15 '23 20:05

Steve Jessop