Catching floating point errors

  • Thread starter Chris Stankevitz
  • Start date
C

Chris Stankevitz

Hi,

I have a very large Visual c++ .net 2003 7.1 native c application
(approximately 500,000 lines of code). This application is a simulation
that frequently works with floating point numbers.

From time to time I do something bad -- for example divide by zero or try
to grow a float beyond numeric_limits<float>::max()

I told MSVC .net 2003 7.1 to "Break into the debugger" for ALL exceptions in
the "Exceptions" dialog. In particular, there is a red circle/x in all the
floating point related exceptions under "Win32 Exceptions" indicating the
debugger should break when it encounters such an exception.

Believe it or not, despite all my hard work making little red Xs, the
debugger does not always stop execution when I perform a funny float
operation.

My question: how do I have MSVC 7.1 .net 2003 break on funny floating point
errors?

PS: Each of my threads execute this code when they start up:
_control87(_EM_INVALID | _EM_DENORMAL |_EM_ZERODIVIDE | _EM_OVERFLOW |
_EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);


Thanks,

Chris
 
W

William DePalo [MVP VC++]

C

Chris Stankevitz

It may be that the runtime is masking the exceptions. Take a look at this
and if it does not help, post again.


Will,

That did not help. I used control87 to tell the runtime to catch floating
point exceptions, but it still let one slip through.

Here's a screenshot of MSVC .net 7.1 2003 letting a sqrt of negative number
slip through:
http://www.stankevitz.com/visualstudio/stat.png

And here's a screenshot of me calling control87 just a few steps back on the
call stack:
http://www.stankevitz.com/visualstudio/control87.png

And here's a screenshot of my exception settings:
http://www.stankevitz.com/visualstudio/exceptions.png


FYI, this is the control87 line I used:
_control87(_EM_INVALID | _EM_DENORMAL |_EM_ZERODIVIDE | _EM_OVERFLOW |
_EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);


Thanks for your assistance!

Chris
 
V

Vladimir Nesterovsky

I believe, the code does not throw. The reason is that the floating point
numbers have infinity and undefined values, which precludes undefined
results of operations.
My question: how do I have MSVC 7.1 .net 2003 break on funny floating point
errors?

You better check them manually.
 
W

William DePalo [MVP VC++]

Chris Stankevitz said:
FYI, this is the control87 line I used:
_control87(_EM_INVALID | _EM_DENORMAL |_EM_ZERODIVIDE | _EM_OVERFLOW |
_EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);

I haven't had the "pleasure" of doing floating point calcualtions since the
'80s when mortgage backed securities were the rage so I had to read the help
for _control87() twice. <g>

Nevertheless, I just tried this in VS.Net 2003,

float f;
unsigned int u;

u = _controlfp(0, 0);
u = u & ~(_EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW |
_EM_UNDERFLOW | _EM_INEXACT);

_controlfp(u, _MCW_EM);

f = 1 / f;
f = sqrt(-1.0f);

The last two lines raise exceptions in the debugger.

Regards,
Will
 
C

Chris Stankevitz

William DePalo said:
Nevertheless, I just tried this in VS.Net 2003,

Will,

Thanks for your help.

Do these "control87" commands need to be issued on every thread in the app?
Do I need to constantly apply them to guarantee they "stick"? Can other
processes disable them? Can opening a common dialog (such as File | Open)
reset them?

Thanks,

Chris
 
C

Chris Stankevitz

William DePalo said:
The last two lines raise exceptions in the debugger.


Ahh... I solved the problem. I had the bits inverted in the first argument
to the _control87 function.

This raised a second problem (pun not intended). When an invalid floating
point operation occurs and is caught by correct use of _control87, the call
stack gets hosed. I cannot see where the exception happened in my code!

It appears the floating point error jumps the code into the kernel and blows
the call stack. :(

Anyone know how I can track down these floating point errors?

Thanks again for your help,

Chris
 
C

Chris Stankevitz

It appears the floating point error jumps the code into the kernel and
blows the call stack. :(


This example illustrates the point. Create a console app and set exceptions
as shown here:
http://www.stankevitz.com/visualstudio/exceptions.png

Then compile/run this code:
//--------------------

#include <cfloat>
#include <cmath>

int main()
{
_control87(0, _MCW_EM);

sqrt(-1.0);

return 0;
}

//--------------------

Thanks,

Chris
 
W

William DePalo [MVP VC++]

Chris Stankevitz said:
Do these "control87" commands need to be issued on every thread in the
app?

As I said, I don't do any "scientific" calculation these days. But as the
exception mechanism of the platform _is thread based_, I think that the
answer is yes.
Do I need to constantly apply them to guarantee they "stick"?

Good question. I don't know. I would guess that the runtime sets the
exception policy while processing the DLL_THREAD_ATTACH notification and not
thereafter. That's a guess. If you have the runtime source (disclaimer: I
can't say for certain how much is distributed with the VS.Net IDE) you might
want to take a look.
Can other processes disable them?

I can't think of an easy way.
Can opening a common dialog (such as File | Open) reset them?

Well, the thing to note about exception handlers under Win32 is that they
are stack-frame based (tabling for now the issue of "vectored" exception
handing). So, if you call on a common dialog and if it does something like
this

__try
{
DoTheCommonDialogThing();
}

__except ( blah blah blah ... )
{
// swallow the exception and move on
}

then you (the caller) will never see it.

Regards,
Will
 
C

Chris Stankevitz

Turns out the call stack comes back if you "pass exception on the caller" a
few times.

Okay, my problem is solved, thanks for your help everyone!

Chris
 
W

William DePalo [MVP VC++]

Chris Stankevitz said:
This raised a second problem (pun not intended).
:)

When an invalid floating point operation occurs and is caught by correct
use of _control87, the call stack gets hosed. I cannot see where the
exception happened in my code!

Does your exception handler call _clearfp()? I think that that is required
to clear the exception. I'm wondering whether your problem is that the
exception is signalled mre times than you think because it has not been
cleared.

As I said before in this thread, that's just a guess.

Regards,
Will
 
D

Doug Harrison [MVP]

Chris said:
Turns out the call stack comes back if you "pass exception on the caller" a
few times.

Okay, my problem is solved, thanks for your help everyone!

One more thing to consider is that FPU exceptions are somewhat asynchronous
and may not be raised until a subsequent FPU instruction is executed. You
can raise any pending FPU exceptions with:

__asm { fwait }

I just found an an article on MSDN which mentions this:

Microsoft Visual C++ Floating-Point Optimization
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/floapoint.asp

I haven't had a chance to read this article, but it looks very good.
 
J

Jan Bares

processes disable them? Can opening a common dialog (such as File | Open)
reset them?

Hi,

just add to previous answers, some device drivers (e.g. HP printer drivers)
mask FPU exceptions and do not restore them back. So it can happen in your
program, that after call to some API (3rd party DLL or so), the exceptions
will be masked. On the contrary, some 3rd party DLL may not work due to
unmasked exceptions. (We unmasked FPU exceptions in AutoCAD 2k, and it won't
even start due to divion by zero)

Jan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top