gcl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Gcl-devel] [Maxima] Out of range floating point number determinatio


From: Camm Maguire
Subject: Re: [Gcl-devel] [Maxima] Out of range floating point number determination
Date: Thu, 23 Aug 2012 11:00:44 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux)

Greetings!

Raymond Toy <address@hidden> writes:

> On 8/22/12 10:12 AM, Camm Maguire wrote:
>> It looks like mingw32 uses _controlfp.  Unfortunately, I cannot discover
>> how to clear the exception in the signal handler.  _clearfp(),
>> _controlfp(-1,_MCW_EM), etc, all raise an additional SIGFPE in the
>> handler, which is fatal.  Ideas?
>>
> Clearing the exception usually means clearing the accrued exceptions
> bits (also called the sticky bits) in the status word, I think.  If
> _clearfp() doesn't do it, then I don't know what else to do other than
> resort to some inline assembly code.
>

This is now resolved.  feclearexcept(-1) is what I sought.  _clearfp()
clears the control word.

GCL is highly portable, making it extremely desirable to abstract at the
C level and avoid assembler if possible.  Unfortunately, from what I can
tell at present, c99 provides the most comprehensive standard, but this
omits support for setting the control word or enabling FPE trapping.
One can get and set the fp 'environment' from 'opaque' objects, but this
does not provide any portable means of enabling trapping.  GNU extends
c99 with feenableexcept.  I'm assuming this covers both x87 and xmm
control words (untested).  This should cover the free unix-like OSes (I
think even debian kfreebsd uses glibc, but I have to check this.  I
don't know about the genuine bsd's).  But we need darwin and mingw as
well at a minimum, and perhaps also solaris if this still exists these
days.

Do any of the following cpu's have a 'control word' equivalent?

mips sparc s390 arm ia64 hppa ppc amd64 (sh alpha m68k ...)

I think you were right about the 'oneshot' behavior arising from
sigaction.  In the handler, fetestexcept also returns 0.  All error
status is in the passed si_code.  sigaction must be resetting the fpu.

GCL mingw has its own signal delivery mechanism, so fetestexcept works
fine.  mingw under wine appears to work for me now.

I was hoping Apple had some interface for manipulating the control word
that worked across x87, xmm, and ppc, but I cannot find it yet.  The gsl
source (ieee-utils/fp-darwin*.c) appears to roll its own.

I no longer have access to a solaris machine.

Here is my snippet from usig.c at the moment:

=============================================================================
static unsigned int excepts;

#define __USE_GNU
#include <fenv.h>

#ifdef __MINGW32__

#include <float.h>

#define GCL_FE_INVALID   _EM_INVALID
#define GCL_FE_DIVBYZERO _EM_ZERODIVIDE
#define GCL_FE_OVERFLOW  _EM_OVERFLOW
#define GCL_FE_UNDERFLOW _EM_UNDERFLOW
#define GCL_FE_INEXACT   _EM_INEXACT

#define fedisableexcept(a_) _clearfp();
#define  feenableexcept(a_) _controlfp(~excepts,_MCW_EM);
#define fecode(a_) fetestexcept(-1)
#define siginfo_t int

#else

#define GCL_FE_INVALID   FE_INVALID
#define GCL_FE_DIVBYZERO FE_DIVBYZERO
#define GCL_FE_OVERFLOW  FE_OVERFLOW
#define GCL_FE_UNDERFLOW FE_UNDERFLOW
#define GCL_FE_INEXACT   FE_INEXACT

#define fecode(a_) ({unsigned _t=0;\
      switch ((a_)->si_code) {                  \
      case FPE_FLTDIV: _t=FE_DIVBYZERO;break;   \
      case FPE_FLTOVF: _t=FE_OVERFLOW;break;    \
      case FPE_FLTUND: _t=FE_UNDERFLOW;break;   \
      case FPE_FLTRES: _t=FE_INEXACT;break;     \
      case FPE_FLTINV: _t=FE_INVALID;break;     \
      default: break;                           \
      }_t;})

#endif

DEFUN_NEW("FE-ENABLE",object,fSfe_enable,SI,1,1,NONE,OI,OO,OO,OO,(fixnum 
enable),"") {

  fedisableexcept(excepts);

  excepts=0;
  if (enable&0x1)       excepts|=GCL_FE_INVALID;
  if ((enable>>=1)&0x1) excepts|=GCL_FE_DIVBYZERO;
  if ((enable>>=1)&0x1) excepts|=GCL_FE_OVERFLOW;
  if ((enable>>=1)&0x1) excepts|=GCL_FE_UNDERFLOW;
  if ((enable>>=1)&0x1) excepts|=GCL_FE_INEXACT;

  feenableexcept(excepts);

  RETURN1(make_fixnum(excepts));

}

static void
sigfpe1(int sig,siginfo_t *i,void *v) {

  char *s;

  switch (fecode(i)) {
  
  case FE_DIVBYZERO:    s="Floating point divide by zero";break;
  case FE_OVERFLOW:     s="Floating point overflow";break;
  case FE_UNDERFLOW:    s="Floating point underflow";break;
  case FE_INEXACT:      s="Floating point inexact result";break;
  case FE_INVALID:      s="Floating point invalid operation";break;
  default:              s="Unknown floating-point exception";break;

  }

  feclearexcept(-1);
  fedisableexcept(excepts);
  feenableexcept(excepts);

  unblock_signals(SIGFPE,SIGFPE);
#ifdef __MINGW32__
  gcl_signal(SIGFPE,sigfpe1);
#endif

  FEerror(s,0);

}
=============================================================================


Take care,
-- 
Camm Maguire                                        address@hidden
==========================================================================
"The earth is but one country, and mankind its citizens."  --  Baha'u'llah



reply via email to

[Prev in Thread] Current Thread [Next in Thread]