C/ c++中最低有效位集的有效除法

Efficient Division by Least Significant Bit set in C/C++

本文关键字:有效 除法 有效位 c++      更新时间:2023-10-16

我想尽快执行以下操作

x / LSB(x)  

,其中x是编译时未知的整数值,LSB(x) = x & -x。(或者,该操作相当于偶数除以2的最高幂<= x。)我正在寻找一个合理的可移植的解决方案(没有编译器的内在/内置像GCC的__builtin_clz或类似的)。

我担心的是下面的简单实现

x / (x & -x)

仍然会导致开销很大的除法,因为编译器可能没有意识到除法实际上相当于向右移动除数后面的0的个数。

如果我的担心是合理的,那么实现它的更有效的方法是什么?

我将欣赏一个解决方案,很容易扩展到整数类型的大小32位,64位,128位,…

x >>= ffs(x)-1;

ffs函数符合4.3BSD, POSIX.1-2001。

如果x为0,它将不起作用。

如果您不想依赖于CLZ (count前导零)硬件指令,您可以按照本答案中描述的方式计算前导零。查找和乘以一个神奇的数字是非常快的。我将在这里重新发布代码:

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)