C Standard Library<fenv.h>
C Standard Library<fenv.h>
<fenv.h>is a header file in the C standard library, used to control the floating-point environment.
<fenv.h>Introduced in the C99 standard, it provides control and query functionality for floating-point exceptions, rounding modes, and other floating-point state.
<fenv.h>The main purpose is:
-
Detect and handle floating-point exceptions (such as division by zero, overflow, etc.).
-
Control the rounding mode for floating-point operations (such as round toward zero, round to nearest, etc.).
-
Query and modify floating-point status flags.
1、Floating-point exceptions
Floating-point exceptions are special situations that occur during floating-point operations, for example:
-
FE_DIVBYZERO: Divide by zero.
-
FE_INEXACT: Inexact result.
-
FE_INVALID: invalid operation (such as taking the square root of a negative number).
-
FE_OVERFLOW: Overflow.
-
FE_UNDERFLOW: Underflow.
These exceptions are represented by floating-point status flags, and can be<fenv.h>The functions therein detect and handle.
2、Rounding modes
The rounding mode controls the way floating-point operation results are rounded.<fenv.h>The following rounding modes are defined:
-
FE_TONEAREST: round to the nearest value (default mode).
-
FE_DOWNWARD: round toward negative infinity.
-
FE_UPWARD: round toward positive infinity.
-
FE_TOWARDZERO: Round toward zero.
3、Main functions and macros
<fenv.h>Provides a set of functions and macros for manipulating the floating-point environment and handling floating-point exceptions.
Floating-point exception handling
| Functions/Macros | Description |
|---|---|
feclearexcept(int excepts) |
Clear the specified floating-point exception flags |
feraiseexcept(int excepts) |
Raise the specified floating-point exception |
fetestexcept(int excepts) |
Test whether the specified floating-point exception occurred |
fegetexceptflag(fexcept_t *flagp, int excepts) |
Get the floating-point exception flag status |
fesetexceptflag(const fexcept_t *flagp, int excepts) |
Set the floating-point exception flag status |
Rounding mode control
| Functions/Macros | Description |
|---|---|
fegetround(void) |
Get the current rounding mode |
fesetround(int round) |
Set the current rounding mode |
Floating-point environment control
| Functions/Macros | Description |
|---|---|
fegetenv(fenv_t *envp) |
Save the current floating-point environment |
fesetenv(const fenv_t *envp) |
Restoring the floating-point environment |
feholdexcept(fenv_t *envp) |
Save the current floating-point environment and clear exception flags. |
feupdateenv(const fenv_t *envp) |
Restore the floating-point environment and raise exceptions |
4、Example
The following is an example using<fenv.h>An example of this, demonstrating how to detect floating-point exceptions and control the rounding mode:
Example
#include <fenv.h>
#include <math.h>
int main() {
// Enable floating-point exception detection
feclearexcept(FE_ALL_EXCEPT);
// Trigger divide-by-zero exception
double x = 1.0, y = 0.0;
double z = x / y;
// Check whether a divide-by-zero exception occurred
if (fetestexcept(FE_DIVBYZERO)) {
printf("Divide by zero exception occurred.\n");
}
// Set rounding mode to round toward zero
fesetround(FE_TOWARDZERO);
// Test rounding mode
double a = 1.5;
double b = rint(a); // Round to integer
printf("Rounding 1.5 toward zero: %.1f\n", b);
return 0;
}
The output result is:
Divide by zero exception occurred. Rounding 1.5 toward zero: 1.0
Detecting floating-point exceptions
Example
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
void check_exceptions() {
// Clear all exception flags
feclearexcept(FE_ALL_EXCEPT);
// Perform operations that may raise exceptions
double x = 0.0;
double y = 1.0 / x; // Divide by zero
// Check for a specific exception
if (fetestexcept(FE_DIVBYZERO)) {
printf("Division by zero occurred!\n");
}
// Check for any exception
if (fetestexcept(FE_ALL_EXCEPT)) {
printf("At least one floating-point exception occurred\n");
}
}
int main() {
check_exceptions();
return 0;
}
Controlling rounding direction
Example
#include <stdio.h>
#pragma STDC FENV_ACCESS ON
void test_rounding(double num) {
int modes[] = {FE_TONEAREST, FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO};
const char *names[] = {"Nearest", "Up", "Down", "Toward zero"};
for (int i = 0; i < 4; i++) {
if (fesetround(modes[i]) == 0) {
printf("Rounding %s: %.1f -> %.0f\n",
names[i], num, rint(num));
}
}
}
int main() {
test_rounding(2.5); // Test the result of 2.5 in different rounding modes
test_rounding(-2.5); // Test the result of -2.5 in different rounding modes
return 0;
}
Save and restore the floating-point environment
Example
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
void sensitive_calculation() {
fenv_t env;
// Save the current environment
fegetenv(&env);
// Set strict environment: catch all exceptions
feclearexcept(FE_ALL_EXCEPT);
// Perform critical calculation
double result = sqrt(-1.0); // Invalid operation
if (fetestexcept(FE_INVALID)) {
printf("Invalid operation detected in sensitive calculation\n");
}
// Restore original environment
fesetenv(&env);
}
int main() {
sensitive_calculation();
return 0;
}
Temporarily masking exceptions
Example
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
void temp_disable_exceptions() {
fenv_t env;
// Save environment and temporarily mask all exceptions
feholdexcept(&env);
// Perform operations that may raise exceptions
double x = 0.0;
double y = 1.0 / x; // No exceptions will be triggered
printf("Division by zero was performed but not reported\n");
// Restore environment and handle exceptions that occurred previously
feupdateenv(&env);
// Now exceptions can be checked
if (fetestexcept(FE_DIVBYZERO)) {
printf("Division by zero was detected after restoring environment\n");
}
}
int main() {
temp_disable_exceptions();
return 0;
}
Exact computation example
Example
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
double precise_sum(double a, double b) {
int original_round = fegetround();
fenv_t env;
// Save environment and set highest precision mode
fegetenv(&env);
fesetround(FE_TONEAREST);
feclearexcept(FE_ALL_EXCEPT);
double result = a + b;
// Check whether the calculation is exact
if (fetestexcept(FE_INEXACT)) {
printf("Warning: Sum was not exact, possible precision loss\n");
}
// Restore original environment
fesetround(original_round);
fesetenv(&env);
return result;
}
int main() {
double a = 1.0 / 3.0;
double b = 2.0 / 3.0;
printf("Sum: %.17g\n", precise_sum(a, b));
return 0;
}
Exception handling wrapper
Example
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
typedef double (*math_func)(double);
double safe_math(math_func f, double x, int *error) {
fenv_t env;
*error = 0;
feclearexcept(FE_ALL_EXCEPT);
fegetenv(&env);
double result = f(x);
int exceptions = fetestexcept(FE_ALL_EXCEPT);
if (exceptions) {
*error = exceptions;
if (exceptions & FE_INVALID) printf("Invalid operation\n");
if (exceptions & FE_DIVBYZERO) printf("Division by zero\n");
if (exceptions & FE_OVERFLOW) printf("Overflow\n");
if (exceptions & FE_UNDERFLOW) printf("Underflow\n");
if (exceptions & FE_INEXACT) printf("Inexact result\n");
}
fesetenv(&env);
return result;
}
int main() {
int error;
double a = safe_math(sqrt, -1.0, &error);
printf("sqrt(-1) = %f (error: %d)\n", a, error);
double b = safe_math(log, 0.0, &error);
printf("log(0) = %f (error: %d)\n", b, error);
return 0;
}
5、Notes
Before using floating-point environment features, it is usually necessary to enable#pragma STDC FENV_ACCESS ONto inform the compiler not to optimize away floating-point environment operations.
-
Not all implementations support all features; before use, you should check whether the macro FE_DFL_ENV is defined.
-
<fenv.h>Only available in C99 and later versions. -
The specific behavior of floating-point exception detection and rounding mode control may depend on the hardware and compiler implementation.
-
On some platforms, floating-point exceptions may be masked by default, and need to be
feenableexceptand other functions explicitly enable. -
Floating-point environment operations may affect performance and should be used with caution.
<fenv.h>Provides control functions for the floating-point environment, including detection and handling of floating-point exceptions, setting of rounding modes, and querying and modification of floating-point state. It is a powerful tool for high-precision floating-point computation and debugging floating-point problems, especially suitable for scientific computing and engineering applications. By using<fenv.h>, developers can better control the behavior of floating-point operations, ensuring the accuracy and reliability of computation results.