liveBook · Manning

Floating-point environment

As explained in Modern C, Third Edition

The floating-point environment is the implementation state that controls and records floating-point exception conditions and related behavior.

The floating-point environment is the implementation state that describes exceptional floating-point conditions and helps determine whether particular operations fail. The <fenv.h> header supplies exception macros, while fetestexcept and feclearexcept query and manage recorded conditions. section 15.1.1

Important portability rules:

  • Treat exception macros as bitsets; combine them with bitwise OR to represent several conditions. section 15.1.1
  • Test feature availability before relying on infinity or a particular exception condition, because supported behavior varies by platform. section 15.1.1
  • Clear recorded conditions before an operation, then test them afterward to distinguish exceptions produced by that operation. section 15.1.1
 bool const has_inf =
 #ifdef INFINITY
   (1.0/0.0 == INFINITY)
 #else
   false
 #endif
   ;

Checks whether the implementation provides infinity and whether division by zero produces INFINITY. section 15.1.1

 int excepts[] = {
 #ifdef FE_DIVBYZERO
   FE_DIVBYZERO,
 #endif
 #ifdef FE_INEXACT
   FE_INEXACT,
 #endif
 #ifdef FE_INVALID
   FE_INVALID,
 #endif
 #ifdef FE_OVERFLOW
   FE_OVERFLOW,
 #endif
 #ifdef FE_UNDERFLOW
   FE_UNDERFLOW,
 #endif
 };

Builds a portable list of exception conditions by including only macros supported by the implementation. section 15.1.1

 void printexcept(void) {
   char const* name[] = {
 #ifdef FE_DIVBYZERO
     "divbyzero",
 #endif
 #ifdef FE_INEXACT
     "inexact",
 #endif
 #ifdef FE_INVALID
     "invalid",
 #endif
 #ifdef FE_OVERFLOW
     "overflow",
 #endif
 #ifdef FE_UNDERFLOW
     "underflow",
 #endif
   };
   int except = fetestexcept(FE_ALL_EXCEPT);
   if (except) {
     printf("[");
     for (unsigned j = 0; except; except &= ~excepts[j], ++j)
       if (excepts[j] & except)
         printf("%s ", name[j]);
     printf("]");
   }
 }
 
 int main (int argc, char* argv[static argc+1]) {
   printf("division by zero is %sequal to INFINITY\n", has_inf ? "" : "un");
   for (unsigned i = 1; i < argc; i++) {
     feclearexcept(FE_ALL_EXCEPT);
     double x = strtod(argv[i], nullptr);
     printf("%g ", x);
     printexcept();
     feclearexcept(FE_ALL_EXCEPT);
     printf(": %g ", 1.0/x);
     printexcept();
     puts("");
   }
 }

Clears and reports floating-point exceptions around parsed values and reciprocal calculations. section 15.1.1

How Modern C, Third Edition covers it

How deep it goes
Defines exception macros and demonstrates testing and clearing conditions, but stops short of detailing environment-setting operations.
Examples
Uses conditional infinity detection, exception-macro enumeration, and reporting around string conversion and reciprocal calculation.
What it assumes
Assumes familiarity with C arithmetic and preprocessor conditionals while introducing floating-point exceptions and their implementation dependence.
What you can do after
Diagnose floating-point conditions with fetestexcept, clear them with feclearexcept, and guard behavior with implementation feature tests.
How it connects
Connects floating-point exceptions with division by zero, infinity, arithmetic violations, and feature tests.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C, Third Edition. The section links point to the parts of the book it draws on.