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

后端 未结 3 1741
一整个雨季
一整个雨季 2021-01-13 16:48

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 exa

相关标签:
3条回答
  • 2021-01-13 17:32

    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
    0 讨论(0)
  • 2021-01-13 17:41

    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.

    0 讨论(0)
  • 2021-01-13 17:44

    There is a supported way to write the payload of a quiet NaN in C.

    The nan, nanf, and nanl functions (of the math.h header, section 7.12.11.2 of the 1999 C specification) accept strings as arguments. The strtof, strtod, and strtold functions (of the stdlib.h header, section 7.20.1.3) accept strings of the form "NAN(character sequence)". The fscanf and sscanf functions follow strtod. However, the character sequence is interpreted in an implementation-defined way. (Which means your compiler is supposed to provide you with documentation specifying the interpretation. Some compilers will not obey this requirement of the standard.)

    The fprintf function (stdio.h, section 7.19.6.1) may output a string of the form "NAN(character sequence)" with the floating-point formats (a, e, f, g), as may printf and sprintf. The standard permits the output of "NAN" with no character sequence, so this will not work with many compilers.

    Because the interpretations are implementation-defined, you should not expect them to be portable. They are typically intended for special purposes such as debugging.

    0 讨论(0)
提交回复
热议问题