位运算小记顺带复习一下原码补码反码

今天看到一些位运算操作的代码,整个人瞬间宕机了,就抽时间了解了一下,顺便做了点笔记。

1|0位运算符概览

运算符 运算规则
按位与 & 两个操作数同时为1,结果为1
按位或 I 两个操作数只要有一个为1,结果就为1
按位非 ~ 1变0,0变1
按位异或 ^ 两个操作数相同,结果为0,不相同,结果为1
左移 << 二进制数整体左移,高位(左侧)丢弃,低位(右侧)补0
右移 >> 二进制数整体右移,低位(右侧)丢弃,正数左侧空位补0,负数左侧空位补1

位运算是直接操作二进制数的运算,在解释其运算规则时,先来了解一下二机制数的相关概念。

2|0原码 反码 补码

计算机中都是用0和1来表示数据的,以8位二进制数为例0000 0000就代表0,但是这样没办法表示负数,于是就规定最左侧的一位为符号位,0为正,1为负,其他位为真值,这种方法表示的就叫原码

那么计算机在实际运算的时候是直接拿原码来计算的吗,我们先来看一个例子:
1 + 1 = 0000 0001 + 0000 0001 = 0000 0010 = 2
结果好像没错,但是我们先别忙着下结论,再来看下一个例子:
1 - 1 = 1 + (-1) = 0000 0001 + 1000 0001 = 1000 0010 = -2
从这里就看出问题来了,直接使用原码计算会出现错误,经过研究,人们发现对于负数,将其真值部分按位取反,正数则不做改变,这就是反码,也即正数的反码是其原码本身,负数的反码为除符号位按位取反,再对其进行上述运算就能得出正确的结果,如下:
1 - 1 = 1 + (-1) = 0000 0001原 + 1000 0001原 = 0000 0001反 + 1111 1110反 = 1111 1111反 = 1000 0000原 = -0
但是这种也有问题,-0的负号显然是无意义的,而且此时0的二进制有两种表示方式,这肯定会给一些计算带来问题。于是人们在此基础上继续深入研究,最终提出了补码的概念,即正数的补码是其原码本身,负数的补码为其反码加1,再来看看计算结果:
1 - 1 = 1 + (-1) = 0000 0001原 + 1000 0001原 = 0000 0001补 + 1111 1111补 = 0000 0000补 = 0000 0000原 = 0
这下终于没问题了,所以在计算机内部的二进制表示其实都是用补码来进行的,与此同时人们也规定了1000 0000表示-128,这也解释了为什么有符号8位整型的范围是-128到127。

这里再总结一下:

  • 正数最简单:三码合一
  • 负数的反码:符号位不变,真值按位取反,也即其正数的原码按位取反
  • 负数的补码:其反码加1,也即其正数的原码按位取反后加1

关于这块更深入的研究可以看下这篇文章原码补码反码,里面关于补码的数学原理解释的很清晰,简直不要太强。在了解了计算机内部使用的是补码这个机制后再看位运算其实就没那么懵逼了。

3|0按位与 &

简单来说就是同1为1,否则为0,比如1 & -1,注意这里负数要用其补码,正数三码合一就无所谓了:
1 & -1 = 0000 0001补 & 1111 1111补 = 0000 0001= 1

与运算的用途:
1)清零
如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。
2)取一个数的指定位
比如取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。
3)判断奇偶
只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数。

4|0按位或 |

简单说就是有1为1,否则为0,比如1 & -1,负数依然要用其补码,:
1 | -1 = 0000 0001补 | 1111 1111补 = 1111 1111补= 1000 0001原 = -1

或运算的用途:
1)常用来对一个数据的某些位设置为1
比如将数 X=1010 1110 的低4位设置为1,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位或运算(X|Y=1010 1111)即可得到。

5|0按位非 ~

这个最简单,是一个单目运算符,就是把二进制数的每一位的1变成0,0变成1,比如:

1 `0000 0001` ~1 `1111 1110`补 = `1000 0010`原 = -2 -1 `1111 1111`~(-1) `0000 0000`补 = 0

有一个快速求非的公式也可以记一下,非常简单:~x=x*(-1)-1=-(x+1)

非运算的用途:
1)使一个数的最低位为零
使a的最低位为0,可以表示为:a & 1。1的值为 1111 1110,再按"与"运算,最低位一定为0。因为" ~"运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高

6|0按位异或 ^

简单记为相同为0,不同为1,比如:
1 ^ (-1) = 0000 0001补 ^ 1111 1111补 = 1111 1110补 = 1000 0010原 = -2

异或的几条性质:
1、交换律 a ^ b = b ^ a
2、结合律 (a ^ b) ^ c = a ^ (b ^ c)
3、对于任何数x,都有 x ^ x=0,x ^ 0 = x
4、自反性: a ^ b ^ b = a ^ 0 = a;

异或运算的用途:

1)翻转指定位
比如将数 X=1010 1110 的低4位进行翻转,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行异或运算(X^Y=1010 0001)即可得到。
2)与0相异或值不变
例如:1010 1110 ^ 0000 0000 = 1010 1110
3)交换两个数的值

fn swap(mut a:i32,mut b:i32){ if a != b { a ^= b; // a = a ^ b b ^= a; a ^= b; println!("{},{}",a,b); } }

7|0左移 << 和 右移 >>

就是字面意思,举个栗子就能明白了:
左移:整体左移,高位(左侧)丢弃,低位(右侧)补0,若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2
1 << 3 = 0000 0001 << 3 = 0000 1000 = 8
负数通过补码移位后如果最高位为正,需要补上负号
-1 << 3 = 1111 1111补 << 3 = 1111 1000补 = 1111 0111反 = 0000 1000原 = -8

右移:整体右移,低位(右侧)丢弃,正数左侧空位补0,负数左侧空位补1,每右移一位,相当于该数除以2
48 >> 3 = 0011 0000 >> 3= 0000 0110 = 6
-48 >> 3 = '1101 0000'补 >> 3 = 1111 1010补 = 1000 0110 = -6


__EOF__

本文作者Ransang
本文链接https://www.cnblogs.com/ransang/p/17723721.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Ransang  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示