如何在编译时计算以2为底的对数?

4

我有一个正常的常量值,它来自于不同于我的库的地方,叫做the_val。现在,我想让log_of_the_val等于floor(log_2(the_val)) - 不是指C++代码 - 并且我当然希望这在编译时发生。

现在,使用gcc,我可以做一些如下的操作:

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

我想这应该可以工作(长度减去标题零的数量)。否则,我可以自己实现一个constexpr函数,但我敢打赌有其他更简单、更便携的方法可以在编译时使用。问题是,那会是什么?

1个回答

8
最直接的解决方法是使用<cmath>中的std::log2,但这并没有被指定为constexpr - 在gcc下是,但在clang下不是。 (实际上,libstdc++ std::log2 调用了__builtin_log2,在gcc下是constexpr的。) __builtin_clz在gcc和clang下都是constexpr的,所以你可能想要使用它。
完全可移植的解决方案是编写一个递归constexpr整数log2:
constexpr unsigned cilog2(unsigned val) { return val ? 1 + cilog2(val >> 1) : -1; }

为什么要用-1?另外,我觉得修复了偏移量问题。 - einpoklum
3
@einpoklum log2(0)是一个错误,但将其简化为返回-1可以简化实现。另一种选择是在1处终止递归,并对0抛出std::domain_error异常:constexpr unsigned cilog2(unsigned val) { return val > 1 ? 1 + cilog2(val >> 1) : val == 1 ? 0 : throw std::domain_error{"cilog2(0)"}; } - ecatmur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接