 |
» |
|
|
 |
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. 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. 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 |
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 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, feclearexceptThe 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 fesettrapenableThe 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. 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] |
|