Search code examples
64-bitvisual-studio-2019floating-point-exceptions

How to use try-catch to catch floating point errors?


#include <iostream>
#include <float.h>
#pragma fenv_access (on)
int main(int, char**argv)
{
    unsigned int fp_control_word;
    _controlfp_s(&fp_control_word, 0, 0);
    const unsigned int new_fp_control_word = fp_control_word | _EM_INVALID | _EM_DENORMAL
        | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT;
    _controlfp_s(&fp_control_word, new_fp_control_word, _MCW_EM);
   try
   {    std::cout << std::atof(argv[1]) / std::atof(argv[2]) << std::endl;
   } catch (...)
   {    std::cout << "caught exception" << std::endl;
   }

}

I remember that it is possible to catch memory access errors on windows using a try-catch block.

There is already a question regarding this subject. But it is 10 years old and the code provided does not result in an exception, but in printing a NAN.

I was always curious about using this feature to abort some piece of numerical code in a nice way. The motivation is to abort some VERY COMPLEX piece of code immediately, if anywhere in this code a floating point exception occurred rather than keeping evaluating the rest of the code with NAN results -- which is rather slow and anyway does not make sense.

Please: I don't care if this is not supported by the C++ standard!

The question is, how to get this code to run into the catch-block -- e.g. by using the command line parameters 0.0 0.0!

For me it always prints out NAN.

What compiler options need to be used?

Or does the code need to be changed?

If one provokes a nullptr dereference in the try-block one will end up in the catch-block. But not for division by zero. One needs to use the compiler option /EHa to enable structured exception handling.


Solution

  • Thanks to https://stackoverflow.com/users/17034/hans-passant for the solution.

    Here comes the working code:

    #include <iostream>
    #include <float.h>
    #pragma fenv_access (on)
    int main(int, char**argv)
    {
        unsigned int fp_control_word;
        _controlfp_s(&fp_control_word, 0, _MCW_EM);
        const unsigned int new_fp_control_word = fp_control_word & ~(_EM_INVALID
            | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT);
        _controlfp_s(&fp_control_word, new_fp_control_word, _MCW_EM);
        try
        {   std::cout << std::atof(argv[1]) / std::atof(argv[2]) << std::endl;
        } catch (...)
        {   std::cout << "caught exception" << std::endl;
        }
    }