Can NAN and INFINITY be used under non-default rounding modes?

Sample code:

#include <stdio.h>
#include <math.h>
#include <fenv.h>

#if _MSC_VER && ! __clang__ && ! __INTEL_COMPILER
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif

int main(void)
{
    float f;
    if (fesetround(RM) != 0) return 1;
    f = V;
    printf("%f\n", f);
    return 0;
}

Invocations:

$ gcc t583.c -std=c11 -pedantic -Wall -Wextra -DV=NAN -DRM=FE_TOWARDZERO && ./a.exe
nan

$ gcc t583.c -std=c11 -pedantic -Wall -Wextra -DV=INFINITY -DRM=FE_TOWARDZERO && ./a.exe
inf

$ cl t583.c /std:c11 /Za /fp:strict /DV=NAN /DRM=FE_TOWARDZERO /nologo && ./t583.exe
0.000000

$ cl t583.c /std:c11 /Za /fp:strict /DV=INFINITY /DRM=FE_TOWARDZERO /nologo && ./t583.exe
340282346638528859811704183484516925440.000000

GCC defines NAN and INFINITY as:

#define NAN           (__builtin_nanf(""))
#define INFINITY      (__builtin_inff())

while MSVC defines NAN and INFINITY as:

#define NAN           ((float)(INFINITY * 0.0F))
#define INFINITY      ((float)(_HUGE_ENUF * _HUGE_ENUF))

and _HUGE_ENUF as:

#define _HUGE_ENUF    1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow

So, with MSVC under /fp:strict AND under FE_TOWARDZERO and FE_DOWNWARD:

  • the INFINITY evaluates to FLT_MAX, and
  • the NAN evaluates to 0.0.

Confused.

However, is it allowed at all to use NAN and INFINITY under non-default rounding modes, such as FE_TOWARDZERO and FE_DOWNWARD?


Reason of the question: better understanding of the C standard.

What problem is being solved: experimenting with non-default rounding modes using MSVC, trying to produce expected results.


is it allowed at all to use NAN and INFINITY under non-default rounding modes, such as FE_TOWARDZERO and FE_DOWNWARD?

The language specification does not express any limitation on using INFINITY. A conforming implementation must therefore accept it and interpret it consistently with the provisions of the language specification regardless of rounding mode. Specifically, it

expands to a constant expression of type float representing positive or unsigned infinity, if available; else to a positive constant of type float that overflows at translation time.

(C17 7.12/4)

That is not conditioned on the rounding mode in effect at any particular time. Since MSVC does have an available float representation for infinity and FLT_MAX is required to be a representation of a finite number, it is non-conforming for INFINITY to evaluate equal to FLT_MAX in MSVC, under any circumstances. Indeed, MSVC is non-conforming to whatever extent INFINITY ever fails to evaluate to a positive float infinity.

It is even more clear for NAN. The specification says that it

is defined if and only if the implementation supports quiet NaNs for the float type.

In that case,

It expands to a constant expression of type float representing a quiet NaN.

(C17 7.12/5)

If NAN is defined at all then it expands to an expression that evaluates to a quiet NaN. Period. If MSVC provides for circumstances in which it instead expands to 0.0, then MSVC is non-conforming under those circumstances.


It should be acknowledged that most, if not all, C implementations have some non-conformity, whether by default or accessible via command-line options or similar. Nevertheless, MSVC is notorious for its comparatively poor conformance among the widely used C implementations.