I have problem with interpretation of C standard, the latest draft taken from http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2454.pdf.
Standard evaluation
The standard defines pragma STD FENV_ACCESS
and states (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.
It is not clear why this pragma in necessary to run under non-default floating-point control modes. Is it because
Later in this paragraph of the standard we find:
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.
It looks like testing current mode without changing it is not an undefined behavior. But the footnote in the same paragraph states:
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.
The question
So if no pragma FENV_ACCESS was specified, does it mean default rounding mode is in effect?
Let's suppose that pragma FENV_ROUND is absent as well, and compiler assumes FENV_ACCESS is off by default, it is necessary for backward compatibility.
Example
Consider the following source code:
#include <math.h>
float func_01(float x) {
return nearbyint(x);
}
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
?
I wrote this answer based on the current C standard, 2018, but the question asks about a draft for a forthcoming standard. Upon reviewing the draft, there are significant changes, and this answer is not applicable.
Notably, draft n2454 states in 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 theFENV_ACCESS
pragma "off", the behavior is undefined…
Notably missing from this is this text from C 2018 that appeared just after “non-default floating-point mode settings”:
… or runs under non- default mode settings,…
The C 2018 text means that if code compiled with FENV_ACCESS
on sets a non-default mode and sets code compiled with FENV_ACCESS
off, then the behavior is not defined, merely because code compiled with FENV_ACCESS
off is running in a non-default mode. The draft text does not contain this, which seems to imply that a caller can change the mode and call code compiled with FENV_ACCESS
off, and the behavior should be defined. That means code compiled with FENV_ACCESS
off must be prepared to run in any floating-point mode.
The same paragraph in the draft also contains this new text:
(When execution passes from a part of the program translated with
FENV_ACCESS
"off" to a part translated withFENV_ACCESS
"on", the state of the floating-point status flags is unspecified and the floating-point control modes have their default settings.)
Consider what happens when routine A with FENV_ACCESS
on calls routine B with FENV_ACCESS
off. When B returns, control passes from an access-off part of the program to an access-on part of the program. The sentence above says the floating-point control modes are then in their default settings. In other words, returning from an access-off routine must change the floating-point mode to the default. That seems odd. So I am not prepared to update this answer to cover the draft well.
It is not clear why this pragma in necessary to run under non-default floating-point control modes.
It is because it may be (depending on the C implementation) that the code the compiler generates must be different if floating-point operations are not known to be in the default mode. For example, when compiling code with FENV_ACCESS
set to off
, the compiler can compile a call to sin
as a call to a fast version that assumes default rounding. But if FENV_ACCESS
is set to on
, it would compile the call to a slower version that tests the rounding mode and uses a corresponding implementation of the sine function.
Because the code that must be generated is different for the on
and off
versions, the compiler must know whether FENV_ACCESS
is on
or off
.
So if no pragma FENV_ACCESS was specified, does it mean default rounding mode is in effect?
No. If the FENV_ACCESS
pragma is not present, the compiler is in its default state, which may be on
or off
, and that is implementation-defined.
If the default is off
and there is no pragma, then, yes, the default rounding mode should be in effect, meaning that, if you have designed your program correctly, then any code compiled with no FENV_ACCESS
pragma is never executed in a non-default rounding mode. That is up to the program designer(s) to ensure.
The function
nearbyint
is described (7.12.9.3) as making rounding using current rounding mode. But the code does not havepragma FENV_ACCESS
. Does it mean that current rounding mode may be ignored andnearbyint
is same asroundeven
?
If code with FENV_ACCESS
set to off
(either by default or explicitly) calls nearbyint
, then the compiler can assume the default rounding mode is in effect, and it can call the fast version of nearbyint
that itself assumes the default rounding mode.
Note that round-to-nearest-ties-to-even is overwhelming the default rounding mode, but this is not specified by the C standard unless Annex F is in effect.