超简单的位运算—再也不用担心看不懂题解了

  • 写在前面
  • 1.原码、反码与补码——整形在计算机中的储存
  • 2.移位操作符
  • 3.位操作符
  • 4.小练手
  • 写在最后

写在前面

大家好,这里是风扇的小小笔记,本篇博客的内容如下:

1️⃣ 原码、反码与补码的概念及作用
2️⃣ 移位操作符”>>“和”<<"的理解和使用
3️⃣ 位操作符”&“、”|“和”^”的理解和使用

1.原码、反码与补码——整形在计算机中的储存

整形在计算机中是以二进制形式(补码)储存的,与其存储有关的这三种码也是二进制的形式。
⭐️小插曲
二进制的最高位是符号位,1表示负数,0表示正数。
如:0000 0000 0000 0001——— 1
1000 0000 0000 0001——— -1

原码
直接将数值按照正负数的形式翻译成二进制就可以得到原码
反码
正数的反码与原码相同,负数的反码等于原码按位取反(符号位不变)
补码
正数的补码与原码相同,负数的补码等于反码加一

小栗子
这里以9和-9为例求他们的原反补三个码:
00000000 000000000 00000000 00001001—— 9的原码
00000000 000000000 00000000 00001001—— 9的反码
00000000 000000000 00000000 00001001—— 9的补码
10000000 000000000 00000000 00001001—— -9的原码
11111111 11111111 11111111 11110110—— -9的反码(第一个一是符号位,符号位不变其他按位取反)
11111111 11111111 11111111 11110111—— -9的补码(反码+1)

2.移位操作符

⭐️左移操作符

将补码依次向左移动一位,右边补0,重复n次(n为移的位数)

以9为例:9<<1将会得到18(其实就是2倍关系)

⭐️右移操作符

先右移运算分两种:逻辑移位和算术移位,这取决于编译器,不过一般而言都是算数位移

这两种移位都是向右移位,右边删掉区别是:算数移位左边的符号位是保持不变的,而逻辑移位左边是填0代替。

小栗子

以上面的-9为例向右移动一位(这里讲的是算数移位)
计算机储存的是-9的补码:
. 11111111 11111111 11111111 11110111
1 11111111 11111111 11111111 1111011 1(左边的符号位不变即左边补充一个和符号为相同的数,右边移出来的1删掉)
. 11111111 11111111 11111111 1111011 ——结果

⭐️得到的结果也是补码形式的,现在要将他转换成反码,再转换成原码
11111111 11111111 11111111 1111011——补码
11111111 11111111 11111111 1111010——反码(补码-1)
10000000 00000000 00000000 00000101——原码(符号位不变)
显然结果为-5
使用代码printf("%d", -9 >> 1);验证:

注:这里1的宽度和0的宽度不同,以至于上述例子的长度没有对齐,但不影响其准确性。

3.位操作符

  • 按位与—-&
    理解:可以理解为“和”的意思,只有两个数同时为真时结果才为真,其余情况为假。
    这里以一个位的单位来举例:1&1=1,1&0= 0,0&0=0

小栗子
计算5&9的值
00000000 00000000 00000000 00000101—— 5
00000000 00000000 00000000 00001001—— 9
00000000 00000000 00000000 00000001——5&9
易知结果为1,用代码 printf("%d", 5&9);验证如下:

  • 按位或—- “|”
    理解:可以理解为“或”的意识,只有两个数同时为假时,结果才为假,其余情况为真。
    这里以一个位的单位来举例:0|0=0,1|0= 1,1|1=1.

小栗子
计算5|9的值
00000000 00000000 00000000 00000101—— 5
00000000 00000000 00000000 00001001—— 9
00000000 00000000 00000000 00001101——5&9
易知结果为13,用代码 printf("%d", 5|9);验证如下:

  • 按位异或—-^
    理解: 判断两个位的数是否不相同,不同为真,相同为假
    这里以一个位的单位来举例:0 ^ 0=0,1 ^ 0= 1,1 ^ 1=0.

小栗子
计算5 ^ 9的值
00000000 00000000 00000000 00000101—— 5
00000000 00000000 00000000 00001001—— 9
00000000 00000000 00000000 00001100——5 ^ 9
易知结果为12,用代码 printf("%d", 5^9);验证如下:

4.小练手

前面给大家介绍了为操作符的作用,现在打算用几个题给大家介绍一下。
例1:求一个数的二进制中“1”的个数
思路(以9为例):00000000 00000000 00000000 00001001
用1和上面的原码依次进行按位与,如果结果为1则计数器自增1。

而让1与对用位的数按位与还有用到左移操作符,1与第二位数与的时候让1左移一位:
00000000 00000000 00000000 00001001——9
00000000 00000000 00000000 00000001——1
00000000 00000000 00000000 00000010——1<<1

代码展示:

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

结果验证:

例2:求两个数二进制中不同位的个数
思路:利用按位异或,先求出a^b,在计算其二进制中 1 的个数,与例1相似,不再写过程。
例3:不创建临时变量的情况下交换两变量
思路:利用 “^ “的特点,任何两个相同数的二进制形式事相同的,即a^ a=0

可以进行上述推导,现在如果把最后一部分的a ^ b看成一个整体又会如何呢。

由于不能有临时变量,那就用a,b的其中一个变量在中间过程中接收c的值,因为最后的时候a,b都是会重新赋值的,所以这样操作并没有影响a,b的值。

代码实现:

int main(){int a , b ;scanf("%d%d",&a,&b);a = a ^ b;b = a ^ b;a = a ^ b;printf("%d %d", a, b);}

写在最后

非常感谢大伙们的耐心阅读(如果内容还可以的话能不能给个小心心鼓励一下小风扇吧),如果对内容有不明白的可以在评论区直接提问,如果是文章有错误的也还请大佬们指导一番,谢谢大家,这段时间我们一起努力吧,小风扇一定会和大家一起进步的!加油,追梦人!