c-如果没有pragma STDC FENV_ACCESS,这是否意味着默认舍入模式



我对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.

问题

所以,如果没有指定杂注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

我根据2018年的现行C标准写下了这个答案,但问题是关于即将出台的标准的草案。在审查草案时,有重大变化,这个答案不适用。

值得注意的是,草案n2454在7.6.1 2中规定:

…如果程序的一部分使用FENV_ROUND杂注以外的任何方式测试浮点状态标志或建立非默认浮点模式设置,但使用FENV_ACCESS杂注的状态进行了转换";"关";,行为未定义…

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

…或在非默认模式设置下运行,…

C 2018文本意味着,如果在FENV_ACCESS打开的情况下编译的代码设置了非默认模式,并在FENV_ACCESS关闭的情况下编辑的代码设置,则不会定义行为,因为在FENV_ACCESS关闭的情况下编译的代码在非默认模式下运行。草案文本不包含这一点,这似乎意味着调用者可以更改模式并调用在FENV_ACCESS关闭的情况下编译的代码,并且应该定义行为。这意味着在FENV_ACCESS关闭的情况下编译的代码必须准备好在任何浮点模式下运行。

草案中的同一段也包含以下新案文:

(当执行从用FENV_ACCESS"关闭"翻译的程序部分转移到用FENV_ACCESS"打开"翻译的部分时,浮点状态标志的状态未指定,浮点控制模式具有默认设置。)

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

C 2018答案

不清楚为什么这个杂注需要在非默认浮点控制模式下运行。

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

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

因此,如果没有指定杂注FENV_ACCESS,是否意味着默认舍入模式有效?

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

如果默认值是off,并且没有杂注,那么,是的,默认舍入模式应该有效,这意味着,如果您正确设计了程序,那么任何不使用FENV_ACCESS杂注编译的代码都不会在非默认舍入模式下执行。这取决于程序设计者来确保。

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

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

请注意,四舍五入到最接近的平局是压倒性的默认舍入模式,但除非附录F有效,否则C标准未对此进行规定。

相关内容

最新更新