异或操作&位运算

做题时用到了按位异或的操作,有点蒙蒙的,大概查了查位运算的一些东西,略作总结,主要以Python为例。

参考链接

位运算简介

位运算是把数字用二进制表示之后,对每一位上0或1的运算。

所有的运算(包括位运算)在计算机内部都是通过补码的形式进行运算的。

补码是计算机表示数据的一般方式,其规则为:如果是正数,则表示方法和原码一样;如果是负数,则将数字的反码加上1(相当于将原码数值位取反然后在最低位加1)。

例如:

数字 6 在8位计算机中的补码为:0000 0110 (即为其原码)

数字 -6 在8位计算机中的补码为:1111 1010

主要的位运算总共有6种:与、或、异或、取反、左移、右移,如下表所示:

表中示例:

a=60,二进制表示 0011 1100

b=13,二进制表示 0000 1101

运算符 描述 示例
& 按位与:参与运算的两个值,如果两个对应位都为1,则该位的结果为1,否则为0; (a&b)结果为12,二进制 0000 1100
\ 按位或:只要对应的两个二进制位中有一个为1时,该位的结果就为1; (a\ b)结果为61,二进制 0011 1101
^ 按位异或:当两个对应的二进制位不同时,该位的结果为1; (a^b)结果为49,二进制 0011 0001
~ 按位取反:对数据的每个二进制位取反,即把1变成0,把0变成1; (~a)结果为 -61,二进制 1100 0011(有符号二进制数的补码形式)
\<\< 按位左移:数据的每个二进制位均左移若干位,\<\<右边的数字指定移动位数,高位丢弃,低位补0; (a\<\<2)结果为240,二进制 1111 0000
>> 按位右移:数据的每个二进制位均右移若干位,>>右边的数字指定移动位数,具体见下文; (a>>2)结果为15,二进制 0000 1111
  • 左移运算符:m\<\<n 表示把 m 左移 n 位,最左边的 n 位被丢弃,同时在最右边补上 n 个0,如下:

    1
    2
    00001010 << 2 = 00101000
    10001010 << 3 = 01010000
  • 右移运算符:m>>n 表示把 m 右移 n 位,最右边的 n 位被丢弃,但最左边的处理方式有所不同:如果符号位为0,则右移后高位补0,如果符号位为1,则高位补1,也就是说,如果数字是正数,则右移后在最左边补 n 个0,如果数字为负数,则右移后在最左边补 n 个1。如下:

    1
    2
    00001010 >> 2 = 00000010
    10001010 >> 3 = 11110001

如下为Python中所有位运算操作符示意:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
a = 60            # 60 = 0011 1100 
b = 13 # 13 = 0000 1101
c = 0

c = a & b; # 12 = 0000 1100
print "a & b 的值为:", c
c = a | b; # 61 = 0011 1101
print "a | b 的值为:", c
c = a ^ b; # 49 = 0011 0001
print "a ^ b 的值为:", c
c = ~a; # -61 = 1100 0011
print " ~a 的值为:", c
c = a << 2; # 240 = 1111 0000
print " a<<2 的值为:", c
c = a >> 2; # 15 = 0000 1111
print " a>>2 的值为:", c

# result:
# a & b 的值为: 12
# a | b 的值为: 61
# a ^ b 的值为: 49
# ~a 的值为: -61
# a<<2 的值为: 240
# a>>2 的值为: 15

移位运算

运算规则

  • 左移运算符:m\<\<n 表示把 m 左移 n 位,最左边的 n 位被丢弃,同时在最右边补上 n 个0,如下:

    1
    2
    00001010 << 2 = 00101000
    10001010 << 3 = 01010000
  • 右移运算符:m>>n 表示把 m 右移 n 位,最右边的 n 位被丢弃,但最左边的处理方式有所不同:如果符号位为0,则右移后高位补0,如果符号位为1,则高位补1,也就是说,如果数字是正数,则右移后在最左边补 n 个0,如果数字为负数,则右移后在最左边补 n 个1。如下:

    1
    2
    00001010 >> 2 = 00000010
    10001010 >> 3 = 11110001

特殊应用

  • 移位运算是最有效的计算乘/除法的运算之一,把整数左/右移一位,和把整数乘以/除以 2 在数学上是等价的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    a = 2
    print a << 1 # 左移一位等效于a = a * 2;
    # result: 4
    print a << 2 # a左移两位等效于a = a * 2的2次方(4);
    # result: 8

    a = 16
    print a >> 1 # 右移一位等效于a = a / 2;
    # result: 8
    print a >> 2 # 右移两位等效于a = a / (2**2);
    # result: 4

按位与

运算规则

0&0=0,0&1=0,1&0=0,1&1=1。

即:两位同时为“1”,结果才为“1”,否则为0,有0则0

特殊应用

  • 清零指定位:

    mask中指定位置0,其它位为1,a = a & mask

  • 取一个数的指定二进制位:

    mask中指定位置1,其它位为0,a = a & mask

  • 判断一个数二进制表示中1的个数:

    一个整数减去1,再和原数做与运算,会把该整数二进制表示中最右边一个1变为0。

    如:

    • 实现一个函数,输入一个正数,输出该数二进制表示中1的个数:

      1
      2
      3
      4
      5
      6
      7
      8
      num = 0
      n=5 # 二进制:101
      while(n):
      n &= (n-1)
      num += 1
      print str(num)

      # result: 2
    • 判断一个正数是不是2的整数次方:

      如果是2的整数次方,则其二进制表示中有且只有一位是1。

      1
      2
      3
      4
      a=4
      print a&(a-1) == 0

      # result: True

按位或

运算规则

0|0=0;0|1=1;1|0=1;1|1=1。

即 :参加运算的两个对象只要有一个为1,其值为1,有1则1

特殊应用

  • 对数据的指定位置为1:

    mask指定位置1,其它位为0,a = a | mask

    如:将 a = 1010 0000 低四位置1,则 a | 0000 1111 即可。

按位异或

运算规则

0^0=0;0^1=1;1^0=1;1^1=0。

即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0,同0异1

异或特点:

  • 0异或任何数均为原数

  • 1异或任何数,结果为对该数取反

  • 任何数异或自己,结果为0

特殊应用

  • 使特定位翻转:

    mask的特定位置1,其它位为0,a = a ^ mask

    如,对数10100001的第2位和第3位翻转,则可以将该数与00000110进行按位异或运算:10100001^00000110 = 10100111

  • 不使用临时变量,交换两个数的值:

    如,交换两个整数a=10100001,b=00000110的值:

    1
    2
    3
    a = a^b # a=10100111
    b = b^a # b=10100001
    a = a^b # a=00000110
  • 与0异或,保留原值:

    a ^ 0仍为a

-------------本文结束感谢您的阅读-------------
0%