如何检查int中是否只设置了一位?

时间:2018-06-29 05:00:27

标签: c++ bit-manipulation

我有一个std::uint32_t,想检查是否设置了确切的一位。如何在不遍历所有位的情况下执行此操作?换句话说,可以简化以下功能吗?

static inline bool isExactlyOneBitSet(std::uint32_t bits)
{
    return ((bits & 1) == bits
        || (bits & 1 << 1) == bits
        || (bits & 1 << 2) == bits
        // ...
        || (bits & 1 << 31) == bits
        );
}

奖金:如果返回值是找到的一位或0,那就太好了。

static inline bool isExactlyOneBitSet(std::uint32_t bits)
{
if (bits & 1) {return 1;}
else if  (bits & 1 << 1) {return 1 << 1;};
//...
else if  (bits & 1 << 31) {return 1 << 31;};

return 0;
}

2 个答案:

答案 0 :(得分:4)

所以您想知道一个数字是否为2的幂?嗯,有一个著名的算法可以做到,

check_bit(std::uint32_t bits)
{
    return bits && !(bits & (bits-1));
}

任何2的幂乘以1都等于1s。例如,

4 - 1 = 3 (011)
8 - 1 = 7 (0111)

按位与2的任意幂和小于1的任何数字1将得到0。因此,我们可以使用表达式n&(n-1)来验证数字是否为2的幂。

n=0时它将失败,因此我们必须添加一个额外的and条件。

要查找钻头的位置,您可以执行以下操作:

int findSetBit(std::uint32_t bits)
{
    if (!(bits && !(bits & (bits-1))))
        return 0;
    return log2(bits) + 1;
}

其他东西

在gcc中,您可以使用__builtin_popcount()查找任意数量的设置位数。

#include <iostream>

int main()
{
   std::cout << __builtin_popcount (4) << "\n";
   std::cout << __builtin_popcount (3) << "\n";

   return 0;
}

然后检查计数是否等于1

关于计数,还有另一种著名的算法 Brian Kernighan的算法。用Google搜索它,它会在log(n)时间内找到计数。

答案 1 :(得分:1)

这是您的红利问题的解决方案(当然,这也是您原来的问题的解决方案):

std::uint32_t exactlyOneBitSet(std::uint32_t bits) {
    return bits&(((bool)(bits&(bits-1)))-1);
}

这会在带有clang的x86_64上仅编译为4条指令:

0000000000000000 <exactlyOneBitSet(unsigned int)>:
   0:   8d 4f ff                lea    -0x1(%rdi),%ecx
   3:   31 c0                   xor    %eax,%eax
   5:   85 f9                   test   %edi,%ecx
   7:   0f 44 c7                cmove  %edi,%eax
   a:   c3                      retq