如何查找二进制数中尾随零的数量?
我采用了 K&R 位计数示例来查找二进制数中的个数,并且我修改它以查找尾随零的尾随数量:
int bitcount(unsigned x)
{
int b;
for(b=0;x!=0;x>>=1)
{
if(x&01)
break;
else
b++;
}
}
我希望审查此方法。
How to find number of trailing zeros in a binary number?
I took the K&R bitcount example for finding the number of ones in a binary number and I modified it to find the trailing number of trailing zeros:
int bitcount(unsigned x)
{
int b;
for(b=0;x!=0;x>>=1)
{
if(x&01)
break;
else
b++;
}
}
I would like to have this method reviewed.
发布评论
评论(8)
来自 https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel ,这是一种并行计算计数以提高效率的方法:
From https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel, here's a way to compute the count in parallel for better efficiency:
在 X86 平台上的 GCC 上,您可以使用 __builtin_ctz(no)
在 Microsoft X86 编译器上,您可以使用
_BitScanForward
它们都会发出 bsf 指令
On GCC on X86 platform you can use
__builtin_ctz(no)
On Microsoft compilers for X86 you can use
_BitScanForward
They both emit a bsf instruction
另一种方法(令我惊讶的是这里没有提到)是构建一个包含 256 个整数的表,其中数组中的每个元素都是该索引的最低 1 位。然后,对于整数中的每个字节,您在表中查找。
像这样的东西(我没有花任何时间来调整它,这只是为了粗略地说明这个想法):
对于像这样的问题,一些表驱动方法的想法是
if
语句在分支预测方面会花费一些成本,因此您应该致力于减少它们。它还减少了位移的数量。您的方法执行 if 语句和每位移位,而此方法对每个字节执行一次移位。 (希望优化器可以展开 for 循环,而不是为此发出比较/跳转。)其他一些答案的if
语句比这更少,但表方法很简单且易于执行理解。当然,您应该以实际测量为指导,看看这些是否重要。Another approach (I'm surprised it's not mentioned here) would be to build a table of 256 integers, where each element in the array is the lowest 1 bit for that index. Then, for each byte in the integer, you look up in the table.
Something like this (I haven't taken any time to tweak this, this is just to roughly illustrate the idea):
The idea with some of the table-driven approaches to a problem like this is that
if
statements cost you something in terms of branch prediction, so you should aim to reduce them. It also reduces the number of bit shifts. Your approach does anif
statement and a shift per bit, and this one does one per byte. (Hopefully the optimizer can unroll the for loop, and not issue a compare/jump for that.) Some of the other answers have even fewerif
statements than this, but a table approach is simple and easy to understand. Of course you should be guided by actual measurements to see if any of this matters.解释:
x & -x 返回设置为 1 的最右边位的数量
。例如 6 -> “0000,0110”,(6&-6)→ "0000,0010"
您可以将其减去两个补数:
x = "a1b",其中 b 代表所有尾随零。
那么
;
x & (-x) = (a1b) & (!a)1b = (0...0)1(0...0)
您只需执行 log2 即可获取尾随零的数量。
Explanation:
x & -x returns the number of right most bit set with 1.
e.g. 6 -> "0000,0110", (6 & -6) -> "0000,0010"
You can deduct this by two complement:
x = "a1b", where b represents all trailing zeros.
then
so
x & (-x) = (a1b) & (!a)1b = (0...0)1(0...0)
you can get the number of trailing zeros just by doing log2.
我认为你的方法是有效的(尽管你可能想使用
unsigned int
)。每次都检查最后一位数字,如果它为零,则将其丢弃,并增加尾随零位的数量。我认为对于尾随零,您不需要循环。
考虑以下问题:
如果正确应用上述步骤,您只需在 O(lg n) 步骤中找到设置的最高位(查看 )。
I think your method is working (allthough you might want to use
unsigned int
). You check the last digit each time, and if it's zero, you discard it an increment the number of trailing zero-bits.I think for trailing zeroes you don't need a loop.
Consider the following:
If you apply the above steps correctly, you can just find the highest bit set in O(lg n) steps (look here if you're interested in how to do).
应该是:
或者甚至
或者甚至(耶!)
或者...
啊,无论如何,那里有 1005 亿种方法可以做到这一点。使用您需要或喜欢的任何东西。
Should be:
or even
or even (yay!)
or ...
Ah, whatever, there are 100500 millions methods of doing this. Use whatever you need or like.
我们可以使用位运算轻松获得它,我们不需要遍历所有位。伪代码:
We can easily get it using bit operations, we don't need to go through all the bits. Pseudo code:
使用现已发布的 C23,代码可以考虑:
With C23, now released, code can consider: