Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Trading Accuracy for Performance
PrevUpHomeNext

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]


PrevUpHomeNext