Error Handling Policies

| Home | Libraries | People | FAQ | More

#### Error Handling Policies

There are two orthogonal aspects to error handling:

- What to do (if anything) with the error.
- What kind of error is being raised.

##### Available Actions When an Error is Raised

What to do with the error is encapsulated by an enumerated type:

    namespace boost { namespace math { namespace policies {

    enum error_policy_type
    {
       throw_on_error = 0, // throw an exception.
       errno_on_error = 1, // set ::errno & return 0, NaN, infinity or best guess.
       ignore_error = 2, // return 0, NaN, infinity or best guess.
       user_error = 3  // call a user-defined error handler.
    };

    }}} // namespaces

The various enumerated values have the following meanings:

###### throw_on_error

Will throw one of the following exceptions, depending upon the type of the error:

Error Type | Exception
--- | ---
Domain Error | std::domain_error
Pole Error | std::domain_error
Overflow Error | std::overflow_error
Underflow Error | std::underflow_error
Denorm Error | std::underflow_error
Evaluation Error | boost::math::evaluation_error
Indeterminate Result Error | std::domain_error

###### errno_on_error

Will set global `::errno` `::errno` to one of the following values depending upon the error type (often EDOM = 33 and ERANGE = 34), and then return the same value as if the error had been ignored:

Error Type | errno value
--- | ---
Domain Error | EDOM
Pole Error | EDOM
Overflow Error | ERANGE
Underflow Error | ERANGE
Denorm Error | ERANGE
Evaluation Error | EDOM
Indeterminate Result Error | EDOM

###### ignore_error

Will return one of the values below depending on the error type (`::errno` is NOT changed)::

Error Type | Returned Value
--- | ---
Domain Error | std::numeric_limits<T>::quiet_NaN()
Pole Error | std::numeric_limits<T>::quiet_NaN()
Overflow Error | std::numeric_limits<T>::infinity()
Underflow Error | 0
Denorm Error | The denormalised value.
Evaluation Error | The best guess as to the result: which may be significantly in error.
Indeterminate Result Error | Depends on the function where the error occurred

###### user_error

Will call a user defined error handler: these are forward declared in boost/math/policies/error_handling.hpp, but the actual definitions must be provided by the user:

    namespace boost{ namespace math{ namespace policies{

    template <class T>
    T user_domain_error(const char* function, const char* message, const T& val);

    template <class T>
    T user_pole_error(const char* function, const char* message, const T& val);

    template <class T>
    T user_overflow_error(const char* function, const char* message, const T& val);

    template <class T>
    T user_underflow_error(const char* function, const char* message, const T& val);

    template <class T>
    T user_denorm_error(const char* function, const char* message, const T& val);

    template <class T>
    T user_rounding_error(const char* function, const char* message, const T& val);

    template <class T>
    T user_evaluation_error(const char* function, const char* message, const T& val);

    template <class T>
    T user_indeterminate_result_error(const char* function, const char* message, const T& val);

    }}} // namespaces

Note that the strings function and message may contain "%1%" format specifiers designed to be used in conjunction with Boost.Format. If these strings are to be presented to the program's end-user then the "%1%" format specifier should be replaced with the name of type T in the function string, and if there is a %1% specifier in the message string then it should be replaced with the value of val.

There is more information on user-defined error handlers in the tutorial here.

##### Kinds of Error Raised

There are six kinds of error reported by this library, which are summarised in the following table:

Error Type | Policy Class | Description
--- | --- | ---
Domain Error | boost::math::policies::domain_error<action> | Raised when more or more arguments are outside the defined range of the function. Defaults to `boost::math::policies::domain_error<throw_on_error>` When the action is set to throw_on_error then throws `std::domain_error`
Pole Error | boost::math::policies::pole_error<action> | Raised when more or more arguments would cause the function to be evaluated at a pole. Defaults to `boost::math::policies::pole_error<throw_on_error>` When the action is throw_on_error then throw a `std::domain_error`
Overflow Error | boost::math::policies::overflow_error<action> | Raised when the result of the function is outside the representable range of the floating point type used. Defaults to `boost::math::policies::overflow_error<throw_on_error>`. When the action is throw_on_error then throws a `std::overflow_error`.
Underflow Error | boost::math::policies::underflow_error<action> | Raised when the result of the function is too small to be represented in the floating point type used. Defaults to `boost::math::policies::underflow_error<ignore_error>` When the specified action is throw_on_error then throws a `std::underflow_error`
Denorm Error | boost::math::policies::denorm_error<action> | Raised when the result of the function is a denormalised value. Defaults to `boost::math::policies::denorm_error<ignore_error>` When the action is throw_on_error then throws a `std::underflow_error`
Rounding Error | boost::math::policies::rounding_error<action> | Raised When one of the rounding functions round, trunc or modf is called with an argument that has no integer representation, or is too large to be represented in the result type Defaults to `boost::math::policies::rounding_error<throw_on_error>` When the action is throw_on_error then throws `boost::math::rounding_error`

Evaluation Error

boost::math::policies::evaluation_error<action>

Raised when the result of the function is well defined and finite, but we were unable to compute it. Typically this occurs when an iterative method fails to converge. Of course ideally this error should never be raised: feel free to report it as a bug if it is!

Defaults to `boost::math::policies::evaluation_error<throw_on_error>`

When the action is throw_on_error then throws `boost::math::evaluation_error`

Indeterminate Result Error | boost::math::policies::indeterminate_result_error<action> | Raised when the result of a function is not defined for the values that were passed to it. Defaults to `boost::math::policies::indeterminate_result_error<ignore_error>` When the action is throw_on_error then throws `std::domain_error`

##### Examples

Suppose we want a call to `tgamma` to behave in a C-compatible way and set global `::errno` rather than throw an exception, we can achieve this at the call site using:

    #include <boost/math/special_functions/gamma.hpp>
    using boost::math::tgamma;

    //using namespace boost::math::policies; may also be convenient.
    using boost::math::policies::policy;
    using boost::math::policies::evaluation_error;
    using boost::math::policies::domain_error;
    using boost::math::policies::overflow_error;
    using boost::math::policies::domain_error;
    using boost::math::policies::pole_error;
    using boost::math::policies::errno_on_error;

    // Define a policy:
    typedef policy<
      domain_error<errno_on_error>,
      pole_error<errno_on_error>,
      overflow_error<errno_on_error>,
      evaluation_error<errno_on_error>
    > my_policy;

    double my_value = 0.; //

    // Call the function applying my_policy:
    double t1 = tgamma(my_value, my_policy());

    // Alternatively (and equivalently) we could use helpful function
    // make_policy and define everything at the call site:
    double t2 = tgamma(my_value,
      make_policy(
        domain_error<errno_on_error>(),
        pole_error<errno_on_error>(),
        overflow_error<errno_on_error>(),
        evaluation_error<errno_on_error>() )
      );

Suppose we want a statistical distribution to return infinities, rather than throw exceptions, then we can use:

    #include <boost/math/distributions/normal.hpp>
    using boost::math::normal_distribution;

    using namespace boost::math::policies;

    // Define a specific policy:
    typedef policy<
          overflow_error<ignore_error>
          > my_policy;

    // Define the distribution, using my_policy:
    typedef normal_distribution<double, my_policy> my_norm;

    // Construct a my_norm distribution, using default mean and standard deviation,
    // and get a 0.05 or 5% quantile:
    double q = quantile(my_norm(), 0.05); // = -1.64485