NAN 和 INFINITY 可以在非默认舍入模式下使用吗?

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

示例代码:

#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;
}

调用:

$ 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 将 NANINFINITY 定义为:

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

而 MSVC 将 NANINFINITY 定义为:

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

_HUGE_ENUF为:

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

因此,MSVC 在 /fp:strictFE_TOWARDZEROFE_DOWNWARD 下:

困惑。

但是,是否允许在非默认舍入模式下使用NANINFINITY,例如FE_TOWARDZEROFE_DOWNWARD


提问原因:更好的理解C标准

正在解决什么问题:使用 MSVC 试验非默认舍入模式,尝试产生预期结果。


更新。微软的回答:

Thanks for reporting this and help us improve our libraries. This issue has been fixed and will be available in a future update.

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

语言规范未对使用 INFINITY 表示任何限制。因此,符合规范的实现必须接受它并根据语言规范的规定一致地解释它,而不管舍入模式如何。具体来说,它

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)

这不以在任何特定时间有效的舍入模式为条件。由于 MSVC 确实有可用的 float 表示无穷大并且 FLT_MAX 需要表示 finite 数字,因此它不符合 INFINITY 在任何情况下都等于 MSVC 中的 FLT_MAX。事实上,MSVC 在任何程度上都不符合 INFINITY 从未评估为正 float 无穷大。

NAN就更清楚了。规范说它

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

那样的话,

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

(C17 7.12/5)

如果完全定义了 NAN,那么它会扩展为计算结果为安静 NaN 的表达式。时期。如果 MSVC 提供了它扩展为 0.0 的情况,那么在这些情况下 MSVC 是不符合要求的。


应该承认,大多数(如果不是全部的话)C 实现都有一些不一致之处,无论是默认情况下还是通过命令行选项或类似方式访问。然而,MSVC 因其在广泛使用的 C 实现中相对较差的一致性而臭名昭著。