Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Operating System

How to handle floating point errors

Linux
Solaris 10
AIX 5.3
HP-UX 11.31
Mac OS X 10.5

Use the C99 floating-point exception functions.

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="1e4394f87677473f-cd8f5a32-4ab142a1-b51f859f-60f00ac1509474fa5df7a327"><ac:plain-text-body><![CDATA[

Windows

Either use the C99 floating-point exception function or structured exception handling through _fpieee_flt [[MSDN

AA. Bibliography#MSDN]]

]]></ac:plain-text-body></ac:structured-macro>

...

In this noncompliant code example, floating-point operations are performed without checking for errors. Note that range checking has been intentionally omitted because the intent is to detect errors following the floating-point operation.

Code Block
bgColor#FFCCCC
langc
void fpOper_noErrorChecking(void) {
  /* ... */
  double a = 1e-40, b, c = 0.1;
  float x = 0, y;
  /* inexact and underflows */
  y = a;
  /* divide by zero operation */
  b = y / x;
  /* inexact (loss of precision) */
  c = sin(30) * a;
  /* ... */
}

...

This compliant solution uses C99 standard functions to handle floating-point errors.

Code Block
bgColor#ccccff
langc
#include <fenv.h>
#pragma STDC FENV_ACCESS ON

void fpOper_fenv(void) {
  double a = 1e-40, b, c = 0.1;
  float x = 0, y;
  int fpeRaised;
  /* ... */

  feclearexcept(FE_ALL_EXCEPT);
  /* Store a into y is inexact and underflows: */
  y = a;
  fpeRaised = fetestexcept(FE_ALL_EXCEPT);
  /* fpeRaised  has FE_INEXACT and FE_UNDERFLOW */

  feclearexcept(FE_ALL_EXCEPT);

  /* divide by zero operation */
  b = y / x;
  fpeRaised = fetestexcept(FE_ALL_EXCEPT);
  /* fpeRaised has FE_DIVBYZERO */

  feclearexcept(FE_ALL_EXCEPT);

  c = sin(30) * a;
  fpeRaised = fetestexcept(FE_ALL_EXCEPT);
  /* fpeRaised has FE_INEXACT */

  feclearexcept(FE_ALL_EXCEPT);
  /* ... */
}

...

Microsoft Visual Studio 2008 and earlier versions do not support C99 functions to handle floating-point errors. Windows provides an alternative method for handling floating-point errors using _statusfp(), _statusfp2(), and _clearfp().

Code Block
bgColor#ccccff
langc
void fpOper_usingStatus(void) {
  /* ... */
  double a = 1e-40, b, c;
  float x = 0, y;
  unsigned int rv = _clearfp();

  /* Store into y is inexact and underflows: */
  y = a;
  rv = _clearfp();  /* rv has _SW_INEXACT and _SW_UNDERFLOW */

  /* zero-divide */
  b = y / x; rv = _clearfp(); /* rv has _SW_ZERODIVIDE */

  /* inexact */
  c = sin(30) * a; rv = _clearfp(); /* rv has _SW_INEXACT */
  /* ... */
}

...

Microsoft Visual Studio 2008 also uses structured exception handling (SEH) to handle floating-point operation. SEH provides more information about the error and allows the programmer to change the results of the floating-point operation that caused the error condition.

Code Block
bgColor#ccccff
langc
void fp_usingSEH(void) {
  /* ... */
  double a = 1e-40, b, c = 0.1;
  float x = 0, y;
  unsigned int rv ;

  unmask_fpsr();

  _try {
    /* Store into y is inexact and underflows */
    y = a;

    /* divide by zero operation */
    b = y / x;

    /* inexact */
    c = sin(30) * a;
  }

  _except (_fpieee_flt(
             GetExceptionCode(),
             GetExceptionInformation(),
             fpieee_handler)) {
  {
  printf ("fpieee_handler: EXCEPTION_EXECUTE_HANDLER");
  }

  /* ... */
}

void unmask_fpsr(void) {
  unsigned int u;
  unsigned int control_word;
  _controlfp_s(&control_word, 0, 0);
  u = control_word & ~(_EM_INVALID
                     | _EM_DENORMAL
                     | _EM_ZERODIVIDE
                     | _EM_OVERFLOW
                     | _EM_UNDERFLOW
                     | _EM_INEXACT);
  _controlfp_s( &control_word, u, _MCW_EM);
  return ;
}

int fpieee_handler(_FPIEEE_RECORD *ieee) {
  /* ... */

  switch (ieee->RoundingMode) {
    case _FpRoundNearest:
      /* ... */
      break;

      /* Other RMs include _FpRoundMinusInfinity,
       * _FpRoundPlusInfinity, _FpRoundChopped */

      /* ... */
    }

  switch (ieee->Precision) {
    case _FpPrecision24:
      /* ... */
      break;

      /* Other Ps include _FpPrecision53*/
      /* ... */
    }

   switch (ieee->Operation) {
     case _FpCodeAdd:
       /* ... */
       break;

       /* Other Ops include _FpCodeSubtract, _FpCodeMultiply,
        * _FpCodeDivide, _FpCodeSquareRoot, _FpCodeCompare,
        * _FpCodeConvert, _FpCodeConvertTrunc */
       /* ... */
    }

  /* 
   * process the bitmap ieee->Cause.
   * process the bitmap ieee->Enable.
   * process the bitmap ieee->Status.
   * process the Operand ieee->Operand1, 
   * evaluate format and Value.
   * process the Operand ieee->Operand2, 
   * evaluate format and Value.
   * process the Result ieee->Result, 
   * evaluate format and Value .
   * The result should be set according to the operation 
   * specified in ieee->Cause and the result format as 
   * specified in ieee->Result.
   */

  /* ... */
}

...