如何计算整数中的零位数? 如何在C++中找到“0”位的数目。 假设我有一个整数 int value = 276;

如何计算整数中的零位数? 如何在C++中找到“0”位的数目。 假设我有一个整数 int value = 276;,c++,bits,C++,Bits,我有100010100位,但是如何计算零呢?最简单最简单的方法就是迭代位并计算: size_t num_zeroes = 0; for(size_t i = 0; i < CHAR_BIT * sizeof value; ++i) { if ((value & (1 << i)) == 0) ++num_zeroes; } size\t num\u zeroes=0; 对于(大小i=0;i>=1) { numbits+=i&1; } } 虽然如果i是负

我有100010100位,但是如何计算零呢?

最简单最简单的方法就是迭代位并计算:

size_t num_zeroes = 0;

for(size_t i = 0; i < CHAR_BIT * sizeof value; ++i)
{
  if ((value & (1 << i)) == 0)
    ++num_zeroes;
}
size\t num\u zeroes=0;
对于(大小i=0;iif((value&(1)到目前为止,最明显的解决方案是查找表

/* Assuming CHAR_BITS == 8 */
int bitsPerByte[256] = { 8, 7, 7, 6, /* ... */ };
int bitsInByte(unsigned char c) { return bits[c]; }

有一本关于这类东西的好书:(是的,这个名字很烂:它与安全无关,只不过是一点点的玩弄)。它提供了几种计算“1”位的算法,最好的也可以找到(尽管这本书解释了这个网站没有)


知道“1”位计数后,只需将其减去类型表示中的位数即可。

您可以进行32减法。

如果使用GCC,您可以尝试内置函数:

int __builtin_popcount (unsigned int x) 
int __builtin_ctz (unsigned int x)
int __builtin_clz (unsigned int x)

请参阅以了解详细信息。

先致意,然后数一数1

计数零位(x)=计数一位(~x)

实现代码来计算一个

template< typename I > 
int count_one_bits( I i )
{
   size_t numbits = 0;
   for( ; i != 0; i >>= 1 )
   {
      numbits += i&1;
   }
}
模板
整数计数1位(I)
{
大小\u t numbits=0;
对于(;i!=0;i>>=1)
{
numbits+=i&1;
}
}
虽然如果i是负数,我的函数会有问题,因为>>会将1位放入右侧,因此将得到一个永不终止的循环。如果有一种模板化的方法来强制执行无符号类型,这将是理想的

一旦你做到了这一点:

template< typename I > int count_zero_bits( I i )
{
   return count_one_bits( ~i );
}
templateint count\u zero\u位(I)
{
返回计数1位(~i);
}
将工作。

计数设置位

unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
  v &= v - 1; // clear the least significant bit set
}
可以很容易地适应给定的任务。这里的迭代次数等于设置的位数


我还建议使用上面的链接来解决此任务和其他类型的位相关任务。还有一个获取宏中实现的位计数的单行示例。

如果您想要提高效率,那么在《黑客之乐》一书中有一个很好的实现

22分免费

unsigned int count_1bits(unsigned int x)
{
    x = x - ((x >> 1) & 0x55555555);
    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
    x = x + (x >> 8);
    x = x + (x >> 16);
    return x & 0x0000003F;
}

unsigned int count_0bits(unsigned int x)
{
    return 32 - count_1bits(x);
}
我将试着解释它是如何工作的。它是一种分而治之的算法

(x >> 1) & 0x55555555
将所有位向右移动1步,并获取每个位对的最低有效位

0x55555555 -> 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 (16x2 bit pairs)
所以基本上你会有下表中所有的2位排列

1. (00 >> 1) & 01 = 00
2. (01 >> 1) & 01 = 00
3. (10 >> 1) & 01 = 01
4. (11 >> 1) & 01 = 01

x - ((x >> 1) & 0x55555555);
然后从非移位对中减去这些

1. 00 - 00 = 00 => 0 x 1 bits
2. 01 - 00 = 01 => 1 x 1 bits
3. 10 - 01 = 01 => 1 x 1 bits
4. 11 - 01 = 10 => 2 x 1 bits

x = x - ((x >> 1) & 0x55555555);
所以现在我们改变了每2位对,它们的值就是它们对应的原始2位对的位数…然后我们以类似的方式继续4位组,8位组,16位组和最后的32位


如果你想得到更好的解释,那就买这本书吧,书中有很多很好的解释和关于替代算法等的讨论。

根据我的说法,获得正整数中零位计数的最简单方法是下面的代码

int get_zero_bit_count(int num)
{
    int cnt = 0;

    while(num > 0)
        {
            int and_num = num & 1;

            if (and_num != num) cnt++;

            num >>= 1; 
        }

        return cnt;
    }

这段代码很容易理解,并且是selp解释性的。这对正整数很有效。

我很惊讶没有人提到这段代码:

int num_zero_bits = __builtin_popcount(~num);

当与GCC一起使用时,这将给出
num
中的零位数。

扩展ronag的答案,其他用户提到的答案会导致错误的结果(他的算法只适用于x=15的值),下面是算法的更新版本:

uint8_t count_1bits(uint32_t x) {
    x = x - ((x >> 1) & 0x55555555);
    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
    x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
    x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
    x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF);
    return x & 0x3F;
}

uint8_t count_0bits(uint32_t x)    {
    return 32 - count_1bits(x);
}
ronag对第一行的解释是正确的,但是,其余的行使用不同的方法。在第一行中,通过移位和减法,每个2位对将包含在该对中设置的原始数字位数。其余的行通过加法递归地将这些数字折叠在一起每个2n位组到该对msb的lsb移位n,以便2n位组包含该组中设置的原始位数:

01110110: 0111 (7 bits were set in the original number) 0110 (6 bits were set in the original number)
-> 01110110 & 00001111 + (01110110 >> 4) & 00001111
= 0110 + 0111
= 1101
上述算法适用于32位整数,但可以通过将常数更改为正确的位长度,使模式保持不变(例如0x5555…=0101…,0x0f0f…=00001111…等)并添加/删除适当的移位来轻松调整
#include <bits/stdc++.h>
using namespace std;
#define ll long long int


int main() {
    ll a;
    cin>>a;
    ll ones=__builtin_popcountll(~a);
    ll zero=__builtin_clzll(a);
    ll num=abs(ones-zero);
    cout<<num<<"\n";
    return 0;
}
使用名称空间std; #定义ll long long int int main(){ 法学硕士; cin>>a; ll ones=uuu内置的uu popcountll(~a); ll zero=内置clzll(a); ll num=绝对值(零一);
库切克:试着用谷歌搜索“比特计数”你忘记了23个前导零了吗?是的,是的,我知道这取决于整数表示;)最近,我花了相当多的时间研究优化谷本计算的
popcount
;以下是几种方法的一个很好的总结:最终使用了16位LUT,它简单且比最快的LUT慢得多。如果你关心速度的话。我认为“计算零位的数量”到目前为止,对于“如何计算整数中的零位数”的问题,更明显的解决方案是8*sizeof(int)-(设置位数)吗,但建议是good@VJo那么C++标准是否授权一个8位字节?从技术上讲,在C中,你不能假设siZof在8位字节中返回大小。@ JeremyP是正确的。C++标准,1.7-1。“一个字节至少大到足以包含基本执行字符集的任何成员,并且由连续的位序列组成,其数量由实现定义。”是的,您需要
CHAR\u BIT*sizeof(int)
即使这样,也只是告诉你内存中的大小,而不是int的值表示实际需要多少位。你从
std::numeric\u limits::digits+std::numeric\u limits::is\u signed
这个词的含义被误解了。“黑客”或“黑客”不仅仅是关于安全性。在这种情况下,它只是意味着”聪明还是快速解决(见维基百科)。:@SysAdmin:不幸的是,该死的媒体把hack/hacking/hacker的意思扭曲成了crack/cracking/cracker。尽管如此,我们中的一些人仍然抵制。@SysAdmin:tr
#include <bits/stdc++.h>
using namespace std;
#define ll long long int


int main() {
    ll a;
    cin>>a;
    ll ones=__builtin_popcountll(~a);
    ll zero=__builtin_clzll(a);
    ll num=abs(ones-zero);
    cout<<num<<"\n";
    return 0;
}