17

I have the following very simple template. As I learned, ^ is not the exponential operator. Now I'm looking for a way to compute this power. There are many examples with a recursive template on the internet. This is not too difficult.

But I wonder: Is there actually no "built-in" method in C++ to compute this on compile time?

template <int DIM>
class BinIdx : Idx
{
        static const int SIZE = 3 ^ DIM; // whoops, this is NOT an exponential operator!
}
Michael
  • 7,407
  • 8
  • 41
  • 84

5 Answers5

15

As mentioned you can use << if the exponent is a power of two.

Otherwise, if the exponents are non-negative integers you can write a constexpr function like this one.

template<typename T, typename U>
auto constexpr pow(T base, U exponent) {
    static_assert(std::is_integral<U>(), "exponent must be integral");
    return exponent == 0 ? 1 : base * pow(base, exponent - 1);
}

This will obviously break for large exponents as well as negative ones, though.

I am not fully aware of how well compilers optimize function calls in constant expressions. Here's a manual optimization for cases where the exponents are powers of two. This will also reduce the amount of recursion done.

template<typename T>
bool constexpr is_power_of_two(T x) {
    return (x != 0) && ((x & (x - 1)) == 0);
}

template<typename T, typename U>
auto constexpr pow(T base, U exponent) {
    static_assert(std::is_integral<U>(), "exponent must be integral");
    if (is_power_of_two(exponent)) {
        return base << exponent;
    }
    return exponent == 0 ? 1 : base * pow(base, exponent - 1);
}

More efficient algorithms are also available. However, I am bad at computer science so I don't know how to implement them.

  • 2
    I think the name of your function should be changed - because of `std::pow` >o – ikh Dec 03 '14 at 11:35
  • 2
    Your last point is important: it is easy to make the compiler explode with compile-time computations if you're not careful. That's a good reason **not** to provide something like this in the standard library – Jonathan Wakely Dec 03 '14 at 11:36
  • ICBW but I think I've seen `` prototypes marked `constexpr` in GCC – sehe Dec 03 '14 at 11:37
  • 3
    @ikh: Why do you say that? The whole point of the `std` namespace is to allow you to give sensible names to your own functions with no danger of conflicting with library names. – Mike Seymour Dec 03 '14 at 11:43
  • 1
    @MikeSeymour However `pow()` is inherited from C. In many case, we can see people including `` instead of ``, which cause things to be broken. – ikh Dec 03 '14 at 11:48
  • @ikh: `` is only a problem with g++, because that compiler's implementation of it is or used to be broken. more generally the .h headers are preferred, not the c... headers, because the c.... headers might place names in the global namespace and thus allow code that will not compile with some other compiler (i.e. effectively less portable code). – Cheers and hth. - Alf Dec 03 '14 at 11:54
  • @ikh: oh, sorry for not reading the context, but now that I have: using c.... headers won't save the situation, even if one controls the whole code base. because they're allowed to place identifiers in the global namespace, in c++11, and because they did it anyway in c++03. so yes i agree with you that the function should better not be named `pow`. much better to choose a non-conflicting name. – Cheers and hth. - Alf Dec 03 '14 at 11:56
  • 4
    If you want to optimize, a better optimization is Exponentiation by Squaring: http://en.wikipedia.org/wiki/Exponentiation_by_squaring – Sebastian Redl Dec 03 '14 at 12:22
  • The last "optimization" is wrong. You can only use bit shift in those cases: `1< – user202729 Jun 12 '20 at 16:10
11

You can use template metaprogramming. Let me show the code.

template <int A, int B>
struct get_power
{
    static const int value = A * get_power<A, B - 1>::value;
};
template <int A>
struct get_power<A, 0>
{
    static const int value = 1;
};

Usage:

std::cout << get_power<3, 3>::value << std::endl;

(live example)

ikh
  • 10,119
  • 1
  • 31
  • 70
11

As an addition to elyse's answer, here is a version with recursion depth of log(n):

template<typename T>
constexpr T sqr(T a) {
    return a * a;
}

template<typename T>
constexpr T power(T a, std::size_t n) {
    return n == 0 ? 1 : sqr(power(a, n / 2)) * (n % 2 == 0 ?  1 : a);
}
Community
  • 1
  • 1
Anton Savin
  • 40,838
  • 8
  • 54
  • 90
5

No, there is no general built in way to calculate the power of values. There is the pow function from the standard library and you can use the << shift operator for the special case 2^x.

This would work in your case (*):

static const int SIZE = (1 << DIM);

* = You updated your question from 2^x to 3^x after I wrote my answer.

For another special case x^y where x and y are static, you can just write a long multiplication:

const result int = x*x*x*x*x;
Flovdis
  • 2,945
  • 26
  • 49
2

A named operator library:

namespace named_operator {
  template<class D>struct make_operator{
    constexpr make_operator(){}
  };
  template<class T, char, class O> struct half_apply { T&& lhs; };

  template<class Lhs, class Op>
  constexpr
  half_apply<Lhs, '*', Op>
  operator*( Lhs&& lhs, make_operator<Op> ) {
    return {std::forward<Lhs>(lhs)};
  }

  template<class Lhs, class Op, class Rhs>
  constexpr auto
  times( Lhs&& lhs, Op, Rhs&& rhs, ... ) // ... keeps this the worst option
  -> decltype( invoke( std::declval<Lhs>(), Op{}, std::declval<Rhs>() ) )
  {
    // pure ADL call, usually based off the type Op:
    return invoke( std::forward<Lhs>(lhs), Op{}, std::forward<Rhs>(rhs)     );
  }

  template<class Lhs, class Op, class Rhs>
  constexpr auto
  operator*( half_apply<Lhs, '*', Op>&& lhs, Rhs&& rhs )
  -> decltype(
    times( std::declval<Lhs>(), Op{}, std::declval<Rhs>() )
  )
  {
    return times( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
  }
}

It only supports operator*, but extending it should be obvious. Picking names for times equivalents is a bit of an issue.

@Anton's solution, augmented with a named operator:

namespace power {
  template<typename T>
  constexpr T sqr(T a) {
    return a * a;
  }

  template<typename T>
  constexpr T power(T a, std::size_t n) {
    return n == 0 ? 1 : sqr(power(a, n / 2)) * (n % 2 == 0 ?  1 : a);
  }

  namespace details {
    struct pow_tag {};
    constexpr named_operator::make_operator<pow_tag> pow;

    template<class Scalar>
    constexpr Scalar times( Scalar lhs, pow_tag, std::size_t rhs ) {
      return power( std::forward<Scalar>(lhs), rhs );
    }
  }
  using details::pow;
}

and now this works:

using power::pow;
int array[ 2 *pow* 10 ] = {0};

live example.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524