如果 pragma STDC FENV_ACCESS 不存在,是否意味着默认舍入模式?

If pragma STDC FENV_ACCESS is absent, does it mean default rounding mode?

我对 C 标准的解释有疑问,最新草案取自 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2454.pdf.

标准评价

标准定义 pragma STD FENV_ACCESS 并声明 (7.6.1p2):

The FENV_ACCESS pragma provides a means to inform the implementation when a program might
access the floating-point environment to test floating-point status flags or run under non-default
floating-point control modes.

目前尚不清楚为什么在非默认浮点控制模式下需要此 pragma 运行。是不是因为

在标准的这一段后面我们发现:

If part of a program tests floating-point status flags or establishes non-default floating-point
mode settings using any means other than the FENV_ROUND pragmas, but was translated with the
state for the FENV_ACCESS pragma "off", the behavior is undefined.

看起来测试当前模式而不改变它不是未定义的行为。但同段脚注指出:

In general, if the state of FENV_ACCESS is "off", the translator can assume that the flags are
not tested, and that default modes are in effect, except where specified otherwise by an
FENV_ROUND pragma.

问题

所以如果没有指定 pragma FENV_ACCESS,是否意味着默认舍入模式生效?

让我们假设 pragma FENV_ROUND 也不存在,并且编译器假设 FENV_ACCESS 默认关闭,这是向后兼容所必需的。

例子

考虑以下源代码:

#include <math.h>
float func_01(float x) {
    return nearbyint(x);
}

函数 nearbyint 被描述为 (7.12.9.3) 使用当前舍入模式进行舍入。但是代码没有pragma FENV_ACCESS。这是否意味着可以忽略当前舍入模式并且 nearbyintroundeven 相同?

C 草稿 n2454

我根据当前的 C 标准 2018 写了这个答案,但问题是关于即将发布的标准的草案。经审稿,有重大变化,本回答不适用。

值得注意的是,n2454 草案在 7.6.1 2 中指出:

… If part of a program tests floating-point status flags or establishes non-default floating-point mode settings using any means other than the FENV_ROUND pragmas, but was translated with the state for the FENV_ACCESS pragma "off", the behavior is undefined…

值得注意的是,在“非默认浮点模式设置”之后出现的 C 2018 中的这段文字明显缺失:

… or runs under non- default mode settings,…

C 2018 文本意味着如果使用 FENV_ACCESS on 编译的代码设置非默认模式并设置使用 FENV_ACCESS off 编译的代码,则行为未定义,仅仅是因为代码编译在非默认模式下 FENV_ACCESS 关闭是 运行ning。草案文本不包含此内容,这似乎暗示调用者可以更改模式并调用关闭 FENV_ACCESS 编译的代码,并且应该定义行为。这意味着关闭 FENV_ACCESS 编译的代码必须准备好在任何浮点模式下 运行。

草案中的同一段也包含了这个新文本:

(When execution passes from a part of the program translated with FENV_ACCESS "off" to a part translated with FENV_ACCESS "on", the state of the floating-point status flags is unspecified and the floating-point control modes have their default settings.)

考虑当 FENV_ACCESS 打开的例程 A 调用 FENV_ACCESS 关闭的例程 B 时会发生什么。当Breturns时,控制从程序的访问关闭部分传递到程序的访问打开部分。上面的句子说浮点控制模式处于默认设置。换句话说,从访问关闭例程返回必须将浮点模式更改为默认模式。这似乎很奇怪。所以我不准备更新这个答案来很好地涵盖草稿。

C 2018 的答案

It is not clear why this pragma in necessary to run under non-default floating-point control modes.

这是因为如果不知道默认模式下的浮点运算,编译器生成的代码可能(取决于 C 实现)必须不同。例如,在将 FENV_ACCESS 设置为 off 的情况下编译代码时,编译器可以将对 sin 的调用编译为对采用默认舍入的快速版本的调用。但是,如果 FENV_ACCESS 设置为 on,它会将调用编译为测试舍入模式并使用相应的正弦函数实现的较慢版本。

因为 onoff 版本必须生成的代码不同,编译器必须知道 FENV_ACCESSon 还是 off.

So if no pragma FENV_ACCESS was specified, does it mean default rounding mode is in effect?

没有。如果 FENV_ACCESS 编译指示不存在,则编译器处于其默认状态,可能是 onoff,这是实现定义的。

如果默认是off并且没有pragma,那么,是的,默认的舍入模式应该生效,也就是说,如果你设计了如果您的程序正确,那么任何没有使用 FENV_ACCESS 编译指示编译的代码都不会在非默认舍入模式下执行。这取决于程序设计者来确保。

The function nearbyint is described (7.12.9.3) as making rounding using current rounding mode. But the code does not have pragma FENV_ACCESS. Does it mean that current rounding mode may be ignored and nearbyint is same as roundeven?

如果 FENV_ACCESS 设置为 off(默认或显式)的代码调用 nearbyint,则编译器可以假定默认舍入模式生效,并且它可以调用本身采用默认舍入模式的 nearbyint 的快速版本。

请注意,round-to-nearest-ties-to-even 压倒了默认的舍入模式,但除非附件 F 生效,否则 C 标准未指定此模式。