Skip site navigation (1)Skip section navigation (2)
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>