| Home | Libraries | People | FAQ | More

## Trading Accuracy for Performance

There are a number of Policies that can be used to trade accuracy for performance:

- Internal promotion: by default functions with `float` arguments are evaluated at `double` precision internally to ensure full precision in the result. Similarly `double` precision functions are evaluated at `long double` precision internally by default. Changing these defaults can have a significant speed advantage at the expense of accuracy, note also that evaluating using `float` internally may result in numerical instability for some of the more complex algorithms, we suggest you use this option with care.
- Target accuracy: just because you choose to evaluate at `double` precision doesn't mean you necessarily want to target full 16-digit accuracy, if you wish you can change the default (full machine precision) to whatever is "good enough" for your particular use case.

For example, suppose you want to evaluate `double` precision functions at `double` precision internally, you can change the global default by passing `-DBOOST_MATH_PROMOTE_DOUBLE_POLICY=false` on the command line, or at the point of call via something like this:

    double val = boost::math::erf(my_argument, boost::math::policies::make_policy(boost::math::policies::promote_double<false>()));

However, an easier option might be:

    #include <boost/math/special_functions.hpp> // Or any individual special function header

    namespace math{

    namespace precise{
    //
    // Define a Policy for accurate evaluation - this is the same as the default, unless
    // someone has changed the global defaults.
    //
    typedef boost::math::policies::policy<> accurate_policy;
    //
    // Invoke BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS to declare
    // functions that use the above policy.  Note no trailing
    // ";" required on the macro call:
    //
    BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(accurate_policy)

    }

    namespace fast{
    //
    // Define a Policy for fast evaluation:
    //
    using namespace boost::math::polcies;
    typedef policy<promote_double<false> > fast_policy;
    //
    // Invoke BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS:
    //
    BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(fast_policy)

    }

    }

And now one can call:

    math::accurate::tgamma(x);

For the "accurate" version of tgamma, and:

    math::fast::tgamma(x);

For the faster version.

Had we wished to change the target precision (to 9 decimal places) as well as the evaluation type used, we might have done:

    namespace math{
    namespace fast{
    //
    // Define a Policy for fast evaluation:
    //
    using namespace boost::math::polcies;
    typedef policy<promote_double<false>, digits10<9> > fast_policy;
    //
    // Invoke BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS:
    //
    BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(fast_policy)

    }
    }

One can do a similar thing with the distribution classes:

    #include <boost/math/distributions.hpp> // or any individual distribution header

    namespace math{ namespace fast{
    //
    // Define a policy for fastest possible evaluation:
    //
    using namespace boost::math::polcies;
    typedef policy<promote_float<false> > fast_float_policy;
    //
    // Invoke BOOST_MATH_DECLARE_DISTRIBUTIONS
    //
    BOOST_MATH_DECLARE_DISTRIBUTIONS(float, fast_float_policy)

    }} // namespaces

    //
    // And use:
    //
    float p_val = cdf(math::fast::normal(1.0f, 3.0f), 0.25f);

Here's how these options change the relative performance of the distributions on Linux:

[table_Distribution_performance_comparison_for_different_performance_options_with_GNU_C_version_5_1_0_on_linux]