2016-02-10 8 views
3

У меня есть положительное постоянное значение, которое исходит из другой библиотеки, чем моя, назовите ее the_val. Теперь я хочу, чтобы log_of_the_val был напольным (log_2 (the_val)) - не говоря ни слова в коде C++ - и я хочу, чтобы это произошло во время компиляции, конечно.Каков правильный способ вычисления интегральных логарифмов base-2 во время компиляции?

Теперь, с помощью GCC, я мог бы сделать что-то вроде

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

и что должно работать, я думаю (длина - число нулей товарной позиции). В противном случае я мог бы реализовать для себя функцию constexpr, но я уверен, что есть что-то еще, более простое и портативное, которое я мог бы использовать во время компиляции. ... вопрос в том, что бы это было?

+0

@IlyaPopov: Да. – einpoklum

ответ

4

Наиболее простым решением является использование std::log2 от <cmath>, но это не указано как constexpr - оно находится под gcc, но не под clang. (На самом деле, libstdC++ std::log2 называет __builtin_log2, который constexpr под GCC.)

__builtin_clz является constexpr под как GCC и лязгом, так что вы можете использовать.

Полностью портативное решение написать рекурсивную constexpr интегральную log2:

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

Какое обоснование для -1? Я также думаю, что это исправлено. – einpoklum

+2

@einpoklum 'log2 (0)' является ошибкой, но упрощает реализацию для возврата '-1'. Альтернативой было бы прекратить рекурсию на '1' и выбросить' std :: domain_error' за '0':' constexpr unsigned cilog2 (unsigned val) {return val> 1? 1 + cilog2 (val >> 1): val == 1? 0: throw std :: domain_error {"cilog2 (0)"}; } ' – ecatmur