编译时间递归函数以计算两个整数的下一个功能
Compile-time recursive function to compute the next power of two of an integer?
在BIT TWIDDLING HACKS网站上,提供了以下算法来将整数汇总到下一个功能:
的下一个功能unsigned int v; // compute the next highest power of 2 of 32-bit v
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
我想编码一个将计算相同操作的元编程功能:
- 递归(用于编译时执行)
- 对于任何类型的整数(甚至应该适用于任何大小(如15位,65位)的可能尴尬的非标准整数...)
这是预期函数的形式:
template <typename Type,
// Something here (like a recursion index)
class = typename std::enable_if<std::is_integral<Type>::value>::type,
class = typename std::enable_if<std::is_unsigned<Type>::value>::type>
constexpr Type function(const Type value)
{
// Something here
}
如何做?
示例:对于value = 42
,它应该返回64
这应该实现您给出的算法:
template<typename T>
constexpr T roundup_helper( T value, unsigned maxb, unsigned curb ) {
return maxb<=curb
? value
: roundup_helper( ((value-1) | ((value-1)>>curb))+1, maxb, curb << 1 )
;
}
template<typename T,
typename = typename enable_if<is_integral<T>::value>::type,
typename = typename enable_if<is_unsigned<T>::value>::type>
constexpr T roundup( T value ) {
return roundup_helper( value, sizeof(T)*CHAR_BIT, 1 );
}
至少,它在我的测试程序中似乎很好。
另外,您可以将v-1
和v+1
移出助手功能,例如:
template<typename T>
constexpr T roundup_helper( T value, unsigned maxb, unsigned curb ) {
return maxb<=curb
? value
: roundup_helper( value | (value>>curb), maxb, curb << 1 )
;
}
template<typename T,
typename = typename enable_if<is_integral<T>::value>::type,
typename = typename enable_if<is_unsigned<T>::value>::type>
constexpr T roundup( T value ) {
return roundup_helper( value-1, sizeof(T)*CHAR_BIT, 1 )+1;
}
另一种可能性是利用默认参数并将其全部放在一个函数中:
template<typename T,
typename = typename enable_if<is_integral<T>::value>::type,
typename = typename enable_if<is_unsigned<T>::value>::type>
constexpr T roundup(
T value,
unsigned maxb = sizeof(T)*CHAR_BIT,
unsigned curb = 1
) {
return maxb<=curb
? value
: roundup( ((value-1) | ((value-1)>>curb))+1, maxb, curb << 1 )
;
}
这可能不是您不幸的事情。但是,如果您有任何偶然的constexpr
计数领导零编译器的固有,则以下既有编译时都非常有效,并且在运行时,如果您碰巧给它进行运行时间参数:
#include <climits>
template <class Int>
inline
constexpr
Int
clp2(Int v)
{
return v > 1 ? 1 << (sizeof(Int)*CHAR_BIT - __builtin_clz(v-1)) : v;
}
int
main()
{
static_assert(clp2(0) == 0, "");
static_assert(clp2(1) == 1, "");
static_assert(clp2(2) == 2, "");
static_assert(clp2(3) == 4, "");
static_assert(clp2(4) == 4, "");
static_assert(clp2(5) == 8, "");
static_assert(clp2(6) == 8, "");
static_assert(clp2(7) == 8, "");
static_assert(clp2(8) == 8, "");
static_assert(clp2(42) == 64, "");
}
我用灌输曲折的叮当声编译了上面的内容。它并非没有问题。您需要决定要对负面论据做什么。但是许多架构和编译器都具有这样的内在性(可耻的是现在不是标准的C/C )。其中一些可能会成为固有的constexpr。
没有这样内在的,我会依靠亚当·彼得森(Adam H. Peterson)的算法。但是,这是它的简单性和效率。
尽管一般效率较低,但该算法将很简单地完成工作:
template <typename T,
typename = typename std::enable_if<std::is_integral<T>::value>::type,
typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
constexpr T upperPowerOfTwo(T value, size_t pow = 0)
{
return (value >> pow) ? upperPowerOfTwo(value, pow + 1)
: T(1) << pow;
}
这还允许您指定2 -imimum功率2 -i. upperPowerOfTwo(1, 3)
返回8.
在大多数情况下,这效率较低的原因是它使O(sizeof(type)*char_bit)调用,而您链接的算法执行O(log(sizeof(type)*char_bit))操作。警告是该算法将在log(v)调用后终止,因此,如果V足够小(即&lt; log(v-type的最大值)),则它将更快。
相关文章:
- C++需要帮助从用户那里获得一个整数,并确保它在另外两个整数之间
- 比较C++中两个整数的最有效和最干净的方法是什么?
- 比较两个整数在C++中与未知 int 类型的相等性
- 如何组合两个整数向量
- 在两个整数之间交换最右边的N位
- 打印出两个整数之间的偶数
- Python 等效代码,可像C++一样直接附加两个整数
- 移位运算符如何在查找两个整数中的不同位数?
- 运算符"|"如何计算两个整数?
- 如何找出在两个整数的乘积中设置了多少位(等于 1)
- 当键是两个整数时,C 地图或unordered_map
- C 将两个整数进入队列
- 比较 C++ 字符串打印中的两个整数数组
- 为什么双精度不存储两个整数的乘积
- C++将字符串输入拆分为两个整数
- C 中的内存模型:为什么在同一内存位置分配了结构中的两个整数
- 获取所有方式以两个整数的产品表示数字
- Systemc传输级建模从TLM_Generic_Payload提取两个整数
- 数据的所有组合都是产品的两个整数
- 编写一个功能,该函数将使用框架交换两个整数