深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)

在这篇博客中我会首先为大家介绍关于表达式求值中的隐式类型转换,然后为大家详细介绍一些与二进制有关的习题,帮助大家也更好的理解二进制~

文章目录

    • 一.隐式类型转换
    • 二.有关二进制的习题详解
      • 1.统计二进制中1的个数(输入一个数n,输出该数32位二进制表示中1的个数,负值用补码表示)
      • 2.写一个代码,判断数n是不是2的k次方
      • 3.获取一个整数二进制序列中的所有偶数位和奇数位,分别打印出二进制序列
      • 4.判断两个int(32位)整数m和n的二进制表达中,有多少个位不同

一.隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
char类型:1个字节、short类型:2个字节、int类型:4个字节
一般会从从低精度转换为高精度。

如: char a=3;char b=127;char c=a+b;
那么我们会怎么去计算c的值呢?
1.将a和b的值进行截断(char类型占一个字节、八个比特位,则截8个数)
2.然后再将截断后的值进行整形提升,得到一个值
3.再将这个值进行截断,得到八位数
4.根据它的最高位,进行整型提升,若最高位为0,则前面24个数补0,且这个码对应的数就是本身,若最高位为1,则前24个数补0,且这个码为这个数的补码,再由这个补码算出原码,求出这个数

详细过程如下
深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)_第1张图片
由上面可知,c的值算出来为-126.那么接下来我们扩展一个思路,让题目变得更简单。首先在这里我们要知道,这里的char类型,默认为signed char,也就是一个有符号的char类型。其可以是正值,也可以是负值。如图:
深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)_第2张图片
也就是在补码表示中,有符号的char,正数中对应的最大值为127,而这个值再加一之后对应的补码,对应的值为-128.可以写成一个环来表示。
深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)_第3张图片
通过上图的两种解释,相信大家都可以理解啦~

二.有关二进制的习题详解

1.统计二进制中1的个数(输入一个数n,输出该数32位二进制表示中1的个数,负值用补码表示)

不知道大家看到这个题目时和我的第一反应是否一样,我首先想的是把这个数的二进制表示全部打印出来,,但是在这里我就被难到了。那么我们再换个思路想想。
方法一:我们先想想对于一个十进制数,我们是怎么得到它的每一位?
深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)_第4张图片
那么我们就可以这样写出代码:

int main()
{
	unsigned int n = 0;
	scanf("%d", &n);
	int i = 0;
	while (n)
	{

		if (n % 2 == 1)
		{
			i++;
		}
		n=n / 2;
	}
	printf("%d\n", i);
	return 0;
}

方法二:将这个数与1进行按位与的操作,再将这个数右移后进行相同操作
深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)_第5张图片
可以写成:

int main()
{
	int n = 0;
	scanf("%d", &n);
	int i = 0;
	int count = 0;
	for(i=0;i<32;i++)
	{
		if (n & 1 == 1)
			count++;
		n = n >> 1;
	}
	printf("%d\n", count);
	return 0;
}

方法三(一个非常巧妙的方法):进行n&n-1,每操作一次,最右边的一个1就没了,直到最后全为0.
深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)_第6张图片
写成代码即为:

int main()
{
	int n = 0;
	int count = 0;
	scanf("%d", &n);
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	printf("%d\n", count);
	return 0;
}

2.写一个代码,判断数n是不是2的k次方

在写这个题之前,我们首先要知道,对于2的k次方这样的数,它的32位二进制数中,一定只有一个1

则用上面提到的第三种方法可以很容易求解:

int Number(int n)
{
	int count = 0;
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	return count;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = Number(n);
	if (ret == 1)
	{
		printf("这个数是2的k次方");
	}
	else
	{
		printf("这个数不是2的k次方");
	}
	return 0;
}

3.获取一个整数二进制序列中的所有偶数位和奇数位,分别打印出二进制序列

在这题中我们仍要用到上面的n&1的思路。
深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)_第7张图片
在这里就是将n与1异或,可以得到最右边的值,再将n右移2,与1异或,可以得到第3位的值。即移动偶数个即可。

void Print(int n)
{
	int i = 0;
	printf("奇数位\n");
	for (i = 0; i <= 30; i += 2)
	{
		printf("%d ", (n >> i) & 1);
	}
	printf("\n");
	printf("偶数位\n");
	for (i = 1; i <= 31; i += 2)
	{
		printf("%d ", (n >> i) & 1);
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	Print(n);
	return 0;
}

4.判断两个int(32位)整数m和n的二进制表达中,有多少个位不同

方法一:一位一位的判断

void count_diff_one(int m, int n)
{
	int i = 0;
	int count = 0;
	for (i = 0; i < 32; i++)
	{
		if (((m >> i) & 1) != ((n >> i) & 1))
		{
			count++;
		}
	}
	printf("%d\n", count);
}
int main()
{
	int m = 0;
	int n = 0;
	scanf("%d %d", &m, &n);
	count_diff_one(m, n);
	
	return 0;
}

方法二:采用异或

异或操作符
相同为0,相异为1
int count_diff_one(int m, int n)
{
	int count = 0;
	int tmp = m ^ n;
	//统计tmp的二进制中有几个1
	while (tmp)
	{
		tmp = tmp & (tmp - 1);
		count++;
	}
	return count;
}

int main()
{
	int m = 0;
	int n = 0;
	scanf("%d %d", &m, &n);
	count_diff_one(m, n);
	
	return 0;
}

好啦,本节介绍就到这里,在这节中我们超级超级超级详细的介绍了一些操作符的使用,以及与二进制有关的例题,希望大家可以从中有所收获嘿嘿嘿!

你可能感兴趣的:(C语言学习ing,算法)