我编写了一个函数railing_zeroes(int n),该函数以数字的二进制表示形式返回尾随零的数字。
示例:二进制文件中的4
是100
,因此本例中的函数返回2
。
unsigned trailing_zeroes(int n) {
unsigned bits;
bits = 0;
while (n >= 0 && !(n & 01)) {
++bits;
if (n != 0)
n >>= 1;
else
break;
}
return bits;
}
if
语句的原因是因为如果n
等于0,则会出现循环。我认为这样编写的代码非常难看。有没有更好的办法?
我想避免在
break
中使用while
语句,因为很多人告诉我,在while/for
中使用该语句有时可能是“非正式的”。我本来想重写函数,但我认为这不是最好的方法:unsigned bits;
if (n == 0)
return bits = 1;
bits = 0;
while (!(n & 01)) {
++bits;
n >>= 1;
}
最佳答案
您的函数不正确:0
仍然具有无限循环。测试应为:
while (n > 0 && !(n & 1))
请注意,您无法使用这种方法处理负数,因此您的函数可能应该使用unsigned
数字参数,或者可以将参数转换为unsigned
。您的函数应为特殊情况
0
并使用更简单的循环:unsigned trailing_zeroes(int n) {
unsigned bits = 0, x = n;
if (x) {
while ((x & 1) == 0) {
++bits;
x >>= 1;
}
}
return bits;
}
上面的功能非常简单易懂。如果结果很小,那将是非常快的。为0
返回的值与函数中的0
一样,这是值得怀疑的,因为0
实际上具有与unsigned
类型的值位一样多的尾随零。有一种更有效的方法,其步骤数不变:
unsigned trailing_zeroes(int n) {
unsigned bits = 0, x = n;
if (x) {
/* assuming `x` has 32 bits: lets count the low order 0 bits in batches */
/* mask the 16 low order bits, add 16 and shift them out if they are all 0 */
if (!(x & 0x0000FFFF)) { bits += 16; x >>= 16; }
/* mask the 8 low order bits, add 8 and shift them out if they are all 0 */
if (!(x & 0x000000FF)) { bits += 8; x >>= 8; }
/* mask the 4 low order bits, add 4 and shift them out if they are all 0 */
if (!(x & 0x0000000F)) { bits += 4; x >>= 4; }
/* mask the 2 low order bits, add 2 and shift them out if they are all 0 */
if (!(x & 0x00000003)) { bits += 2; x >>= 2; }
/* mask the low order bit and add 1 if it is 0 */
bits += (x & 1) ^ 1;
}
return bits;
}
请注意,我们可以通过将第一步更改为更大的int
大小来处理while (!(x & 0x0000FFFF)) { bits += 16; x >>= 16; }
一些编译器具有内置函数__builtin_ctz()
,可以使用非常有效的汇编代码来计算尾随零的数量。它不是C标准函数,但是以降低可移植性为代价,如果可用,您可能希望使用它。查看编译器的文档。这是GCC docuemntation的摘要:
关于c++ - 尾随零,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45221914/