Search code examples
c++11constantsconstexprlogarithmidioms

What's the right way to compute integral base-2 logarithms at compile-time?


I have some positive constant value that comes from a different library than mine, call it the_val. Now, I want log_of_the_val to be floor(log_2(the_val)) - not speaking in C++ code - and I want that to happen at compile time, of course.

Now, with gcc, I could do something like

decltype(the_val) log_of_the_val = sizeof(the_val) * CHAR_BIT - __builtin_clz(the_val) - 1;

and that should work, I think (length - number of heading zeros). Otherwise, I could implement a constexpr function myself for it, but I'm betting that there's something else, and simpler, and portable, that I could use at compile-time. ... question is, what would that be?


Solution

  • The most straightforward solution is to use std::log2 from <cmath>, but that isn't specified to be constexpr - it is under gcc, but not under clang. (Actually, libstdc++ std::log2 calls __builtin_log2, which is constexpr under gcc.)

    __builtin_clz is constexpr under both gcc and clang, so you may want to use that.

    The fully portable solution is to write a recursive constexpr integral log2:

    constexpr unsigned cilog2(unsigned val) { return val ? 1 + cilog2(val >> 1) : -1; }