如何高效地计算整数二进制表示中末尾零的数量?
这是一个不错的、快速简便的实现:
public static int NumberOfTrailingZeros(int i)
{
return _lookup[(i & -i) % 37];
}
private static readonly int[] _lookup =
{
32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17,
0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18
};
从第一个数字开始制作掩码,然后不断移动直到找到匹配项:
public static int numTrailingBinaryZeros(int n)
{
int mask = 1;
for (int i = 0; i < 32; i++, mask <<= 1)
if ((n & mask) != 0)
return i;
return 32;
}
从 .Net Core 3.0 开始,有BitOperations.TrailingZeroCount函数。虽然我不知道之前的版本是否也有该函数,但是如果我查看当前的 .NET 7 源代码,它已经内联到了Bmi1.TrailingZeroCount中,并在支持的 x86 环境中转换为tzcnt
x86 汇编指令,因此具有硬件加速实现,对于ARM也有软件实现的备选方案。
public static int numberOfTrailingZeros(int i) {
// HD, Figure 5-14
int y;
if (i == 0) return 32;
int n = 31;
y = i <<16; if (y != 0) { n = n -16; i = y; }
y = i << 8; if (y != 0) { n = n - 8; i = y; }
y = i << 4; if (y != 0) { n = n - 4; i = y; }
y = i << 2; if (y != 0) { n = n - 2; i = y; }
return n - ((i << 1) >>> 31);
}
return n - (int)((uint)(i << 1) >> 31);
。 - voxoidInteger.numberOfTrailingZeros
)。 - thecodewarriorint trailingZeros(int n) {
if(!n)
return 32;
for(int s = 0; !(n & 1); s++)
n >>= 1;
return s;
}
这个 Java 版本的变体使用了更多的位操作来消除最后一个条件测试:
public static uint Ctz(uint num)
{
if (num == 0) return 32; // optional, otherwise returns 0
uint tmp;
uint res = 0;
num &= (uint)-(int)num; // Isolate bit
tmp = num >> 16; if (tmp != 0) { num = tmp; res += 16; }
tmp = num >> 8; if (tmp != 0) { num = tmp; res += 8; }
tmp = num >> 4; if (tmp != 0) { num = tmp; res += 4; }
return res + ((num >> 1) - (num >> 3));
}
int
或long
吗? - Robert Harvey