Go to main content
Oracle® Developer Studio 12.5: Numerical Computation Guide

Exit Print View

Updated: June 2016
 
 

4.3 Detecting Exceptions

As required by the IEEE standard, the floating-point environments on SPARC-based systems and x86-based systems provide status flags that record the occurrence of floating-point exceptions. A program can test these flags to determine which exceptions have occurred. The flags can also be explicitly set and cleared. The ieee_flags function provides one way to access these flags. In programs written in C or C++, the C99 floating-point environment functions provide another.

On SPARC-based systems, each exception has two flags associated with it, current and accrued. The current exception flags always indicate the exceptions raised by the last floating-point instruction to complete execution. These flags are also accumulated (i.e., “or”‐ed) into the accrued exception flags thereby providing a record of all untrapped exceptions that have occurred since the program began execution or since the accrued flags were last cleared by the program. When a floating-point instruction incurs a trapped exception, the current exception flag corresponding to the exception that caused the trap is set, but the accrued flags are unchanged. Both the current and accrued exception flags are contained in the floating-point status register, %fsr.

On x86-based systems, the floating-point status word (SW) provides flags for accrued exceptions as well as flags for the status of the floating-point stack. On x86-based systems that support SSE2 instructions, the MXCSR register contains flags that record accrued exceptions raised by those instructions.

4.3.1 ieee_flags(3m)

ieee_flags provides an interface for IEE 754 exception flags that is similar Oracle Developer Studio C, C++, and Fortran. However, this interface is only available on the Oracle Solaris OS. Use the C99 Exception Flag Functions for C and C++ programs that are intended to be more widely portable.

The syntax for a call to ieee_flags(3m) is:

i = ieee_flags(action, mode, in, out);

A program can test, set, or clear the accrued exception status flags using the ieee_flags function by supplying the string "exception" as the second argument. For example, to clear the overflow exception flag from Fortran, write:

      character*8 out
      call ieee_flags('clear', 'exception', 'overflow', out) 

To determine whether an exception has occurred from C or C++, use:

      i = ieee_flags("get", "exception", in, out); 

When the action is "get", the string returned in out is one of the following:

  • "not available" — if information on exceptions is not available

  • "" (an empty string) — if there are no accrued exceptions or, in the case of x86, the denormal operand is the only accrued exception

  • The name of the exception named in the third argument, in, if that exception has occurred

  • Otherwise, the name of the highest priority exception that has occurred

For example, in the following Fortran call the string returned in out is "division" if the division-by-zero exception has occurred. Otherwise it is the name of the highest priority exception that has occurred:

      character*8 out
      i = ieee_flags('get', 'exception', 'division', out)

Note that in is ignored unless it names a particular exception. For example, the argument "all" is ignored in the following C call:

      i = ieee_flags("get", "exception", "all", out); 

Besides returning the name of an exception in out, ieee_flags returns an integer value that combines all of the exception flags currently raised. This value is the bitwise “or” of all the accrued exception flags, where each flag is represented by a single bit as shown in Table 32. The positions of the bits corresponding to each exception are given by the fp_exception_type values defined in the file sys/ieeefp.h. (Note that these bit positions are machine-dependent and need not be contiguous.)

Table 32  Exception Bits
Exception
Bit Position
Accrued Exception Bit
invalid
fp_invalid
i & (1 << fp_invalid)
overflow
fp_overflow
i & (1 << fp_overflow)
division
fp_division
i & (1 << fp_division)
underflow
fp_underflow
i & (1 << fp_underflow)
inexact
fp_inexact
i & (1 << fp_inexact)
denormalized
fp_denormalized
i & (1 << fp_denormalized) (x86 only)

This fragment of a C or C++ program shows one way to decode the return value.

/*
 *   Decode integer that describes all accrued exceptions. 
 *   fp_inexact etc. are defined in <sys/ieeefp.h> 
 */ 
 
char *out; 
int invalid, division, overflow, underflow, inexact; 
 
code = ieee_flags("get", "exception", "", &out); 
printf ("out is %s, code is %d, in hex: 0x%08X\n", 
  out, code, code); 
inexact  =  (code >> fp_inexact) & 0x1; 
division  =  (code >> fp_division) & 0x1; 
underflow  =  (code >> fp_underflow) & 0x1; 
overflow  =  (code >> fp_overflow) & 0x1; 
invalid  =  (code >> fp_invalid) & 0x1; 
printf("%d %d %d %d %d \n", invalid, division, overflow,
  underflow, inexact); 

4.3.2 C99 Exception Flag Functions

C/C++ programs can test, set, and clear the floating-point exception flags using the C99 floating-point environment functions. The header file fenv.h defines five macros corresponding to the five standard exceptions: FE_INEXACT, FE_UNDERFLOW, FE_OVERFLOW, FE_DIVBYZERO, and FE_INVALID. It also defines the macro FE_ALL_EXCEPT to be the bitwise “or” of all five exception macros. These macros can be combined to test or clear any subset of the exception flags or raise any combination of exceptions. The following examples show the use of these macros with several of the C99 floating-point environment functions. See the feclearexcept(3M) manual page for more information.


Note -  For consistent behavior, do not use both the C99 floating-point environment functions and extensions in libm and the ieee_flags and ieee_handler functions in libsunmath in the same program.

To clear all five exception flags, use the following:

feclearexcept(FE_ALL_EXCEPT);

To test whether the invalid operation or division by zero flags have been raised, use the following:

int i;

i = fetestexcept(FE_INVALID | FE_DIVBYZERO);
if (i & FE_INVALID)
    /* invalid flag was raised */
else if (i & FE_DIVBYZERO)
    /* division-by-zero flag was raised */

The fegetexceptflag and fesetexceptflag functions provide a way to save and restore a subset of the flags. The next example shows one way to use these functions.

fexcept_t flags;
 
/* save the underflow, overflow, and inexact flags */
fegetexceptflag(&flags, FE_UNDERFLOW | FE_OVERFLOW | FE_INEXACT);
/* clear these flags */
feclearexcept(FE_UNDERFLOW | FE_OVERFLOW | FE_INEXACT);
/* do a computation that can underflow or overflow */
...
/* check for underflow or overflow */
if (fetestexcept(FE_UNDERFLOW | FE_OVERFLOW) != 0) {
    ...
}
/* restore the underflow, overflow, and inexact flags */
fesetexceptflag(&flags, FE_UNDERFLOW | FE_OVERFLOW, | FE_INEXACT);