如何计算整数中的零位数? 如何在C++中找到“0”位的数目。 假设我有一个整数 int value = 276;
我有100010100位,但是如何计算零呢?最简单最简单的方法就是迭代位并计算:如何计算整数中的零位数? 如何在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是负
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 if((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;
}