方法一:
首先,简单思路为:给该整数模2除2我们就能得到该数2进制的每一位
用9举例,9的二进制数为1001 (9%2=1,(9/2)%2=0, (9/2/2)%2=0, (9/2/2/2)%2=1)
那么就想到了第一种方法:
#include "stdio.h"
void main()
{
int num = 9;
int count = 0;
while(num)
{
if(num%2 == 1)
{
count++;
}
num = num/2;
}
printf("%d", count);
return 0;
}
输出结果为:9
方法二:
然而很明显上面的方法对于负数来说是不适用的:
用-1举例,
-1 的原码是:10000000 00000000 00000000 00000001
-1 的反码是:11111111 11111111 11111111 11111110
-1 的补码是:11111111 11111111 11111111 11111111
而在内存中我们存的是一个整数的32位补码
则计算机中参数-1 二进制的个数就是32个。
那么可以换一种方法来判断一个二进制数位 是0 还是1
例: 10的二进制数是1010
判断他的最后一位是不是1,可以给10 与1, 1010&0001=0000,
如果是1011&0001=0001,那么可见通过&1 就能判断该数最后一位是否为1
最后一位判断完了,我们就需要判断倒数第二位,可以通过">>"符号进行移位,从而让最后倒数第二位移到最后一位,从而进行判断。
例:
#include<stdio.h>
int main()
{
int num = -1;
int i = 0;
int count = 0;
for(i=0; i<32; i++)
{
if((num&1) == 1)
{
count++;
}
num = num>>1;
}
printf("%d", count);
return 0;
}
输出结果为:32
方法三:
了解C语言的同学都感受得到C语言功能博大精深,我们不难发现规律:
如:1010 & 1001 =1000 1000&0111=0000 (即10&9=8,8&7=0)
1111 & 1110 =1110 1110&1101=1100 1100&1011=1000 1000&0111=0000(即16&15=15,15&14=12, 12&11=8,8&7=0)
因为10的二进制数有两个1,所以10可以&两次,而20的二进制数有4个1,所以他可以&四次
也就是对于一个整数n,n = n&(n-1)所能进行的次数就是其二进制数所含1的个数
例:
#include<stdio.h>
int main()
{
int num = -1;
int count = 0;
while(num)
{
count++;
num = num&(num-1);
}
printf("count=%d\n", count);
return 0;
}
输出结果为:32
方法四:
我们可以通过无符号整形 unsigned int n,将n=-1转换成其对应32位全1所对应的正数,然后通过方法一用于此正数就可以得到结果
#include "stdio.h"
int count_one_bit(unsigned int n)
{
int count = 0;
while(n)
{
if(n%2==1)
{
count ++;
}
n=n/2;
}
return count;
}
int main()
{
int num = -1;
int ret=count_one_bit(num);
printf("ret=%d\n", ret);
return 0;
}
#include "stdio.h"
int count_one_bit(unsigned int n)
{
int count = 0;
while(n)
{
if(n%2==1)
{
count ++;
}
n=n/2;
}
return count;
}
int main()
{
int num = -1;
int ret=count_one_bit(num);
printf("ret=%d\n", ret);
return 0;
}
输出结果为:32