1.计算一个数字二进制补码里面1的个数
(1)方法一
根据这个10进制的整数,对这个数进行%10,/10不断地进行下去,
%10得到最后一位,/10得到舍去最后一位之后剩余的数;
同理得到:二进制就进行%2/2的操作,不断地进行下去,
%2==1就计数,否则就/2,知道结果是0就退出循环;
int countone(unsigned int m) { int count = 0; while (m) { if (m % 2 == 1) { count++; } m = m / 2; } return count; } int main() { int n = 0; scanf("%d", &n); int ret = countone(n); printf("%d\n", ret); return 0; }
这个里面传参类型设置成unsigned int是因为-1这个特例
但是如果直接输入-1,-1%2不是1,-1/2=0就会直接跳出循环,无法正常计数,所以转换成为无符号整形;
(2)方法二
int countone(int m) { int count = 0; int i = 0; for(i=0;i<32;i++) { if ((m>>i) & 1 == 1) { count++; } } return count; }
这里的m右移i位和1进行按位与运算,32个比特位构成一个循环,依次进行判断输出最后的个数;
(3)方法三
通过这个我们发现m&(m-1)每次都能去掉二进制序列里面后面的一个数字1,这样就可以有几个1就进行几次循环,大大的提高了效率,相比于第二种方法很快,因为第二种无论是否为0都要进行判断,而这种只需要判断是0的数位,但是这种方法难以想到;
int countone(int m) { int count = 0; while (m) { count++; m = m & (m - 1); } return count; }
这里要先进行加加操作,然后每一次就减少一个0;
2.把一个数字的二进制位的某一位0变成1再变成0
#include <stdio.h> int main() { int a = 13; a = a | (1<<4); printf("a = %d\n", a); a = a & ~(1<<4); printf("a = %d\n", a); return 0; }
比如10:00000000 00000000 00000000 00001010把第5位变成0再恢复1
(1)变成0就是把把1左移4位,进行按位或操作,0变为1,后面的和0或操作,1还是1,0还是0,无影响;
(2)再变成0就是做以后取反和a进行按位与操作,原为数字1就变为0其他的和1进行,1还是1,0还是0
换成其他的数字,该方法也是用,只是需要左移n-1位,n是题目要求的第几位数字,这个例子第五
位进行变化,就左移4位
3.输入2个数字,判断他们的二进制位不同的位数
(1)先进行按位异或,相同就是0,不同就是1;
(2)统计1的个数,就回到了第一题的方法;
#include <stdio.h> int main(){ int a=0; int b=0; int c=0; int count=0; while(scanf("%d %d",&a,&b)!=EOF) { c=a^b; while(c) { c=c&(c-1); count++; } } printf("%d",count); return 0; }
4.分别打印一个数字的二进制序列的奇数位和偶数位数字
void Printbit(int num) { for (int i = 31; i >= 1; i -= 2) { printf("%d ", (num >> i) & 1); } printf("\n"); for (int i = 30; i >= 0; i -= 2) { printf("%d ", (num >> i) & 1); } printf("\n"); } int main() { int m = 0; scanf("%d", &m); Printbit(m); return 0; }
这个主要难在如何打印:
(1)是1就打印1,是0就打印0;
(2)将这个二进制序列右移并和1进行按位与运算
例如:第一位是奇数位,向右移动31位,和1进行按位与运算,是1就打印1,是0就打印0;