Date: Wed, 18 Feb 1998 18:17:39 +0100 From: Kent Boortz <kent@erlang.ericsson.se> To: bartol@salk.edu Cc: kent@erlang.ericsson.se Subject: Re: IEEE Floating Point question: Inf and NaN (fwd) Message-ID: <19980218181739G.kent@erlang.ericsson.se> In-Reply-To: Your message of "Tue, 3 Feb 1998 09:07:00 -0800 (PST)" <Pine.BSF.3.96.980203090615.25791C-100000@dale.salk.edu> References: <Pine.BSF.3.96.980203090615.25791C-100000@dale.salk.edu>
next in thread | previous in thread | raw e-mail | index | archive | help
> The fpsetmask call is actually a very important thing to know about and
> one area where the FreeBSD team should be quite proud. As a programmer,
> it's great to have this kind of control over how these exceptions are
> handled. After learning about this call I'm convinced that the system
> default of trapping the exception and stopping execution is the correct
> system-wide policy (it is conducive to the writing of good code in
> general).
I would prefer the higher level "ieee_handler()" calls used in
SunOS4. Using the fpsetmask() calls seem to be *very* hardware
dependent. I include a program below that test the floating point
trapping on FreeBSD 2.2.2, GCC 2.7.2.1, tested on a 486 machine and
Pentium. If I do
% gcc -DSTICKY -DALL float.c -lm ; ./a.out
it kind of freaks out after a while. If I omit "-DALL" to exclude the
FP_X_IMP, "loss of precision", this also seem to disable the overflow
and underflow exceptions. This immediately break the next *normal*
floating point operation, i.e. gives an exception when it shouldn't.
The fpsetmask man page talks about resetting the "sticky bits". I
thought I was supposed to write "fpsetsticky(0)" to reset but it seems
to be that I should set bits to reset them. What value should I use
and *when* do I call this function? Before every floating point
aritmetic call? After every call? After an unsuccessful call? Can I
call "fpsetsticky()" from inside the signal handler?
Is the fpsetmask/SIGFPE handling in FreeBSD 2.2.2 broken or am I
doing something wrong? I had even more problem when I tried this on
Solaris for Intel, I managed to create panic.
If you have any information about how this is supposed to work,
please let me know,
/kgb
============================================================================
Mask:
before set: FP_X_INV FP_X_OFL FP_X_DZ
we want : FP_X_INV FP_X_OFL FP_X_UFL FP_X_DZ FP_X_DNML FP_X_IMP
new : FP_X_INV FP_X_OFL FP_X_UFL FP_X_DZ FP_X_DNML FP_X_IMP
****************************************
**** Exception: overflow
**** Sticky : FP_X_OFL
**** Exception: underflow
**** Sticky : FP_X_UFL
**** Exception: divide by zero
**** Exception: invalid
**** Exception: NaN
****************************************
**** Exception: overflow
**** Sticky : FP_X_OFL
**** Exception: underflow
**** Sticky : FP_X_UFL
**** Exception: divide by zero
**** Exception: invalid
**** Exception: NaN
****************************************
**** Exception: overflow
**** Sticky : FP_X_OFL
**** Exception: underflow
**** Sticky : FP_X_UFL
\\\\ Exception in normal operation
**** Exception: divide by zero
\\\\ Exception in normal operation
**** Exception: invalid
\\\\ Exception in normal operation
**** Exception: NaN
\\\\ Exception in normal operation
****************************************
**** Exception: overflow
**** Sticky : FP_X_OFL
\\\\ Exception in normal operation
**** Exception: underflow
**** Sticky : FP_X_UFL
\\\\ Exception in normal operation
**** Exception: divide by zero
\\\\ Exception in normal operation
**** Exception: invalid
**** Sticky : FP_X_OFL
\\\\ Exception in normal operation
**** Exception: NaN
\\\\ Exception in normal operation
****************************************
============================================================================
#include <stdio.h>
#include <signal.h>
#ifdef __FreeBSD__
#include <machine/ieeefp.h>
#include <floatingpoint.h>
#define sigset(__A,__B) signal(__A,__B)
#else
#include <ieeefp.h>
#endif
#include <float.h>
#include <math.h>
int got_exception = 0;
double dummy = 1.234;
int mask;
static void report_reset_exception(char*);
static void print_mask(char*,int);
static void check_normal(void);
static void set_exception(int);
static void *sys_sigset(int sig, void (*func)());
static void do_test(void);
/***************************************************************************/
int main()
{
mask = FP_X_INV | FP_X_OFL | FP_X_UFL | FP_X_DZ;
#ifdef FP_X_DNML
mask |= FP_X_DNML;
#endif
#ifdef ALL
mask |= FP_X_IMP;
#endif
printf("Mask:\n");
print_mask("before set: ",fpgetmask());
print_mask("we want : ",mask);
fpsetmask(mask);
print_mask("new : ",fpgetmask());
sys_sigset(SIGFPE,set_exception);
printf("****************************************\n");
do_test();
do_test();
do_test();
do_test();
return 1;
}
/***************************************************************************/
static void do_test()
{
double i, k;
k = 3.57e257;
i = DBL_MAX * k;
report_reset_exception("overflow");
k = 3.57e257;
i = DBL_MIN / k;
report_reset_exception("underflow");
k = 0.0;
i = 3.58 / k;
report_reset_exception("divide by zero");
k = 0x7ff0000;
i = 3.58 * k;
report_reset_exception("invalid");
i = remainder(1.0,0);
report_reset_exception("NaN");
printf("****************************************\n");
}
/***************************************************************************/
static void report_reset_exception(char *msg)
{
if (got_exception == 1)
{
int sticky = fpgetsticky();
got_exception = 0;
printf( "**** Exception: %s\n",msg);
if (sticky)
{
print_mask("**** Sticky : ",sticky);
#ifdef STICKY
fpsetsticky(mask); /* ?????? What value ??????*/
#endif
}
}
else
printf("==== No exception: %s\n",msg);
check_normal();
}
/***************************************************************************/
static void check_normal()
{
dummy += 1.234; /* Do something with the fpu */
if (got_exception == 1)
{
got_exception = 0;
printf( "\\\\\\\\ Exception in normal operation\n");
}
}
/***************************************************************************/
#ifdef FP_X_DNML
#define PSIZE 6
#else
#define PSIZE 5
#endif
static void print_mask(char *msg,int mask)
{
int i;
struct {
char *name;
int value;
} ir[] = {
{"FP_X_INV",FP_X_INV},
{"FP_X_OFL",FP_X_OFL},
{"FP_X_UFL",FP_X_UFL},
{"FP_X_DZ ",FP_X_DZ},
#ifdef FP_X_DNML
{"FP_X_DNML",FP_X_DNML},
#endif
{"FP_X_IMP",FP_X_IMP}
};
printf("%s",msg);
for (i = 0; i < PSIZE; i++)
if (mask & ir[i].value)
printf("%s ", ir[i].name);
printf("\n");
}
static void set_exception(int i)
{
got_exception = 1;
if (i != SIGFPE)
{
printf("Got another signal: %d\n",i);
exit(1);
}
}
/***************************************************************************/
#ifdef SIGACTION
static void *sys_sigset(int sig, void (*func)())
{
struct sigaction act, oact;
printf("TRUE POSIX\n");
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = func;
sigaction(sig, &act, &oact);
return oact.sa_handler;
}
#else
static void *sys_sigset(int sig, void (*func)())
{
return sigset(sig,func);
}
#endif
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19980218181739G.kent>
