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>