Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
HP-UX Floating-Point Guide: HP 9000 Computers > Chapter 5 Manipulating the Floating-Point Status Register

Run-Time Mode Control: The fenv(5) Suite

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

 » Glossary

 » Index

This section describes the fenv(5) suite of functions, a collection of services provided in the C math library that allow an application to manipulate several modifiable control mode and status flags in the floating-point status register. These functions and their associated parameter types are declared in the header file /usr/include/fenv.h.

NOTE: The fenv(5) suite replaces the fpgetround(3M) suite of functions.

You can call these functions from Fortran programs. See “A Program Example” for examples.

The fenv(5) suite contains the following functions:

  • fegetenv and fesetenv, which retrieve and set the floating-point environment

  • feholdexcept and feupdateenv, which can be used to hide spurious exceptions

  • fegetexceptflag and fesetexceptflag, which retrieve and set the accrued exception flags

  • feraiseexcept, fetestexcept, and feclearexcept, which raise, test, and clear exceptions

  • fegetround and fesetround, which retrieve and set the rounding mode

  • fegettrapenable and fesettrapenable, which retrieve and set the exception trap enable bits

  • fegetflushtozero and fesetflushtozero, which retrieve and set the underflow mode

All of these functions except the last four (fegettrapenable, fesettrapenable, fegetflushtozero, and fesetflushtozero) have been included in the C9X draft standard by the ANSI/ISO C committee.

NOTE: Be careful if you use these functions at higher optimization levels (2 and above). Optimization may change the order of operations in a program, so that a call to one of these functions may be placed after an operation you want the function to affect, or before an operation whose result you want the function to check. These functions will then produce unexpected results. (If it is possible to isolate the part or parts of your program that call these functions, you could place them in a separate module and compile it at a lower optimization level than the rest of the program. You may also use the FLOAT_TRAPS_ON pragma to suppress optimization for part of your program. For information, see the C online help (cc +help).

The PA-RISC Floating-Point Status Register

The PA-RISC floating-point status register is fr0L, the left half of fr0.

Figure 5-1 “PA-RISC Floating-Point Status Register (fr0L)” shows the structure and contents of fr0L. Fields marked Res are reserved for future use.

Figure 5-1 PA-RISC Floating-Point Status Register (fr0L)

PA-RISC Floating-Point Status Register (fr0L)

PA-RISC 2.0 Architecture and the PA-RISC 1.1 Architecture and Instruction Set Reference Manual describe the contents of fr0L in detail. The fields manipulated by the fenv(5) functions are as follows:

Flags

Exception flags. A flag bit is associated with each IEEE exception. If the corresponding enable bit is not set, the floating-point unit sets an exception flag to 1 when the corresponding exception occurs, but does not cause a trap. Table 5-1 “IEEE Exception Bits” shows the bit names and the corresponding exceptions. The functions fegetexceptflag, fesetexceptflag, feclearexcept, fetestexcept, and feraiseexcept manipulate these flags.

Table 5-1 IEEE Exception Bits

Bit Name

Description

V

Invalid operation

Z

Division by zero

O

Overflow

U

Underflow

I

Inexact result

 

Enables

Exception trap enable bits. An enable bit is associated with each IEEE exception. When an enable bit equals 1, the corresponding trap is enabled. When an enable bit equals 0, the corresponding IEEE exception sets the corresponding flag to 1 instead of causing a trap. The functions fegettrapenable and fegettrapenable manipulate these bits.

RM

Rounding mode for all floating-point operations. The values corresponding to each rounding mode are shown in Table 5-2 “Rounding Modes”. The functions fegetround and fesetround manipulate these bits.

Table 5-2 Rounding Modes

Rounding Mode

Description

0

Round to nearest

1

Round toward zero

2

Round toward +infinity

3

Round toward -infinity

 

D

The D bit. When this bit is set to 1, flush-to-zero underflow mode is enabled (see “Underflow Mode: fegetflushtozero and fesetflushtozero”). The functions fegetflushtozero and fesetflushtozero manipulate this bit.

The fields not manipulated by the fenv(5) functions are as follows:

C

The Compare bit.

Res

Reserved for future use.

Model, Revision

The Model and Revision fields contain values that correspond to various implementations of HP 9000 ­floating-point coprocessors.

T

The Delayed Trap bit.

Rounding Mode: fegetround and fesetround

The functions fegetround and fesetround allow you to retrieve or change the rounding mode for floating-point operations. The declarations for these functions are as follows:

int fegetround(void);
int fesetround(int round);

The value returned by fegetround and the argument of fesetround match one of the rounding direction macros defined in fenv.h. The rounding direction macros are as follows:

FE_TONEAREST

Round to nearest

FE_TOWARDZERO

Round toward zero

FE_UPWARD

Round toward positive infinity

FE_DOWNWARD

Round toward negative infinity

The fegetround function returns the current rounding mode. By default, the rounding mode is FE_TONEAREST.

The fesetround function sets the rounding mode to the specified value. It returns a nonzero value if and only if the argument matches a rounding direction macro.

The following C program uses fesetround and fegetround to show how the rounding mode affects the result of an overflow (see Table 2-11 “Overflow Results Based on Rounding Mode”).

Example 5-1 Sample Program: fe_round.c

/*************************************************************/
#include <stdio.h>
#include <fenv.h>

int main(void)
{
int save_rnd, rnd;
double x, y, z;

save_rnd = fegetround();
if (save_rnd == FE_TONEAREST)
printf("rounding direction is FE_TONEAREST\n");
else
printf("unexpected rounding direction\n");

x = 1.79e308;
y = 2.2e-308;
z = x / y; /* overflow */
printf("%g / %g = %g\n", x, y, z);

x = -1.79e308;
y = 2.2e-308;
z = x / y; /* negative overflow */
printf("%g / %g = %g\n", x, y, z);

fesetround(FE_TOWARDZERO);
rnd = fegetround();
if (rnd == FE_TOWARDZERO)
printf("rounding direction is FE_TOWARDZERO\n");
else
printf("unexpected rounding direction\n");

x = 1.79e308;
y = 2.2e-308;
z = x / y; /* overflow */
printf("%g / %g = %g\n", x, y, z);

fesetround(FE_UPWARD);
rnd = fegetround();
if (rnd == FE_UPWARD)
printf("rounding direction is FE_UPWARD\n");
else
printf("unexpected rounding direction\n");
/* continued */
/*************************************************************/

Example 5-2 Sample Program: fe_round.c (cont.)

/*************************************************************/
x = -1.79e308;
y = 2.2e-308;
z = x / y; /* negative overflow */
printf("%g / %g = %g\n", x, y, z);

/* return to round-to-nearest */
fesetround(save_rnd);
rnd = fegetround();
if (rnd == FE_TONEAREST)
printf("rounding direction is FE_TONEAREST\n");
else
printf("unexpected rounding direction\n");
}
/*************************************************************/

If you compile and run this program, it produces the following output:

$ cc fe_round.c -lm
$ ./a.out
rounding direction is FE_TONEAREST
1.79e+308 / 2.2e-308 = inf
-1.79e+308 / 2.2e-308 = -inf
rounding direction is FE_TOWARDZERO
1.79e+308 / 2.2e-308 = 1.79769e+308
rounding direction is FE_UPWARD
-1.79e+308 / 2.2e-308 = -1.79769e+308
rounding direction is FE_TONEAREST

See “IEEE Rounding Modes” for more information about rounding modes on HP 9000 systems.

Exception Bits

The IEEE-754 standard specifies five floating-point exceptions: divide-by-zero, overflow, underflow, inexact result, and invalid operation. If one of these five exceptions occurs and the corresponding exception trap enable bit is set to 0,the corresponding exception flag is set to 1 and no trap takes place. If an exception occurs and the exception trap enable bit is set to 1,the trap takes place, and a SIGFPE signal is generated. The exception trap enable bits are sometimes called mask bits; the exception flags are sometimes called sticky bits. The term sticky follows from the fact that once an exception flag is set by an exception whose trap is disabled, it remains set for the life of the process unless it is cleared by the application (for example, by a call to fesetexceptflag or feclearexcept).

The C library supplies a group of functions, all included in the C9X draft standard, to manipulate the exception flags. The library also supplies two functions, not included in the C9X draft standard and specific to HP, to manipulate the exception trap enable bits. The following subsections discuss these groups of functions.

The functions use the following exception macros, defined in fenv.h, for the exception flags and the exception trap enable bits:

FE_INEXACT

Inexact result

FE_UNDERFLOW

Underflow

FE_OVERFLOW

Overflow

FE_DIVBYZERO

Divide by zero

FE_INVALID

Invalid operation

FE_ALL_EXCEPT

All exceptions

For details about using these functions to detect and handle floating-point exceptions, see “Using the fesettrapenable Function” and “Detecting Exceptions without Enabling Traps”.

Manipulating the Exception Flags: fegetexceptflag, fesetexceptflag, fetestexcept, feraiseexcept, feclearexcept

The functions fegetexceptflag and fetestexcept return the current settings of the exception flags. The fesetexceptflag function sets the flags to a previously saved state. The feraiseexcept function raises exceptions, and the feclearexcept function clears the exception flags.

The C declarations for these functions are as follows:

void fegetexceptflag(fexcept_t *flagp, int excepts);
void fesetexceptflag(const fexcept_t *flagp, int excepts);
int fetestexcept(int excepts);
void feraiseexcept(int excepts);
void feclearexcept(int excepts);

The fegetexceptflag function stores the desired exception flags (as indicated by the argument excepts, which can be any bitwise OR of the exception macros) in the object pointed to by the argument flagp.

The fesetexceptflag function sets the status for the exception flags indicated by the argument excepts according to the representation in the object pointed to by flagp. Use it to reset the exception flags to a previously saved state.

The fetestexcept function determines which of a specified subset of the exception flags are currently set.

The feraiseexcept function raises the exceptions represented by its argument (and causes traps if the corresponding traps are enabled). It allows you to raise exceptions directly without having to write operations in your program that generate an exception.

The feclearexcept function clears the exception flags represented by its argument.

The following program uses all these functions. First it calls fegetexceptflag to retrieve the initial settings of the exception flags. Then it calls feraiseexcept to raise a couple of exceptions, and calls fetestexcept to verify that the flags are set correctly. Then it calls feclearexcept to clear the accumulated flags, and after another call to fetestexcept it calls feraiseexcept again to set the underflow exception. The next call to fetestexcept shows that, as with basic operations, raising the underflow exception also raises the inexact exception on HP systems. Finally, the program calls fesetexceptflag to restore the initial state of the exception flags.

Example 5-3 Sample Program: fe_flags.c

/*************************************************************/
#include <stdio.h>
#include <fenv.h>

int main(void)
{
fexcept_t flags;
int excepts;
void print_flags(int);

fegetexceptflag(&flags, FE_ALL_EXCEPT);
printf("at start:\n");
print_flags(flags);

/* raise divide-by-zero exception */
feraiseexcept(FE_DIVBYZERO);
excepts = fetestexcept(FE_DIVBYZERO | FE_INEXACT);
printf("after raising divide-by-zero exception:\n");
print_flags(excepts);
/* continued */
/*************************************************************/

Example 5-4 Sample Program: fe_flags.c (cont.)

/*************************************************************/
/* raise divide-by-zero exception */
feraiseexcept(FE_DIVBYZERO);
excepts = fetestexcept(FE_DIVBYZERO | FE_INEXACT);
printf("after raising divide-by-zero exception:\n");
print_flags(excepts);

/* raise inexact exception */
feraiseexcept(FE_INEXACT);
excepts = fetestexcept(FE_DIVBYZERO | FE_INEXACT);
printf("after raising inexact exception:\n");
print_flags(excepts);

/* clear exceptions, retrieve new setting */
feclearexcept(FE_ALL_EXCEPT);
excepts = fetestexcept(FE_ALL_EXCEPT);
printf("after clearing exceptions:\n");
print_flags(excepts);

/* raise underflow exception; inexact also set */
feraiseexcept(FE_UNDERFLOW);
excepts = fetestexcept(FE_ALL_EXCEPT);
printf("after raising underflow exception:\n");
print_flags(excepts);

/* restore original state of flags */
fesetexceptflag(&flags, FE_ALL_EXCEPT);
printf("after fesetexceptflag:\n");
excepts = fetestexcept(FE_ALL_EXCEPT);
print_flags(excepts);
}

void print_flags(int flags)
{
if (flags & FE_INEXACT)
printf(" inexact result occurred\n");
if (flags & FE_UNDERFLOW)
printf(" underflow occurred\n");
if (flags & FE_OVERFLOW)
printf(" overflow occurred\n");
if (flags & FE_DIVBYZERO)
printf(" division by zero occurred\n");
if (flags & FE_INVALID)
printf(" invalid operation occurred\n");

if (!(flags & FE_ALL_EXCEPT))
printf(" no exceptions are set\n");
}
/*************************************************************/

If you run this program, it generates the following output:

$ cc fe_flags.c -lm
$ ./a.out
at start:
no exceptions are set
after raising divide-by-zero exception:
division by zero occurred
after raising inexact exception:
inexact result occurred
division by zero occurred
after clearing exceptions:
no exceptions are set
after raising underflow exception:
inexact result occurred
underflow occurred
after fesetexceptflag:
no exceptions are set

Manipulating the Exception Trap Enable Bits: fegettrapenable and fesettrapenable

The fegettrapenable function retrieves the current setting of the exception trap enable bits. The fesettrapenable function sets the trap enable bits.

The C declarations for these functions are as follows:

int fegettrapenable(void);
void fesettrapenable(int excepts);

The fegettrapenable function returns the bitwise OR of the exception macros corresponding to the currently set exception trap enable bits.

The fesettrapenable function sets the exception trap enable bits indicated by the argument excepts, which is a bitwise OR of the exception macros corresponding to the desired exception trap enable bits. The function also clears the trap enable bits for any exceptions not indicated by the argument excepts.

The following program calls these functions.

Example 5-5 Sample Program: fe_traps.c

/*************************************************************/
#include <stdio.h>
#include <fenv.h>
#include <signal.h>

int traps;
fexcept_t flags;

/* trap handler for floating-point exceptions */
void handle_sigfpe(int sig)
{
void print_flags(int);
void print_traps(int);

printf("Raised signal %d -- floating point error\n", sig);
print_traps(traps);
print_flags(flags);
exit(-1);
}

int main(void)
{
void print_flags(int);
void print_traps(int);
struct sigaction act;

/* establish the trap handler */
act.sa_handler = &handle_sigfpe;
sigaction(SIGFPE, &act, NULL);

/* retrieve initial settings of flags and traps */
traps = fegettrapenable();
fegetexceptflag(&flags, FE_ALL_EXCEPT);
printf("at start:\n");
print_traps(traps);
print_flags(flags);

/* set a trap for the divide by zero exception */
fesettrapenable(FE_DIVBYZERO);
traps = fegettrapenable();
printf("after fesettrapenable(FE_DIVBYZERO):\n");
print_traps(traps);

/* raise divide by zero exception with trap enabled;
trap handler is called */
printf("raising division by zero exception now\n");
feraiseexcept(FE_DIVBYZERO);
} /* continued */
/*************************************************************/

Example 5-6 Sample Program: fe_traps.c (cont.)

/*************************************************************/
void print_flags(int flags)
{
if (flags & FE_INEXACT)
printf(" inexact result flag set\n");
if (flags & FE_UNDERFLOW)
printf(" underflow flag set\n");
if (flags & FE_OVERFLOW)
printf(" overflow flag set\n");
if (flags & FE_DIVBYZERO)
printf(" division by zero flag set\n");
if (flags & FE_INVALID)
printf(" invalid operation flag set\n");

if (!(flags & FE_ALL_EXCEPT))
printf(" no exception flags are set\n");
}

void print_traps(int traps)
{
if (traps & FE_INEXACT)
printf(" inexact result trap enabled\n");
if (traps & FE_UNDERFLOW)
printf(" underflow trap enabled\n");
if (traps & FE_OVERFLOW)
printf(" overflow trap enabled\n");
if (traps & FE_DIVBYZERO)
printf(" division by zero trap enabled\n");
if (traps & FE_INVALID)
printf(" invalid operation trap enabled\n");

if (!(traps & FE_ALL_EXCEPT))
printf(" no traps are enabled\n");
}
/*************************************************************/

If you run this program, it produces the following output:

$ cc fe_traps.c -lm
$ ./a.out
at start:
no traps are enabled
no exception flags are set
after fesettrapenable(FE_DIVBYZERO):
division by zero trap enabled
raising division by zero exception now
Raised signal 8 -- floating point error
division by zero trap enabled
no exception flags are set

Manipulating the Floating-Point Environment: fegetenv, fesetenv, feupdateenv, feholdexcept

The fenv(5) suite includes a group of functions that allow you to manage the floating-point environment as a whole. The declarations for these functions are as follows.

void fegetenv(fenv_t *envp);
void fesetenv(const fenv_t *envp);
void feupdateenv(const fenv_t *envp);
int feholdexcept(fenv_t *envp);

All these functions take as argument a value representing the floating-point environment.

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

The fesetenv function establishes the floating-point environment represented by the object pointed to by envp. The argument envp must point to an object set by a call to fegetenv or feholdexcept, or equal the macro FE_DFL_ENV.

The feupdateenv function saves the current exceptions in its automatic storage, installs the floating-point environment represented through envp, and then raises the saved exceptions. The argument envp must point to an object set by a call to fegetenv or feholdexcept, or equal the macro FE_DFL_ENV.

The feholdexcept function saves the current floating-point environment in the object pointed to by envp, clears the exception flags, and disables all traps.

The functions can be used together to save and restore the floating-point environment at different parts of your program and in different ways, so that you can control whether selected exceptions are hidden from calling routines. For example, you can call feholdexcept to store the floating-point environment temporarily and start afresh with no flags or traps set. Later on, you can use either fesetenv or feupdateenv to restore the saved environment, or save and update it. A call to fesetenv does not raise any saved exceptions, however, whereas a call to feupdateenv does raise the exceptions.

The following program shows the use of all these functions except feupdateenv.

Example 5-7 Sample Program: fe_env.c

/*************************************************************/
#include <stdio.h>
#include <fenv.h>

int main(void)
{
double x, y, z;
fenv_t env, holdenv;
int set_excepts;
fexcept_t flags;
char c = ' ';
void print_flags(int);

fegetenv(&env);
printf("at start, env is %08x\n", env);

do {
printf("\nEnter x and y: ");
scanf("%lf %lf", &x, &y);
printf("x and y are %g and %g\n", x, y);

z = x/y; /* perform calculations */

set_excepts = fetestexcept(FE_ALL_EXCEPT);
print_flags(set_excepts);
printf("result is %g\n", z);
printf("again? (y or n) ");
fflush(stdin);
scanf("%c", &c);
} while (c != 'n');

printf("enabling trap for inexact\n");
fesettrapenable(FE_INEXACT);

fegetenv(&env);
printf("after calculations and enabling inexact trap, \
env is %08x\n", env);

printf("saving environment\n");
/* continued */
/*************************************************************/

Example 5-8 Sample Program: fe_env.c (cont.)

/*************************************************************/
feholdexcept(&holdenv);

do {
printf("\nEnter x and y: ");
scanf("%lf %lf", &x, &y);
printf("x and y are %g and %g\n", x, y);

z = x/y; /* perform calculations */

set_excepts = fetestexcept(FE_ALL_EXCEPT);
print_flags(set_excepts);
printf("result is %g\n", z);
printf("again? (y or n) ");
fflush(stdin);
scanf("%c", &c);
} while (c != 'n');

fegetenv(&env);
printf("after more calculations, env is %08x\n", env);

printf("resetting env to saved version\n");
fesetenv(&holdenv);
set_excepts = fetestexcept(FE_ALL_EXCEPT);
print_flags(set_excepts);

fegetenv(&env);
printf("env is %08x\n", env);

feclearexcept(FE_UNDERFLOW | FE_INEXACT);
fegetenv(&env);
printf("after feclearexcept(FE_UNDERFLOW | FE_INEXACT), \
env is %08x\n", env);
set_excepts = fetestexcept(FE_ALL_EXCEPT);
print_flags(set_excepts);

fesetenv(FE_DFL_ENV);
fegetenv(&env);
printf("after fesetenv(FE_DFL_ENV), env is %08x\n", env);
}

void print_flags(int flags)
{
if (flags & FE_INEXACT)
printf(" inexact result occurred\n");
if (flags & FE_UNDERFLOW)
printf(" underflow occurred\n");
if (flags & FE_OVERFLOW)
printf(" overflow occurred\n");
if (flags & FE_DIVBYZERO)
printf(" division by zero occurred\n");
if (flags & FE_INVALID)
printf(" invalid operation occurred\n");

if (!(flags & FE_ALL_EXCEPT))
printf(" no exceptions are set\n");
}
/*************************************************************/

If you compile and run this program, the call to fesetenv restores the environment without raising the inexact exception, so the inexact trap is not taken even though it is set.

$ fe_env
at start, env is 000b0800

Enter x and y: 1.0e308 1.0e-308
x and y are 1e+308 and 1e-308
inexact result occurred
overflow occurred
result is inf
again? (y or n) n
setting trap for inexact
after calculations and enabling inexact trap, env is 280b0801
saving environment

Enter x and y: 1.0e-308 1.0e308
x and y are 1e-308 and 1e+308
inexact result occurred
underflow occurred
result is 0
again? (y or n) n
after more calculations, env is 1c0b0800
resetting env to saved version
inexact result occurred
overflow occurred
env is 2c0b0801
after feclearexcept(FE_UNDERFLOW | FE_INEXACT), env is 240b0801
overflow occurred
after fesetenv(FE_DFL_ENV), env is 040b0800

The following program illustrates the use of the feupdateenv function.This program computes a sum of squares. Some of the intermediate computations may underflow, but only if the final result underflows or overflows do we want to raise an exception. Therefore, after setting traps for underflow and overflow exceptions, the program calls feholdexcept to save the previously accumulated exceptions. After performing the intermediate computations, it clears any underflow or inexact exceptions, then calls feupdateenv to merge the current exceptions with the previously accumulated ones.

Example 5-9 Sample Program: fe_update.c

/*************************************************************/
#include <stdio.h>
#include <float.h>
#include <fenv.h>

#define ARRLEN 11

static double argarr[ARRLEN] = { -1.73205, -0.57735,
0.0174551, 0.57735, 1.0, 1.73205,
2.0, -1.22465e-244,
-2.44929e-207, -1.0 };

int main(void)
{
double x, y, z;
fenv_t env, holdenv;
int set_excepts, i;
fexcept_t flags;
char c = ' ';
void print_flags(int);

fegetenv(&env);
printf("at start, env is %08x\n", env);

do {
printf("\nEnter x and y: ");
scanf("%lf %lf", &x, &y);
printf("x and y are %g and %g\n", x, y);

z = x/y; /* perform calculations */

set_excepts = fetestexcept(FE_ALL_EXCEPT);
print_flags(set_excepts);
printf("result is %g\n", z);
printf("again? (y or n) ");
fflush(stdin);
scanf("%c", &c);
} while (c != 'n');

printf("setting traps for overflow and underflow\n");
fesettrapenable(FE_OVERFLOW | FE_UNDERFLOW);

fegetenv(&env);
printf("after calculations, env is %08x\n", env);

printf("saving environment\n");
/* continued */
/*************************************************************/

Example 5-10 Sample Program: fe_update.c (cont.)

/*************************************************************/
feholdexcept(&holdenv);

/* accumulate sum of squares */
for (i = 0; i < ARRLEN; i++) {
z = argarr[i] * argarr[i];
y +=z;
}

set_excepts = fetestexcept(FE_ALL_EXCEPT);
print_flags(set_excepts);
printf("sum of squares is %g\n", y);

fegetenv(&env);
printf("after more calculations, env is %08x\n", env);

if (y >= DBL_MIN) {
printf("clearing underflow & inexact exceptions\n");
feclearexcept(FE_UNDERFLOW | FE_INEXACT);
}
else {
printf("clearing inexact exception\n");
feclearexcept(FE_INEXACT);
}

fegetenv(&env);
printf("after feclearexcept, env is %08x\n", env);

printf("merging env with saved version\n");
feupdateenv(&holdenv);
fegetenv(&env);
printf("after feupdateenv, env is %08x\n", env);

set_excepts = fetestexcept(FE_ALL_EXCEPT);
print_flags(set_excepts);
}

void print_flags(int flags)
{
if (flags & FE_INEXACT)
printf(" inexact result occurred\n");
if (flags & FE_UNDERFLOW)
printf(" underflow occurred\n");
if (flags & FE_OVERFLOW)
printf(" overflow occurred\n");
if (flags & FE_DIVBYZERO)
printf(" division by zero occurred\n");
if (flags & FE_INVALID)
printf(" invalid operation occurred\n");

if (!(flags & FE_ALL_EXCEPT))
printf(" no exceptions are set\n");
}
/*************************************************************/

If you compile and run this program, it produces results like the following:

$ cc fe_update.c -lm
$ ./a.out
at start, env is 00000000

Enter x and y: 3 0
x and y are 3 and 0
division by zero occurred
result is inf
again? (y or n) n
setting traps for overflow and underflow
after calculations, env is 44200006
saving environment
inexact result occurred
underflow occurred
sum of squares is 12.667
after more calculations, env is 18180000
clearing underflow & inexact exceptions
after feclearexcept, env is 040c0000
merging env with saved version
after feupdateenv, env is 440c0006
division by zero occurred

Underflow Mode: fegetflushtozero and fesetflushtozero

The functions fegetflushtozero and fesetflushtozero allow the programmer to retrieve the current underflow mode or to change the way the system handles underflows by setting the D bit in the status register to either 1 or 0.

Flush-to-zero mode, also known as fast underflow mode, sudden underflow mode, or fastmode, is an alternative to IEEE-754-compliant underflow mode. On HP 9000 systems, a floating-point underflow involves a fault into the kernel, where the IEEE-754-specified conversion of the result into a denormalized value or zero is accomplished by software emulation. On many HP 9000 systems, flush-to-zero mode allows the hardware to simply substitute a zero for the result of an operation, with no fault occurring. (The zero has the sign of the result for which it is substituted.) This may be a significant performance optimization for applications that underflow frequently and that can tolerate the accuracy loss, in denormalized values, that results from flush-to-zero mode. For many operations, flush-to-zero mode also causes denormalized floating-point operands to be treated as if they were true zero operands.

NOTE: Flush-to-zero mode is supported on all HP 9000 systems except those with chip levels of PA7000 and PA7100LC. You can look up the chip level of your system in /opt/langtools/lib/sched.models. See “Determining Your System's Architecture Type” for more information.

Use caution in changing the underflow mode when you call math library routines. Setting flush-to-zero mode may affect non-denormalized results of math library routine calls.

The C declarations for these functions are as follows:

int fegetflushtozero(void);
void fesetflushtozero(int value);

The fegetflushtozero function returns the current flush-to-zero mode setting: a result of 1 means that flush-to-zero mode is set, a result of 0 means that the default IEEE-754-compliant underflow mode is set. On systems that do not support flush-to-zero mode, this function always returns 0.

On systems that support flush-to-zero mode, the fesetflushtozero function sets flush-to-zero mode to value, which must be either 1 (flush-to-zero mode) or 0 (IEEE-754-compliant underflow mode). On systems that do not support flush-to-zero mode, this function has no effect.

On systems that support flush-to-zero mode, the default setting is IEEE-754-compliant underflow mode (0).

The following program calls fegetflushtozero and fesetflushtozero to retrieve and set the underflow mode.

Example 5-11 Sample Program: fe_flush.c

/*************************************************************/
#include <stdio.h>
#include <fenv.h>

typedef union {
double y;
struct {
unsigned int ym, yl;
} i;
} DBL_INT;

int main(void)
{
DBL_INT dix, diy, diz;
int fm, fm_saved;

fm_saved = fegetflushtozero();
printf("underflow mode is %d\n", fm_saved);

dix.y = -4.94066e-324;
printf("denormalized value is %g [%08x%08x]\n", dix.y,
dix.i.ym, dix.i.yl);

fesetflushtozero(1);
fm = fegetflushtozero();
printf("after fesetflushtozero(1), mode is %d\n", fm);
printf("denormalized value is %g [%08x%08x]\n", dix.y,
dix.i.ym, dix.i.yl);

fesetflushtozero(fm_saved);
fm = fegetflushtozero();
printf("after fesetflushtozero(%d), mode is %d\n",
fm_saved, fm);
printf("denormalized value is %g [%08x%08x]\n", dix.y,
dix.i.ym, dix.i.yl);
}
/*************************************************************/

If you run this program on a system that supports flush-to-zero mode, it produces the following output:

$ cc fe_flush.c -lm
$ ./a.out
underflow mode is 0
denormalized value is -4.94066e-324 [8000000000000001]
after fesetflushtozero(1), mode is 1
denormalized value is -0.00000 [8000000000000001]
after fesetflushtozero(0), mode is 0
denormalized value is -4.94066e-324 [8000000000000001]
Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© 1997 Hewlett-Packard Development Company, L.P.