c++linuxfloating-pointx86-64floating-point-exceptions

floating point exceptions in LINUX -- how to convert them into something useful


I've got some piece of code calculating a vector of functions of a vector of independent variables (and parameters):

struct instance
{    double m_adParam1, m_adParam2;
     std::array<double, OUTSIZE> calculate(const std::array<double, INSIZE>&x) const;
};

When any part of this code fails due to a division by (nearly) zero or due to a domain error, the entire code should fail and tell the caller, that it cannot calculate this function for the given input.

This should also apply for calculated values used for comparison only. So testing the result vector for NAN or infinity is not sufficient. Inserting tests after every fallible operation is infeasible.

How could one do this?

I read about fetestexcept(). But it is unclear what is resetting this state flag. SIGFPE is useless for anything other than debugging. Having the ability to convert this into C++ exceptions as on Windows would be great, but inserting a final check would be sufficient as well.

Inserting code to check for invalid inputs for the following code is also infeasible, as it would slow down the calculation dramatically.


Solution

  • I read about fetestexcept(). But it is unclear what is resetting this state flag.

    That is what feclearexcept() does. So you can do something like

    std::feclearexcept(FE_INVALID | FE_OVERFLOW | FE_DIVBYZERO);
    
    // do lots of calculations
    
    // now check for exceptions
    if (std::fetestexcept(FE_INVALID))
        throw std::domain_error("argh");
    else if (std::fetestexcept(FE_OVERFLOW))
        throw std::overflow_error("eek");
    // ...
    

    The exception flags are "sticky" and no other operation, besides an explicit feclearexcept(), should clear them.

    The main benefits of using feenablexcept() to force a SIGFPE are that you would detect the error immediately, without waiting until you happen to get around to testing the exception flag, and that you could pinpoint the exact instruction that caused the exception. It doesn't sound like either of those are needed in your use case.