位移位直到位串中的第一个'1'

时间:2014-09-10 04:39:02

标签: bit-manipulation

有没有办法移动我的位串,直到我将第一个1作为我的最低位? e.g。

0001000100 right shifts twice to 0000010001
0100001010 right shifts once to 0010000101
0010000000 right shifts seven times to 0000000001

我试图通过按位操作来做到这一点。

2 个答案:

答案 0 :(得分:5)

如果n是某种类型的无符号整数:

while ( (n & 0x1) == 0) n >>= 1;

答案 1 :(得分:2)

或者,您可以计算尾随位数,然后按此移位。没有分支,并且在位宽中以对数方式进行缩放。例如32位:

t = ~x & (x - 1)  # mask where all the trailing zeroes are now 1s
c = t - ((t >> 1) & 0x55555555)  # count 1s in the mask
c = (c & 0x33333333) + ((c >> 2) & 0x33333333)
c = (c & 0x0F0F0F0F) + ((c >> 4) & 0x0F0F0F0F)
c = (c & 0x00FF00FF) + ((c >> 8) & 0x00FF00FF)
c = (c & 0x0000FFFF) + ((c >> 16) & 0x0000FFFF)
result = x >> c   # shift right by the number of trailing zeroes

对于64位,您还需要一个还原步骤。

在硬件中,你可以更有效地做一个popcnt,深度为O(log n)(实现这个天真地给出O(log 2 n)因为你有每个log n加法器深度O(log n))。第一步也是最后一步显然也具有对数深度。

对于软件,请检查您的CPU是否为bsftzcntpopcnt或某些等效内容,以执行以下操作:

x >> __builtin_ctz(x)
or
x >> __popcnt(~x & (x - 1))

ctz(0)之类的结果通常是未定义的,但是任何数量的零转换都不会改变它,所以没关系。如果没有这样的指令,请参阅第一个代码块,了解如何解决该问题。

x的最高幂2进行字面划分(实际划分)似乎很有吸引力:

x / (x & -x)

但那太可怕了,不要这样做。即使除了x = 0现在可以解决您的介绍问题之外,分工是一件非常糟糕的事情,您几乎不惜任何代价避免这种情况。