Skip to content

Latest commit

 

History

History
217 lines (118 loc) · 4.74 KB

位运算.md

File metadata and controls

217 lines (118 loc) · 4.74 KB

位运算符作用于二进制数的位上。

用位运算就是直接对整数在内存中的二进制位进行操作,一些场景中使用位运算,其执行效率更高。

数字的二进制表示方式

原码、反码、补码是有符号整数的三种不同表示方式,其中正数的原码、反码、补码一致。

计算机在存储一个数字时并不是直接存储该数字对应的二进制数字(原码),而是存储该数字对应二进制数字的补码。

原码转换为补码的过程,也可以理解为数据存储到计算机内存中的过程。

本小节例子的二进制位数为八位。

graph LR
	0(计算机输入-1) --> 1(原码1000 0001) --> 2(反码1111 1110) --> 3(补码1111 1111) --> 4(内存)
Loading

有符号的八位二进制数中,最大数是1000 0000,而左侧1表示-,但是-0并没有什么实际意义,因此这个数字被用以表示十进制整数-128(它也不存在原码和补码),这也可以解释为什么计算机中一个字节的取值范围是[-128,127]。

  • 原码

    1位符号位+数字绝对值转换的二进制;符号位0表示正,1表示负。

    +1 原码: 0000 0001

    -1 原码: 1000 0001

  • 反码

    表示负数的一种方法,本质是通过取反实现正负的区分。

    • 正数的反码是其本身(即原码)
    • 负数的反码:符号位不变,对其余各位取反

    +1 原码: 0000 0001 反码: 0000 0001

    -1 原码: 1000 0001 反码: 1111 1110

  • 补码

    补码是通过反码实现正负数区分的一种方式。

    • 正数的补码就是其本身(即原码),因此直接转换位十进制数字输出;
    • 负数的补码:第1位为1不变,其余为原码取反再加一

    +1 原码:0000 0001 反码: 0000 0001 补码: 0000 0001

    -1 原码:1000 0001 反码: 1111 1110 补码: 1111 1111

位运算

以下例子中除按位取非运算中均使用正数,略去了符号位以让描述更简约(并不影响计算结果的准确性)。

& 位与

对两个操作数的每一位执行逻辑与操作,如果两个相应的位都为 1,则结果为 1,否则为 0。

1&2 == 0 
# 01
# 11
# 01 --> 1

| 位或

对两个操作数的每一位执行逻辑或操作,如果两个相应的位都为 0,则结果为 0,否则为 1。

1|2 == 3

# 01
# 11
# 11 --> 3

^位异或

对两个操作数的每一位执行逻辑异或操作,如果两个相应的位值相同,则结果为 0,否则为 1。

1^2 == 3
# 01
# 10
# 11 -> 3

~ 位非

对操作数的每一位执行逻辑取反操作,即将每一位的 0 变为 1,1 变为 0。

~1 == -2
  1. 十进制2用八位二进制表示为:0000 0001 (原码即补码——正数)

  2. 对二进制的0000 0001取反得到:1111 1110

    由于的符号位是1,计算机认为这是一个负数的补码,负数输出时先按规则处理:

    • 符号位不变,符号为-

    • 补码减一取反得原码

      1. 二进制计算1111 11101 得到 1111 1101

          1111 1110
        - 0000 0001
          1111 1101  #10 - 01 -> 01
      2. 上一步结果取反

        1111 1101取反得到000 0010即为二进制的2

  3. 原码输出使进制数字即为-2

<< 左移位

将操作数的所有位向左移动指定的位数。左移 n 位相当于乘以 2 的 n 次方。二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。

5*2**3 == 5<<3  # 5x8 == 5*2**3 == 40

>> 右移位

将操作数的所有位向右移动指定的位数。右移n位相当于除以 2 的 n 次方。二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补 0,负数左补 1,右边丢弃。

40/2**3 == 40>>3  # 40/8 == 40/2**3 == 5

>>> 无符号右移位

丢弃各二进位全部右移若干位,高位补0,低位丢弃。某些语言不支持。

12>>>2 == 3
-12>>>2 == 1073741821

位运算使用技巧

判断奇偶数

用整数和1进行与运算,结果值为0则为偶数,否则为基数:

n&1 == 0  #为真则n为偶数,否则n为奇数

判断正整数是否为2的幂

(n - 1) & n==0  #为真则n是2的幂

不使用额外空间交换两个整数

如果两个变量的值都为整数,且希望交换两个变量的值,可使用按位异或:

a ^= b
b ^= a
a ^= b

#如果语言支持连续^=
#a ^= b ^= a ^= b

#---需要额外空间的方法
# 方法 1 使用临时变量
# 方法 2 使用加减法
a = a+b
b = a-b
a = a-b