1. 无符号数、原码、反码、补码
计算机中的数值需要按一定的方式进行存储:
- 原码
- 反码
- 补码
对于正数来说,原码和反码和补码都是一样的,对于负数有不同的规则。
从记忆的角度来看,无符号数是最基本的二进制表示,有符号数是将最高位作为符号位,剩余位数的计数和无符号数保持一致。
我们将有符号数称为原码。反码和补码就无法直接肉眼得出数值。
反码 = 原码的符号位不变,剩余取反(或者是这个数的正数部分所有位取反)
补码 = 反码 + 1
比如我们要求 -127 这个数的补码: 首先知道 127 的二进制为 0111 1111 取反得到 1000 0000 再加 1 得到 1000 0001 再顺一下 -127 这个数字的各个码的表达形式: 无符号数 = 无法表示 有符号数(原码) = (1)111 1111 符号位为1 反码 = 1000 0000 补码 = 1000 0001
有助于理解的表格:
网图,侵删
2.意义
补码是为了简化cpu运算,使得加减乘除运算仅通过加法器+补码表示就能实现。
如果直接使用原码进行运算,直接用加法运算原码算不出正确的结果,而引入复杂逻辑判断符号位会复杂化 cpu 的设计
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
因此出现了补码,使得有符号数能直接通过加法器实现减法运算,乘法和除法也就可以实现了。
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
3. Python 位运算
3.1 位运算
print(f"11 = {bin(11)}")# 取反print(f"~11 = {bin(~11)}")# 左移print(f"11 << 2 = {bin(11 << 2)}")# 右移print(f"11 >> 2 = {bin(11 >> 2)}")print(f"10 = {bin(10)}")# 按位与print(f"10&11 = {bin(10&11)}")# 按位或print(f"10|11 = {bin(10|11)}")# 按位异或print(f"10^11 = {bin(10^11)}")11 = 0b1011~11 = -0b110011 << 2 = 0b10110011 >> 2 = 0b1010 = 0b101010&11 = 0b101010|11 = 0b101110^11 = 0b1
3.2 利用位运算实现快速运算
2的倍数
n = 3# n 乘 2 的 1 次方print(f"n = {n}")print(f"n*2 = {n << 1}")print(f"n*(2^n) = {n << n}")print(f"2^n = {1 << n}")n = 3n*2 = 6n*(2^n) = 242^n = 8
快速交换2个数
a = 2b = 3a ^= bb ^= aa ^= bprint(f"a = {a}")print(f"b = {b}")a = 3b = 2
快速获取 a 最后一个位置的数
a = 10print(f"a = {bin(a)}")print(f"a & (-a) = {bin(a & (-a))}")a = 0b1010a & (-a) = 0b10a = 0b1011a & (-a) = 0b1
