c++ 如何检查int中是否正好设置了一个位?

iezvtpos  于 2023-03-25  发布在  其他
关注(0)|答案(3)|浏览(110)

我有一个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;
}
odopli94

odopli941#

所以你想知道一个数是否是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的按位与将给予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;
}

然后检查count是否等于1
关于count,还有一个著名的算法,Brian Kernighan的算法。谷歌一下,它在log(n)时间内找到count。

n9vozmp4

n9vozmp42#

下面是你的附加问题的解决方案(当然,它也是你原来问题的解决方案):

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

这在x86_64上只编译了4条指令,并带有clang:

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
yfwxisqw

yfwxisqw3#

给定一个数字n,下面的表达式将确定是否正好设置了一个位(在任何语言中):(n & (n - 1)) == 0 .
要检查一个数字是否是2的正幂,也可以使用表达式(n & (-n)) == n
然而,在JavaScript中,这些表达式在-2^31处失败。
注意这里的按位AND(&)运算符。

相关问题