


Compile Time Power of a Runtime Base

The pow function effectively computes the compile-time integral power of a run-time base.


#include <boost/math/special_functions/pow.hpp>

namespace boost { namespace math {

template <int N, typename T>
calculated-result-type pow(T base);

template <int N, typename T, class Policy>
calculated-result-type pow(T base, const Policy& policy);

Rationale and Usage

Computing the power of a number with an exponent that is known at compile time is a common need for programmers. In such cases, the usual method is to avoid the overhead implied by the pow, powf and powl C functions by hardcoding an expression such as:

// Hand-written 8th power of a 'base' variable
double result = base*base*base*base*base*base*base*base;

However, this kind of expression is not really readable (knowing the value of the exponent involves counting the number of occurrences of base), error-prone (it's easy to forget an occurrence), syntactically bulky, and non-optimal in terms of performance.

The pow function of Boost.Math helps writing this kind expression along with solving all the problems listed above:

// 8th power of a 'base' variable using math::pow
double result = pow<8>(base);

The expression is now shorter, easier to read, safer, and even faster. Indeed, pow will compute the expression such that only log2(N) products are made for a power of N. For instance in the example above, the resulting expression will be the same as if we had written this, with only one computation of each identical subexpression:

// Internal effect of pow<8>(base)
double result = ((base*base)*(base*base))*((base*base)*(base*base));

Only 3 different products were actually computed.

Return Type

The return type of these functions is computed using the result type calculation rules. For example:



Error Handling

Two cases of errors can occur when using pow:

The default overflow error policy is throw_on_error. A call like pow<-2>(0) will thus throw a std::overflow_error exception. As shown in the link given above, other error handling policies can be used:

The default indeterminate result error policy is ignore_error, which for this function returns 1 since it's the most commonly chosen result for a power of 0. Here again, other error handling policies can be used:

Here is an example of error handling customization where we want to specify the result that has to be returned in case of error. We will thus use the user_error policy, by passing as second argument an instance of an overflow_error policy templated with user_error:

// First we open the boost::math::policies namespace and define the `user_overflow_error`
// by making it return the value we want in case of error (-1 here)

namespace boost { namespace math { namespace policies {
template <class T>
T user_overflow_error(const char*, const char*, const T&)
{ return -1; }

// Then we invoke pow and indicate that we want to use the user_error policy
using boost::math::policies;
double result = pow<-5>(base, policy<overflow_error<user_error> >());

// We can now test the returned value and treat the special case if needed:
if (result == -1)
    // there was an error, do something...

Another way is to redefine the default overflow_error policy by using the BOOST_MATH_OVERFLOW_ERROR_POLICY macro. Once the user_overflow_error function is defined as above, we can achieve the same result like this:

// Redefine the default error_overflow policy
#include <boost/math/special_functions/pow.hpp>

// From this point, passing a policy in argument is no longer needed, a call like this one
// will return -1 in case of error:

double result = pow<-5>(base);

Bruno Lalande submitted this addition to Boost.Math.

Thanks to Joaquín López Muñoz and Scott McMurray for their help in improving the implementation.


D.E. Knuth, The Art of Computer Programming, Vol. 2: Seminumerical Algorithms, 2nd ed., Addison-Wesley, Reading, MA, 1981