C语言二进制有关习题

1dff28868a2a4fe8852407e2791119af.png

Hello,大家好,我是一代,今天给大家讲解有关二进制的习题

习题一:求一个整数存储在内存中的二进制1的个数

提示:整数在内存存储时用的是补码

方法一:

很多人想到的方法就是对数进行/2和%2运算,代码如下:

#include<stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	int count = 0;
	while (a)
	{
		if (a % 2 == 1)
		{
			count++;
		}
		a /= 2;
	}
	printf("%d", count);
	return 0;
}

但仔细一想这样的代码是否有问题,当a=-1是否有问题 

10f4ccb257ed48fdae517400c569e745.png

可以看到当输入 -1时输出是0,而正确的答案是32

-1的原码:10000000 00000000 00000000 00000001

-1的反码:111111111 111111111 111111111 111111110

-1的补码:111111111 111111111 111111111 111111111

 可见-1存储在内存中二进制1的个数为32

但其实这样的代码还有可救之处,只要将其改为将a无符号整数就行

代码如下:

#include<stdio.h>
int main()
{
	unsigned a = 0;
	scanf("%d", &a);
	int count = 0;
	while (a)
	{
		if (a % 2 == 1)
		{
			count++;
		}
		a /= 2;
	}
	printf("%d", count);
	return 0;
}

当输入-1时输出是32 

 

7afbfae871f047b4a2831d09e20a6a0d.png

 

方法二:

前面我们学习了移位操作符和按位与,我们就可以想到将1进行进行左移,让其与输入整数进行按位与&,以为1<<i除了所在位为1,其他位为0,进行&就可以保留输入的数二进制所在位为1的位。

代码如下:

#include<stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	int i = 0,count=0;
	for (i = 0; i < 32; i++)
	{
		if (a & (1 << i))
		{
			count++;
		}
	}
	printf("%d", count);
	return 0;
}

但代码其实还有优化的空间

方法三:

这里使用这种方法之前,我跟大家先将解一下这种算法。

当a=15时

a的补码:1111

a-1的补码:1110 

a=a&(a-1)补码为1110

a-1的补码为1101

a=a&(a-1)的补码为1100

a-1的补码为1011

a=a&(a-1)的补码为1000

a-1的补码为0111

a=a&(a-1)的补码为0000

 可以观察到每次a=a&(a-1)后a的二进制中1的个数减少1个,直到a为0是结束。

于是就可以写如下代码:

#include<stdio.h>
int main()
{
	int a = 0,count=0;
	scanf("%d", &a);
	while (a)
	{
		a = a & (a - 1);
		count++;
	}
	printf("%d", count);
	return 0;
}

习题二:将13二进制的第5位修改为1,再修改为0

 修改特定位置的二进制位,就可以将1左移i位,再与数进行就行按位与和按位或将特定位修改位1或者0

代码如下:

#include<stdio.h>
int main()
{
	int a = 13;
	a = a | (1 << 4);
	printf("%d\n", a);
	a = a & ~(1 << 4);
	printf("%d", a);
	return 0;
}

这里有个符号~是按位取反,即把所有二进制位1变成0,0变成1。

习题三:判断一个数是否是2的n次方

上面我们讲了一种算法n&(n-1),一个数是2的n次方,所对应二进制位就只有一个1。

于是就有如下代码:

#include<stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	if ((a & (a - 1))==0)
	{
		printf("%d是2的次方数",a);
	}
	else
	{
		printf("%d不是2的次方数", a);
	}
	return 0;
}

 注意:位运算符的优先级低于关系操作符,所以a&(a-1)要加上括号

 

 

 

  • 37
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值