原码、反码、补码与位运算(与/或/异或/取反)
目录
- 一、为什么会有原码、反码、补码
- 三者关系总结
- 二、四大位运算
- 2.1 按位与(&)
- 应用
- 2.2 按位或(|)
- 应用
- 2.3 按位异或(^)
- 异或的重要性质
- 应用
- 2.4 按位取反(~)
- 计算~6
- 应用
一、为什么会有原码、反码、补码
计算机只能识别0和1,也就是二进制。那我们怎么表示负数呢?
人们最先想到的办法:把二进制的最高位拿出来当符号位,0表示正数,1表示负数,剩下的位表示数值。这就是「原码」。
但原码有个致命问题:减法算不对。
比如计算1 + (-1),用8位原码算:
0000 0001 (+1的原码) + 1000 0001 (-1的原码) ------------ 1000 0010 (结果是-2,明显不对)为了解决原码的减法问题,人们发明了「反码」:负数的数值位按位取反,符号位不变。这样减法就可以转换成加法来算。
但反码还是有问题:0有两种表示(+0:00000000,-0:11111111),一个数有两个编码显然不合理。
最终,人们在反码的基础上加1,发明了「补码」,完美解决了0的唯一性和减法运算的问题,成为了计算机的最终选择。
核心结论:计算机中整数的存储和运算,全部使用补码。后面所有位运算,都是对补码的二进制位进行操作。
记忆锚点:正数三码合一,负数反码加1。记住这一句话,原反补的关系就串起来了。
三者关系总结
| 十进制数 | 原码 | 反码 | 补码 |
|---|---|---|---|
| +5 | 0000 0101 | 0000 0101 | 0000 0101 |
| -5 | 1000 0101 | 1111 1010 | 1111 1011 |
| +0 | 0000 0000 | 0000 0000 | 0000 0000 |
| -0 | 1000 0000 | 1111 1111 | 0000 0000(溢出丢弃) |
二、四大位运算
2.1 按位与(&)
运算规则:只有对应位都为1时,结果位才为1;只要有一个是0,结果就是0。
| 位A | 位B | A & B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
应用
按位与的核心作用是清零、保留、判断,像一个过滤网,只留下我们想要的位。
- 清零指定位置:构造掩码,要清零的位设为0,保留的位设为1,做按位与。
例:保留低4位,高4位清零:num = num & 0x0F;
解释: 0x0F 的二进制是 0000 1111。和原数做 & 之后,高 4 位和 0 相与全部变 0,低 4 位和 1 相与保持原样,精准实现 “保留低 4 位、清零高 4 位”。
- 判断某一位是否为1:判断第n位(从0开始):
if (num & (1 << n))
解释:1<<1 是 0000 0010,6 的二进制是 0000 0110,按位与结果是 0000 0010(非 0),说明第 1 位是 1。
- 判断奇偶性:
num & 1结果为1是奇数,为0是偶数(比取模%快得多)
解释:1 的二进制只有最低位是 1,和 num 做 & 之后,只保留最低位,其余位全部清零。
2.2 按位或(|)
运算规则:对应位中只要有一个是1,结果位就是1;只有全为0时,结果才是0。
| 位A | 位B | A | B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
应用
按位或的核心作用是置1、合并,像一个“叠加器”,把指定的位“点亮”。
- 将指定位置为1:构造掩码,要置1的位设为1,其余为0,做按位或。
例:把第2位置1:num = num | (1 << 2);
解释:2 的二进制是 0000 0010,1<<2 是 0000 0100,按位或之后是 0000 0110(十进制 6)。第 2 位成功变成 1,其他位保持不变。
- 合并标志位:用每一位代表一种状态,通过或运算叠加多个权限。
例:int perm = READ | WRITE;同时赋予读和写权限
解释:READ | WRITE 结果是 0011,两个权限位都被置 1。这是操作系统、驱动代码里管理状态的标准方式。
2.3 按位异或(^)
运算规则:对应位相同则结果为0,不同则结果为1。
很多初学者容易把异或和或搞混,记住:异或是“不一样才为1”,或是“有1就为1”。
| 位A | 位B | A ^ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
异或的重要性质
- 自身异或等于0:
a ^ a = 0 - 异或0等于自身:
a ^ 0 = a - 交换律:
a ^ b = b ^ a - 结合律:
(a ^ b) ^ c = a ^ (b ^ c)
应用
异或是位运算里最巧妙的一个,核心作用是翻转、交换、去重。
- 翻转特定位:构造掩码,要翻转的位设为1,其余为0,做异或。
例:翻转低4位:num = num ^ 0x0F; - 不使用临时变量交换两个整数:经典面试题
a=a^b;b=a^b;// 等价于 b = (a^b)^b = a^(b^b) = a^0 = aa=a^b;// 等价于 a = (a^b)^a = b - 找出数组中唯一出现奇数次的数:所有数异或,出现偶数次的会抵消为0,剩下的就是答案
2.4 按位取反(~)
运算规则:对二进制的每一位(包括符号位)全部取反,0变1,1变0。
易错点:很多人以为只翻转数值位,实际上符号位也会一起翻转,所以正数取反会变成负数,负数取反会变成正数。
计算~6
步骤:先写补码 → 逐位取反 → 转成原码看十进制
- 6的补码:
0000 0110 - 按位取反:
1111 1001(这是结果的补码,是个负数) - 转原码:补码减1得反码 →
1111 1000,数值位取反 →1000 0111 - 原码对应十进制:-7
所以~6 = -7
快速记忆:对任意整数x,都有
~x = -x - 1
比如 ~6 = -6-1 = -7,~(-5) = 5-1 = 4
应用
- 配合按位与清零低位:比如清零最低位:
num = num & ~1;
(~1就是除了最低位是0,其他位都是1,和num与之后最低位清零,其他位不变) - 快速求补数:配合移位运算实现对齐、向上取整等操作。
