21. Floating-point environment <fenv.h>

The header <fenv.h> declares two types and several macros and functions to provide access to the floating-point environment. The floating-point environment refers collectively to any floating-point status flags and control modes supported by the implementation. [1] A floating-point status flag is a system variable whose value is set (but never cleared) when a floating-point exception is raised, which occurs as a side effect of exceptional floating-point arithmetic to provide auxiliary information. A floating-point control mode is a system variable whose value may be set by the user to affect the subsequent behavior of floating-point arithmetic.

Certain programming conventions support the intended model of use for the floating-point environment: [2]

  • a function call does not alter its caller’s floating-point control modes, clear its caller’s floating-point status flags, nor depend on the state of its caller’s floating-point status flags unless the function is so documented;
  • a function call is assumed to require default floating-point control modes, unless its documentation promises otherwise;
  • a function call is assumed to have the potential for raising floating-point exceptions, unless its documentation promises otherwise.

The type fenv_t represents the entire floating-point environment.

The type fexcept_t represents the floating-point status flags collectively, including any status the implementation associates with the flags.

Each of the macros:

FE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOW

is defined if and only if the implementation supports the floating-point exception by means of the functions in 13.6.2. [3] Additional implementation-defined floating-point exceptions, with macro definitions beginning with FE_ and an uppercase letter, may also be specified by the implementation. The defined macros expand to integer constant expressions with values such that bitwise ORs of all combinations of the macros result in distinct values.

The macro FE_ALL_EXCEPT is simply the bitwise OR of all floating-point exception macros defined by the implementation. If no such macros are defined, FE_ALL_EXCEPT shall be defined as 0.

Each of the macros:

FE_DOWNWARD
FE_TONEAREST
FE_TOWARDZERO
FE_UPWARD

is defined if and only if the implementation supports getting and setting the represented rounding direction by means of the fegetround and fesetround functions. Additional implementation-defined rounding directions, with macro definitions beginning with FE_ and an uppercase letter, may also be specified by the implementation. The defined macros expand to integer constant expressions whose values are distinct nonnegative values. [4]

The macro FE_DFL_ENV represents the default floating-point environment - the one installed at program startup - and has type “pointer to const-qualified fenv_t”. It can be used as an argument to <fenv.h> functions that manage the floating-point environment.

Additional implementation-defined environments, with macro definitions beginning with FE_ and an uppercase letter, and having type “pointer to const-qualified fenv_t”, may also be specified by the implementation.

[1]This header is designed to support the floating-point exception status flags and directed-rounding control modes required by IEC 60559, and other similar floating-point state information. Also it is designed to facilitate code portability among all systems.
[2]With these conventions, a programmer can safely assume default floating-point control modes (or be unaware of them). The responsibilities associated with accessing the floating-point environment fall on the programmer or program that does so explicitly.
[3]The implementation supports an exception if there are circumstances where a call to at least one of the functions in 13.6.2, using the macro as the appropriate argument, will succeed. It is not necessary for all the functions to succeed all the time.
[4]Even though the rounding direction macros may expand to constants corresponding to the values of FLT_ROUNDS, they are not required to do so.

21.1. The FENV_ACCESS pragma

Synopsis

#include <fenv.h>
#pragma STDC FENV_ACCESS on-off-switch

Description

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. [5] The pragma shall occur either outside external declarations or preceding all explicit declarations and statements inside a compound statement. When outside external declarations, the pragma takes effect from its occurrence until another FENV_ACCESS pragma is encountered, or until the end of the translation unit. When inside a compound statement, the pragma takes effect from its occurrence until another FENV_ACCESS pragma is encountered (including within a nested compound statement), or until the end of the compound statement; at the end of a compound statement the state for the pragma is restored to its condition just before the compound statement. If this pragma is used in any other context, the behavior is undefined. If part of a program tests floating-point status flags, sets floating-point control modes, or runs under non-default mode settings, but was translated with the state for the FENV_ACCESS pragma “off”, the behavior is undefined. The default state (“on” or “off”) for the pragma is implementation-defined. (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.)

EXAMPLE

#include <fenv.h>
void f(double x)
{
  #pragma STDC FENV_ACCESS ON
  void g(double);
  void h(double);
  /* ... */
  g(x + 1);
  h(x + 1);
  /* ... */
}

If the function g might depend on status flags set as a side effect of the first x + 1, or if the second x + 1 might depend on control modes set as a side effect of the call to function g, then the program shall contain an appropriately placed invocation of #pragma STDC FENV_ACCESS ON. [6]

[5]The purpose of the FENV_ACCESS pragma is to allow certain optimizations that could subvert flag tests and mode changes (e.g., global common subexpression elimination, code motion, and constant folding). In general, if the state of FENV_ACCESS is “off”, the translator can assume that default modes are in effect and the flags are not tested.
[6]The side effects impose a temporal ordering that requires two evaluations of x + 1. On the other hand, without the #pragma STDC FENV_ACCESS ON pragma, and assuming the default state is “off”, just one evaluation of x + 1 would suffice.

21.2. Floating-point exceptions

The following functions provide access to the floating-point status flags. [7] The int input argument for the functions represents a subset of floating-point exceptions, and can be zero or the bitwise OR of one or more floating-point exception macros, for example FE_OVERFLOW | FE_INEXACT. For other argument values the behavior of these functions is undefined.

21.2.1. The feclearexcept function

Synopsis

#include <fenv.h>
int feclearexcept(int excepts);

Description

The feclearexcept function attempts to clear the supported floating-point exceptions represented by its argument.

Returns

The feclearexcept function returns zero if the excepts argument is zero or if all the specified exceptions were successfully cleared. Otherwise, it returns a nonzero value.

Synopsis

#include <fenv.h>
int feclearexcept(int excepts);

Link with -lm.

Following description, exceptions, rounding mode, floating-point environment and return values are applicable to all functions of this header

Description

This function was defined in C99, and describe the handling of floating-point rounding and exceptions (overflow, zero-divide, etc.).

Exceptions

The divide-by-zero exception occurs when an operation on finite numbers produces infinity as exact answer.

The overflow exception occurs when a result has to be represented as a floating-point number, but has (much) larger absolute value than the largest (finite) floating-point number that is representable.

The underflow exception occurs when a result has to be represented as a floating-point number, but has smaller absolute value than the smallest positive normalized floating-point number (and would lose much accuracy when represented as a denormalized number).

The inexact exception occurs when the rounded result of an operation is not equal to the infinite precision result. It may occur whenever overflow or underflow occurs.

The invalid exception occurs when there is no well-defined result for an operation, as for 0/0 or infinity - infinity or sqrt(-1).

Exception handling

Exceptions are represented in two ways: as a single bit (exception present/absent), and these bits correspond in some implementation- defined way with bit positions in an integer, and also as an opaque structure that may contain more information about the exception (perhaps the code address where it occurred).

Each of the macros FE_DIVBYZERO, FE_INEXACT,  FE_INVALID,  FE_OVERFLOW, FE_UNDERFLOW is defined when the implementation supports handling of the corresponding exception, and if so then defines the corresponding bit(s), so that one can call exception handling functions, for example, using the integer argument FE_OVERFLOW|FE_UNDERFLOW. Other exceptions may be supported. The macro FE_ALL_EXCEPT is the bitwise OR of all bits corresponding to supported exceptions.

The feclearexcept() function clears the supported exceptions represented by the bits in its argument.

The fegetexceptflag() function stores a representation of the state of the exception flags represented by the argument excepts in the opaque object *flagp.

The feraiseexcept() function raises the supported exceptions represented by the bits in excepts.

The fesetexceptflag() function sets the complete status for the exceptions represented by excepts to the value *flagp. This value must have been obtained by an earlier call of fegetexceptflag() with a last argument that contained all bits in excepts.

The fetestexcept() function returns a word in which the bits are set that were set in the argument excepts and for which the corresponding exception is currently set.

Rounding mode

The rounding mode determines how the result of floating-point operations is treated when the result cannot be exactly represented in the significand. Various rounding modes may be provided: round to nearest (the default), round up (toward positive infinity), round down (toward negative infinity), and round toward zero.

Each of the macros FE_TONEAREST, FE_UPWARD, FE_DOWNWARD and FE_TOWARDZERO is defined when the implementation supports getting and setting the corresponding rounding direction.

The fegetround() function returns the macro corresponding to the current rounding mode.

The fesetround() function sets the rounding mode as specified by its argument and returns zero when it was successful.

C99 and POSIX.1-2008 specify an identifier, FLT_ROUNDS, defined in <float.h>, which indicates the implementation-defined rounding behavior for floating-point addition. This identifier has one of the following values:

-1 The rounding mode is not determinable.
0 Rounding is toward 0.
1 Rounding is toward nearest number.
2 Rounding is toward positive infinity.
3 Rounding is toward negative infinity.

Other values represent machine-dependent, nonstandard rounding modes.

The value of FLT_ROUNDS should reflect the current rounding mode as set by fesetround().

Floating-point environment

The entire floating-point environment, including control modes and status flags, can be handled as one opaque object, of type fenv_t. The default environment is denoted by FE_DFL_ENV (of type const fenv_t *). This is the environment setup at program start and it is defined by ISO C to have round to nearest, all exceptions cleared and a nonstop (continue on exceptions) mode.

The fegetenv() function saves the current floating-point environment in the object *envp.

The feholdexcept() function does the same, then clears all exception flags, and sets a nonstop (continue on exceptions) mode, if available. It returns zero when successful.

The fesetenv() function restores the floating-point environment from the object *envp. This object must be known to be valid, for example, the result of a call to fegetenv() or feholdexcept() or equal to FE_DFL_ENV. This call does not raise exceptions.

The feupdateenv() function installs the floating-point environment represented by the object *envp, except that currently raised exceptions are not cleared. After calling this function, the raised exceptions will be a bitwise OR of those previously set with those in *envp. As before, the object *envp must be known to be valid.

RETURN VALUE

These functions return zero on success and nonzero if an error occurred.

[7]The functions fetestexcept, feraiseexcept and feclearexcept support the basic abstraction of flags that are either set or clear. An implementation may endow floating-point status flags with more information - for example, the address of the code which first raised the floating-point exception; the functions fegetexceptflag and fesetexceptflag deal with the full content of flags.

21.2.2. The fegetexceptflag function

Synopsis

#include <fenv.h>
int fegetexceptflag(fexcept_t *flagp, int excepts);

Description

The fegetexceptflag function attempts to store an implementation-defined representation of the states of the floating-point status flags indicated by the argument excepts in the object pointed to by the argument flagp.

Returns

The fegetexceptflag function returns zero if the representation was successfully stored. Otherwise, it returns a nonzero value.

21.2.3. The feraiseexcept function

Synopsis

#include <fenv.h>
int feraiseexcept(int excepts);

Description

The feraiseexcept function attempts to raise the supported floating-point exceptions represented by its argument. [8] The order in which these floating-point exceptions are raised is unspecified, except as stated in F.7.6 of specification. Whether the feraiseexcept function additionally raises the “inexact” floating-point exception whenever it raises the “overflow” or “underflow” floating-point exception is implementation-defined.

Returns

The feraiseexcept function returns zero if the excepts argument is zero or if all the specified exceptions were successfully raised. Otherwise, it returns a nonzero value.

[8]The effect is intended to be similar to that of floating-point exceptions raised by arithmetic operations. Hence, enabled traps for floating-point exceptions raised by this function are taken. The specification in F.7.6 of specification is in the same spirit.

21.2.4. The fesetexceptflag function

Synopsis

#include <fenv.h>
int fesetexceptflag(const fexcept_t *flagp, int excepts);

Description

The fesetexceptflag function attempts to set the floating-point status flags indicated by the argument excepts to the states stored in the object pointed to by flagp. The value of *flagp shall have been set by a previous call to fegetexceptflag whose second argument represented at least those floating-point exceptions represented by the argument excepts. This function does not raise floating-point exceptions, but only sets the state of the flags.

Returns

The fesetexceptflag function returns zero if the excepts argument is zero or if all the specified flags were successfully set to the appropriate state. Otherwise, it returns a nonzero value.

21.2.5. The fetestexcept function

Synopsis

#include <fenv.h>
int fetestexcept(int excepts);

Description

The fetestexcept function determines which of a specified subset of the floating-point exception flags are currently set. The excepts argument specifies the floating-point status flags to be queried. [9]

Returns

The fetestexcept function returns the value of the bitwise OR of the floating-point exception macros corresponding to the currently set floating-point exceptions included in excepts.

[9]This mechanism allows testing several floating-point exceptions with just one function call.

EXAMPLE Call f if “invalid” is set, then g if “overflow” is set:

#include <fenv.h>
/* ... */
{
  #pragma STDC FENV_ACCESS ON
  int set_excepts;
  feclearexcept(FE_INVALID | FE_OVERFLOW);
  // maybe raise exceptions
  set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW);
  if (set_excepts & FE_INVALID) f();
  if (set_excepts & FE_OVERFLOW) g();
  /* ... */
}

21.3. Rounding

The fegetround and fesetround functions provide control of rounding direction modes.

21.3.1. The fegetround function

Synopsis

#include <fenv.h>
int fegetround(void);

Description

The fegetround function gets the current rounding direction.

Returns

The fegetround function returns the value of the rounding direction macro representing the current rounding direction or a negative value if there is no such rounding direction macro or the current rounding direction is not determinable.

21.3.2. The fesetround function

Synopsis

#include <fenv.h>
int fesetround(int round);

Description

The fesetround function establishes the rounding direction represented by its argument round. If the argument is not equal to the value of a rounding direction macro, the rounding direction is not changed.

Returns

The fesetround function returns zero if and only if the requested rounding direction was established.

EXAMPLE Save, set, and restore the rounding direction. Report an error and abort if setting the rounding direction fails.

#include <fenv.h>
#include <assert.h>
void f(int round_dir)
{
  #pragma STDC FENV_ACCESS ON
  int save_round;
  int setround_ok;
  save_round = fegetround();
  setround_ok = fesetround(round_dir);
  assert(setround_ok == 0);
  /* ... */
  fesetround(save_round);
  /* ... */
}

21.4. Environment

The functions in this section manage the floating-point environment - status flags and control modes - as one entity.

21.4.1. The fegetenv function

Synopsis

#include <fenv.h>
int fegetenv(fenv_t *envp);

Description

The fegetenv function attempts to store the current floating-point environment in the object pointed to by envp.

Returns

The fegetenv function returns zero if the environment was successfully stored. Otherwise, it returns a nonzero value.

21.4.2. The feholdexcept function

Synopsis

#include <fenv.h>
int feholdexcept(fenv_t *envp);

Description

The feholdexcept function saves the current floating-point environment in the object pointed to by envp, clears the floating-point status flags, and then installs a non-stop (continue on floating-point exceptions) mode, if available, for all floating-point exceptions. [10]

Returns

The feholdexcept function returns zero if and only if non-stop floating-point exception handling was successfully installed.

[10]IEC 60559 systems have a default non-stop mode, and typically at least one other mode for trap handling or aborting; if the system provides only the non-stop mode then installing it is trivial. For such systems, the feholdexcept function can be used in conjunction with the feupdateenv function to write routines that hide spurious floating-point exceptions from their callers.

21.4.3. The fesetenv function

Synopsis

#include <fenv.h>
int fesetenv(const fenv_t *envp);

Description

The fesetenv function attempts to establish the floating-point environment represented by the object pointed to by envp. The argument envp shall point to an object set by a call to fegetenv or `feholdexcept, or equal a floating-point environment macro. Note that fesetenv merely installs the state of the floating-point status flags represented through its argument, and does not raise these floating-point exceptions.

Returns

The fesetenv function returns zero if the environment was successfully established. Otherwise, it returns a nonzero value.

21.4.4. The feupdateenv function

Synopsis

#include <fenv.h>
int feupdateenv(const fenv_t *envp);

Description

The feupdateenv function attempts to save the currently raised floating-point exceptions in its automatic storage, install the floating-point environment represented by the object pointed to by envp, and then raise the saved floating-point exceptions. The argument envp shall point to an object set by a call to feholdexcept or fegetenv, or equal a floating-point environment macro.

Returns

The feupdateenv function returns zero if all the actions were successfully carried out. Otherwise, it returns a nonzero value.

EXAMPLE Hide spurious underflow floating-point exceptions:

#include <fenv.h>
double f(double x)
{
  #pragma STDC FENV_ACCESS ON
  double result;
  fenv_t save_env;
  if (feholdexcept(&save_env))
    return /* indication of an environmental problem */;
  // compute result
  if (/* test spurious underflow */)
    if (feclearexcept(FE_UNDERFLOW))
      return /* indication of an environmental problem */;
  if (feupdateenv(&save_env))
    return /* indication of an environmental problem */;
  return result;
}