十进制的数字要分离十进制的每一位,要先模上10,获取个位数,接着除以十,将每一个位数都降低一级。再模上十,获取下一位数上的数字,再模上10......以此类推。
而二进制要获得每一位数,也是一样的。先模上2,获取第一位数,接着除以2,将位数降低。接着再模2,再除2......直到全部转化为二进制。
cpp
#include <stdio.h>
int fun(int n)
{
int count = 0;
while (n)
{
if (n % 2 == 1)
{
count++;
}
n /= 2;
}
return count;
}
//这种方法不适用于负数
int main()
{
int n = 0;
scanf("%d", &n);
int count = fun(n);
printf("%d", count);
return 0;
}
每一次循环判断到求得的相应位数为1(即n % 2 为1)时,count就会加一。
但是这种方法有一个缺点,如果n为负数,count的值就会为零,因为count在count++之后就会变成0,而0进入到循环的判断条件中,就会终止循环。
-1的补码应该是32个一,结果应该为32。
正确做法是将函数接收到的参数n转化为无符号整型,如此-1就不会因为二进制的第一位被函数解读为负数了。
如图:
cpp
#include <stdio.h>
int fun(unsigned int n)
{
int count = 0;
while (n)
{
if (n % 2 == 1)
{
count++;
}
n /= 2;
}
return count;
}
//这种方法不适用于负数
int main()
{
int n = 0;
scanf("%d", &n);
int count = fun(n);
printf("%d", count);
return 0;
}
用按位与&实现的方法在我之前的博客中写过了,但是无论是按位与的方法还是上面的方法,当n够大的时候,都要进行多次计算。
有没有一种方法能有多少个一就计算多少次呢,这种方法比较难想到,但是代码本身比较简单。
cpp
#include <stdio.h>
int fun(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
//101011
//101010
//按位与 第一次
//101010
//101001
//按位与 第二次
//101000
//100111
//按位与 第三次
//100000
//000001
//按位与 第四次
//000000
//结果为四
return count;
}
int main()
{
int n = 0;
scanf("%d", &n);
int count = fun(n);
printf("%d", count);
return 0;
这里利用里二进制逢二进一的特点,每当一位数是1后面位数都是0时,减去一就是让其位数变成0。再利用按位与的特点,只有位数都为一时,结果位数才为1。