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>
