为啥非严格浮点模型不改变 __STDC_IEC_559__ 的值 1?

Posted

技术标签:

【中文标题】为啥非严格浮点模型不改变 __STDC_IEC_559__ 的值 1?【英文标题】:Why don't non-strict floating-point models change the value 1 of __STDC_IEC_559__?为什么非严格浮点模型不改变 __STDC_IEC_559__ 的值 1? 【发布时间】:2022-01-04 00:00:17 【问题描述】:

示例代码(t0.c):

#include <stdio.h>   // fix for clang, see https://***.com/q/69976945/1778275
#if __STDC_IEC_559__ == 1
#pragma message "__STDC_IEC_559__ is 1"
#else
#pragma message "__STDC_IEC_559__ is not 1"
#endif

调用:

# gcc 11.2 on Linux on x86-64
$ gcc t0.c -std=c11 -pedantic -Wall -Wextra -fno-rounding-math
t0.c:3:9: note: '#pragma message: __STDC_IEC_559__ is 1'

# clang 13.0.0 on Linux on x86-64
$ clang t0.c -std=c11 -pedantic -Wall -Wextra -ffp-model=fast
t0.c:3:9: warning: __STDC_IEC_559__ is 1 [-W#pragma-messages]

# icc 2021.1.2 on Linux on x86-64
$ icc t0.c -std=c11 -pedantic -Wall -Wextra -fp-model=fast
__STDC_IEC_559__ is 1

这里我们看到非严格浮点模型不会改变1 的值__STDC_IEC_559__。为什么?

UPD20211126: 回复:

开关本身不会改变舍入行为,因此不会改变是否定义了宏。

现在-fno-rounding-math下的gcc错误编译了以下程序(t1.c):

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

#pragma STDC FENV_ACCESS ON

int main(void)

#if __STDC_IEC_559__ == 1
    if (fesetround(FE_UPWARD) == 0)
    
        printf("%a\n", FLT_MIN / 1.0000001f);
    
#endif
    return 0;       

调用和执行:

# gcc 11.2 on Linux on x86-64
gcc t1.c -std=c11 -pedantic -Wall -Wextra -lm -fno-rounding-math && ./a.out
t1.c:5: warning: ignoring '#pragma STDC FENV_ACCESS' [-Wunknown-pragmas]
0x1.fffffcp-127

# gcc 11.2 on Linux on x86-64
gcc t1.c -std=c11 -pedantic -Wall -Wextra -lm -frounding-math && ./a.out
t1.c:5: warning: ignoring '#pragma STDC FENV_ACCESS' [-Wunknown-pragmas]
0x1p-126

在这里我们看到__STDC_IEC_559__ == 1 下的结果是不同的。出乎意料。

注意:是的,在 gcc 中 Pragma STDC * (C99 FP) unimplemented。

UPD20211130。出于好奇:如果这些在非严格浮点模型下的实现不符合附件 F 中的规范,那么他们定义__STDC_IEC_559__1 的目的是什么?

【问题讨论】:

相关:Status of STDC_IEC_559 with modern C compilers 但是,我认为-ffp 开关不会改变浮点的表示形式——它们仍然是 IEE754(= ISO/IEC/IEEE 60559)格式。 人类编写的软件不正确。 阅读手册。 -frounding-math ...应该为动态改变FP舍入模式的程序指定该选项 @n.1.8e9-where's-my-sharem。来自comments:每个单独的开关组合与编译器都被视为不同的 C 实现 【参考方案1】:

因为它们似乎有问题。

【讨论】:

【参考方案2】:

-fno-rounding-math 是 gcc 默认。它启用了假设无舍入 IEEE 算法的优化。 -frounding-math 关闭这些优化。开关本身不会改变舍入行为,因此不会改变是否定义了宏。

-frounding-math
  Disable transformations and optimizations that assume default 
  floating-point rounding behavior.  This is round-to-zero for all 
  floating point to integer conversions, and round-to-nearest for all 
  other arithmetic truncations.  This option should be specified for 
  programs that change the FP rounding mode dynamically, or that may 
  be executed with a non-default rounding mode.  This option disables
  constant folding of floating-point expressions at compile time
  (which may be affected by rounding mode) and arithmetic 
  transformations that are unsafe in the presence of sign-dependent 
  rounding modes.

-ffast-math 在 gcc 中关闭宏。它在 clang 中不这样做,这可能是一个错误。

【讨论】:

参见 UPD20211126。

以上是关于为啥非严格浮点模型不改变 __STDC_IEC_559__ 的值 1?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 NVCC 对 constexpr 比非 constexpr 主机函数更严格?

__x__(81)1017第十六天__ JavaScript 严格模式

GCC 中的浮点运算

为啥 VC++ 引入了非标准关键字:__leave?

如果 t.__str__() 返回一个非字符串而不是 print(t.__str__()),为啥 print(t) 会出错?

ES5-ES6-ES7_严格模式