Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

how to detect an overflow (or underfolow) floating point calculation?

11 views
Skip to first unread message

May Young

unread,
Jun 13, 2003, 1:42:19 PM6/13/03
to
Hi,

I want to detect an overflow (or underfolow) floating point calculation.
Do you know how?

I figure out a way below but it just partly works (only for
SW_ZERODIVIDE events). In the code below, d2 is apparently overflow.
But ui gets a value of zero instead of _SW_OVERFLOW (0x00000004) when I
debug the code. If I change d1 to 0., then ui is _SW_ZERODIVIDE
(0x00000008) as desired. Do you know why? Thanks for any advise. Tony

_clearfp();
double d1 = 100.;
double d2 = DBL_MAX * d1;
unsigned int ui = _statusfp();
if (ui > 1)
{
// handle the error
.....
}

David Crow [MCSD]

unread,
Jun 13, 2003, 2:38:24 PM6/13/03
to
See the documentation for setjmp() and longjmp().

"May Young" <to...@srac.com> wrote in message
news:3EEA0CFB...@srac.com...

Joseph M. Newcomer

unread,
Jun 13, 2003, 11:32:09 PM6/13/03
to
As long as you don't actually USE setjmp and longjmp! They are awful! Use the setup and
handler ideas, but use throw to throw a real C++ exception. That is, everything in that
example code that actually *uses* setjmp or longjmp should be discarded as inappropriate.
(A longjmp, for example, will bypass all destructors on the stack!)
joe


On Fri, 13 Jun 2003 18:38:24 GMT, "David Crow [MCSD]" <david.crow....@pbsnow.com>
wrote:

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Joseph M. Newcomer

unread,
Jun 14, 2003, 12:41:00 AM6/14/03
to
The prospect that anyone would actually use setjmp/longjmp was so horrifying I wrote a
decent example. This is not fully general, but essentially packages up that unbelievably
bad setjmp/longjmp code into something that actually works in a C++ environment.

I should point out that the code shown in the setjmp/longjmp example is really bad code
even in C, and completely unusable in C++.

In a header file, declare

// FloatingPointException.h
#ifndef _FLOATINGEXCEPTION_H_80186C90_9E1C_11d7_A087_00095B1A7BE1
#define _FLOATINGEXCEPTION_H_80186C90_9E1C_11d7_A087_00095B1A7BE1

#include <signal.h>
#include <float.h>


class CFloatingPointException : public CException {
public:
CFloatingPointException(int err) : CException() { fperr = err; }
public:
int fperr;
public:
static void Enable();
static BOOL SetSignalHandler();
CString Decode();
protected:
CFloatingPointException() {}
static void CDECL fphandler(int sign, int num);

DECLARE_DYNAMIC(CFloatingPointException)
};
#endif // _FLOATINGEXCEPTION_H_80186C90_9E1C_11d7_A087_00095B1A7BE1

The .cpp file:

//FloatingPointException.cpp

#include "stdafx.h"
#include "FloatingPointException.h"


IMPLEMENT_DYNAMIC(CFloatingPointException, CException)

/****************************************************************************
* CFloatingPointException::fphandler
* Inputs:
* int sign: Signal number
* int num: Subcode
* Result: void
*
* Effect:
* Throws an exception CFloatingPointException
****************************************************************************/

/* static */ void CDECL CFloatingPointException::fphandler(int sign, int num)
{
/* Initialize floating-point package. */
_fpreset();
throw new CFloatingPointException(num);
} // CFloatingPointException::fphandler


/****************************************************************************
* CFloatingPointException::Enable
* Result: void
*
* Effect:
* Enables floating point exceptions
****************************************************************************/

/* static */ void CFloatingPointException::Enable()
{
_control87( 0, _MCW_EM );
}

/****************************************************************************
* CFloatingPointException::SetSignalHandler
* Result: BOOL
* TRUE if successful
* FALSE if error
* Effect:
* Sets the signal handler for floating point exceptions
****************************************************************************/

/* static */ BOOL CFloatingPointException::SetSignalHandler()
{
return signal( SIGFPE, (void(CDECL*)(int))fphandler ) != SIG_ERR;
}

/****************************************************************************
* CFloatingPointException::Decode
* Result: CString
* String representation of floating-point error
****************************************************************************/

CString CFloatingPointException::Decode()
{
switch(fperr)
{ /* fperr */
case _FPE_INVALID:
return CString(_T("Invalid number"));
case _FPE_OVERFLOW:
return CString(_T("Overflow"));
case _FPE_UNDERFLOW:
return CString(_T("Underflow"));
case _FPE_ZERODIVIDE:
return CString(_T("Zero divide"));
default:
{
CString s;
s.Format(_T("Unknown floating point error %08x"), fperr);
return s;
}
} /* fperr */
} // CFloatingPointException::Decode

The use:

void CFpoverflowDlg::OnOverflow()
{
CString s;
double n1;
double n2;

/* Unmask all floating-point exceptions. */
CFloatingPointException::Enable();
/* Set up floating-point error handler. The compiler
* will generate a warning because it expects
* signal-handling functions to take only one argument.
*/
c_N1.GetWindowText(s);
n1 = atof(s);
c_N2.GetWindowText(s);
n2 = atof(s);

c_DivideResult.SetWindowText(_T(""));
c_MultiplyResult.SetWindowText(_T(""));
c_ErrorStatus.SetWindowText(_T(""));

if( !CFloatingPointException::SetSignalHandler())
{ /* failed to set up handler */
AfxMessageBox(_T("Unable to create handler"), MB_OK);
return;
} /* failed to set up handler */

TRY {
double r = n1 / n2;

s.Format(_T("%4.3g / %4.3g = %4.3g"), n1, n2, r );
c_DivideResult.SetWindowText(s);

r = n1 * n2;
s.Format(_T("%4.3g * %4.3g = %4.3g"), n1, n2, r );
c_MultiplyResult.SetWindowText(s);
}
CATCH(CFloatingPointException, e)
{ /* failed */
CString err = e->Decode();
c_ErrorStatus.SetWindowText(err);

e->Delete();
} /* failed */
END_CATCH


On Fri, 13 Jun 2003 18:38:24 GMT, "David Crow [MCSD]" <david.crow....@pbsnow.com>
wrote:

>See the documentation for setjmp() and longjmp().

Joseph M. Newcomer [MVP]

Alexander Grigoriev

unread,
Jun 14, 2003, 10:48:13 AM6/14/03
to
Visual C seems to unwind the stack correctly with longjmp in C++ program,
but it's not guaranteed for other environments:

"If you do use setjmp/longjmp in a C++ program, the interaction between
these functions and C++ exception handling requires that you include
SETJMP.H or SETJMPEX.H. Destructors for local objects will be called during
the stack unwind if you compile with the /GX (Enable Exception Handling)
option. Also, if you intend your code to be portable, do not rely on correct
destruction of frame-based objects when executing a nonlocal goto using a
call to longjmp."
But the whole idea of those functions is a horrible blow to the program
reliability.

"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
news:tp5lev4pru962f9rm...@4ax.com...

Doug Harrison [MVP]

unread,
Jun 14, 2003, 12:27:42 PM6/14/03
to
Joseph M. Newcomer wrote:

>The prospect that anyone would actually use setjmp/longjmp was so horrifying I wrote a
>decent example. This is not fully general, but essentially packages up that unbelievably
>bad setjmp/longjmp code into something that actually works in a C++ environment.
>
>I should point out that the code shown in the setjmp/longjmp example is really bad code
>even in C, and completely unusable in C++.

I guess you're talking about this?

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/HTML/_crt_setjmp.asp

For C, it's pretty typical setjmp/longjmp code, and there's nothing
particularly wrong with it that I can see. Maybe you're talking about the
use of global variables? If so, there's very little you can legally do
inside a signal handler, and to do I/O, as in the example, you have to save
any state information you need for after you longjmp back into a safe
context. Given the limitations of signal handlers, globals are about your
only choice.

On the other hand, I'd argue that unmasking FPU exceptions may be misguided.
Many apps can get away with polling the FPU status word after a series of
calculations, and unmasking exceptions doesn't really save you from this.
Some FPU exceptions are raised only when the next FPU instruction is
attempted, so you generally have to insert an __asm { fwait } following your
calculations to trigger any pending FPU exceptions, which is just a poll by
another name. Of course, a very long series of calculations could
potentially benefit from early detection of FPU errors, and that's the sort
of thing for which FPU exceptions make sense.

BTW, your C++ alternative code's signal handler uses heap routines in the
form of new, which is expressly forbidden by the signal docs, and throws a
C++ exception, which is not expressly allowed. In general, signal handlers
are fickle beasts and valid usage requires a good bit of research. I
wouldn't even mess with signals when using VC. I'd use SEH (and possibly
_set_se_translator) instead.

--
Doug Harrison
Microsoft MVP - Visual C++

Doug Harrison [MVP]

unread,
Jun 14, 2003, 12:27:42 PM6/14/03
to
May Young wrote:

Try to write a tiny console program that duplicates the behavior. Compile
with -FAs and examine the mixed assembly/source output. For example:

#include <stdio.h>
#include <float.h>

int main()
{
_clearfp();
double d1 = 100;


double d2 = DBL_MAX * d1;
unsigned int ui = _statusfp();

printf("%08x\n", ui);
return 0;
}

Under VC6, SP5:

********** unoptimized

C>cl a.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

a.cpp
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:a.exe
a.obj

C>a
00000005

********** optimized

C>cl -O1 a.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

a.cpp
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:a.exe
a.obj

C>a
00000000

**********

Compiling the -O1 case with -FAs, I found that the compiler optimized
everything but the function calls out of existence.

Joseph M. Newcomer

unread,
Jun 14, 2003, 1:19:23 PM6/14/03
to
Good points all. It has been far too many years since I touched signal. Besides, I was
watching the Stargate SG-1 season premiere while doing this, so my concentration was not
at its peak. The "indefinite floating-point exception" is actually a very old problem,
dating back to the IBM 360/90 and perhaps even the IBM 7030 ("Stretch").
joe

Joseph M. Newcomer [MVP]

0 new messages