位操作符以及几种常见应用

操作符详解

  • 原反补
  • 移位操作符
    • 1、左移操作符
    • 2、右移操作符
    • 3、示例
  • 位操作符
    • 例1:不创建临时变量,交换两个数
    • 例2:求一个整数存储在内存中二进制中1的个数
    • 百度笔试题:如何判断一个数字是否为2的K次幂(不需要计算K)

原反补

加法器计算机里面,只有加法器,没有减法器,所有的减法运算,都必须用加法进行。通过被减数的补码代替被减数,可以把减法转变为加法运算。
补码减法所依据的基本关系式:
[x-y]补 =[x+(-y)]补= [x]补+ [-y]补
原码:1000 0001
反码:1111 1110 原码取反
补码:1111 1111 反码+1/原码从右数第一个1保留,其余位取反,符号位不变
负数的原反补才有意义,正数的原反补均相同。
数0的补码表示是唯一的:
[+0]补=[+0]反=[+0]原=00000000
[ -0]补=11111111+1=00000000

移位操作符

<< 左移操作符
>> 右移操作符

1、左移操作符

规则:左边扔掉,右边补0;

2、右移操作符

1、逻辑移位规则:右边丢掉,左边用0补充
2、算术移位规则:右边扔掉,左边补符号位

3、示例

1)负数的右移:负数右移的二进制的右边补1。如果一直右移的话,最后就就变成0xFFFFFFFF 即-1。如: -4>>1 为-2 ;-4>>2为-1;-1>>-1
2)负数的左移:跟正整数左移一样,右边补0,一直左移的话,最后就是0。
3)正数的右移:相当于除以2。
4)正数的左移:相当于乘以2。

int main() {
	int a = -1;
	int b = 2;
	printf("-1左移一位后:%d\n",a << 1);//1111 1111左移一位之后变为1111 1110=-2;
	printf("-1右移一位后:%d\n",a >> 1);//仍然是-1;
	printf("2左移一位后:%d\n",b << 1);//0010左移一位之后变为0100=4;
	printf("2右移一位后:%d\n",b>> 1);//0010右移一位之后变为0001=1;
	return 0;
}

位操作符

& :按位与
| :按位或
^ :按位异或
注:他们的操作数必须是整数

例1:不创建临时变量,交换两个数

第一种

#include 
int main()
{
int a = 10;
int b = 20;
a = a^b;
b = a^b;
a = a^b;
///
a=a+b;//第二种方式
b=a-b;
a=a-b;// 不用担心溢出,因为溢出之后会被减回来。
printf("a = %d b = %d\n", a, b);
return 0;
}

提一下为什么不用担心溢出,因为在计算机的数据的存储中好比是一个圆:以int型为例。int的存储范围是(-2147483648,2147483647),所以我们可以看成一这样可以循环的圆,2147483647+再加上一个1就会变成-2147483648
位操作符以及几种常见应用_第1张图片

#include
int main() {
	int a = 2147483647;
	printf("%d\n", a + 1);
	int b = -2147483647-1;//注意不能直接取值到-2147483648,会报错
	printf("%d\n", b - 1);
	return 0;
}

位操作符以及几种常见应用_第2张图片

不明白的小伙伴可以自己动手算一算

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

//方法1
#include 
int main()
{
	int num = 10;
	int count= 0;//计数
	while(num)//缺陷:如果num为负数会死循环
	{
		if(num%2 == 1)//每一次都模2,相当于取了二进制的最后一位,如果为1则记录一次
			count++;
		num = num/2;//num右移一位
	}
	printf("二进制中1的个数 = %d\n", count);
	return 0;
}
//方法2:
#include 
int main()
{
	int num = -1;
	int i = 0;
	int count = 0;//计数
	for(i=0; i<32; i++)//负数也可以计算,因为不管正负循环都只循环32次,不会再记录后补的位
	{
		if(((num>>1) & 1) != 0)
		{
			count++;
		}
	}
	printf("二进制中1的个数 = %d\n",count);
	return 0;
}
//但是这里必须循环32次,还可以对循环的次数进行优化
//方法3,最终版本,但也是最难想到的版本
#include 
int main()
{
	int num = -1;
	int i = 0;
	int count = 0;//计数
	while(num)//num不等于0时
	{
		count++;
		num = num&(num-1);//每&一次都会减少一个1,所以记录循环次数就可以得到1的位数
	}
	printf("二进制中1的个数 = %d\n",count);
	return 0;
}

百度笔试题:如何判断一个数字是否为2的K次幂(不需要计算K)

通过题干分析我们知道,如果是2的K次幂,那么二进制数中只有1个1,所以我们就判断count最终是不是等于1,就可以了

#include 
int main()
{
	int num = 0;
	scanf("%d", &num);
	int i = 0;
	int count = 0;//计数
	while (num)//num不等于0时
	{
		count++;
		num = num & (num - 1);//每&一次都会减少一个1,所以记录循环次数就可以得到1的位数
	}
	if (count == 1)
	{
		printf("该数字是2的K次幂");
	}
	else {
		printf("该数字不是2的K次幂")}
	return 0;
}

你可能感兴趣的:(笔记,补码,c++)