我想尽快执行以下操作
x / LSB(x)
其中x
是编译时未知的整数值LSB(x) = x & -x
。
(或者,该操作相当于甚至除以2的最高功率= x。)我正在寻找一个合理的可移植解决方案(没有编译器内在函数/内置像GCC的__builtin_clz
或类似的。)
我关心的是以下简单实现
x / (x & -x)
仍会导致昂贵的划分,因为编译器可能无法意识到除法实际上等于除数除数中的尾随零的数量。
如果我的担忧是合理的,那么实施它的更有效方法是什么?
我希望能够轻松扩展到32位,64位,128位整数类型的解决方案......
答案 0 :(得分:1)
怎么样
x >>= ffs(x)-1;
ffs
函数符合4.3BSD,POSIX.1-2001。
如果x
为0,它就不会工作。
答案 1 :(得分:0)
如果您不想依赖CLZ(计数前导零)硬件指令,则可以按this answer中所述计算前导零。通过查找和乘以幻数非常快速。我将在此处重新发布代码:
unsigned x; // input to clz
unsigned c; // output of clz
static const unsigned MultiplyDeBruijnBitPosition[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
c = MultiplyDeBruijnBitPosition[((unsigned)((x & -x) * 0x077CB531U)) >> 27];
一旦计算了前导零,就不需要使用除法指令了。相反,您可以将值向右移动c
。即(消除不需要的临时值),代码变为:
static const unsigned MultiplyDeBruijnBitPosition[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
x >>= MultiplyDeBruijnBitPosition[((unsigned)((x & -x) * 0x077CB531U)) >> 27]; // x /= LSB(x)