
对于程序员来说,掌握位运算不仅能够提升代码的执行效率,还能解决一些常规方法难以处理的复杂问题。

在开始探索位运算的高级技巧之前,让我们先简单回顾一下基本的位运算操作。常见的位运算包括与(&)、或(|)、异或(^)、取反(~)、左移(<<)和右移(>>)。
(一)与运算(&)与运算的规则是:只有当两个对应的二进制位都为 1 时,结果位才为 1,否则为 0。
例如,5 & 3 的计算过程如下:
5 的二进制表示为 101
3 的二进制表示为 011
101 & 011 = 001,即结果为 1
(二)或运算(|)或运算的规则是:只要两个对应的二进制位中有一个为 1,结果位就为 1,只有当两个位都为 0 时,结果位才为 0。
例如,5 | 3 的计算过程如下:
5 的二进制表示为 101
3 的二进制表示为 011
101 | 011 = 111,即结果为 7
(三)异或运算(^)异或运算的规则是:当两个对应的二进制位不同时,结果位为 1,相同时结果位为 0。
例如,5 ^ 3 的计算过程如下:
5 的二进制表示为 101
3 的二进制表示为 011
101 ^ 011 = 110,即结果为 6
(四)取反运算(~)取反运算会将二进制位中的 0 变为 1,1 变为 0。
例如,~5 的计算过程如下:
5 的二进制表示为 101
~101 = 010(这里只考虑 8 位二进制的情况,实际计算可能涉及更多位),即结果为 -6(在有符号整数中,最高位为符号位,1 表示负数)
(五)左移运算(<<)左移运算会将二进制位向左移动指定的位数,右边空出的位用 0 填充。
例如,5 << 2 的计算过程如下:
5 的二进制表示为 101
101 << 2 = 10100,即结果为 20
(六)右移运算(>>)右移运算会将二进制位向右移动指定的位数,对于有符号整数,左边空出的位用符号位填充(正数用 0 填充,负数用 1 填充);对于无符号整数,左边空出的位用 0 填充。
例如,5 >> 1 的计算过程如下:
5 的二进制表示为 101
101 >> 1 = 010,即结果为 2
二、位运算的奇技淫巧(一)判断奇偶性利用位运算可以非常高效地判断一个整数的奇偶性。由于奇数的二进制表示的最低位为 1,偶数的二进制表示的最低位为 0,因此可以通过与 1 进行与运算来判断。如果结果为 1,则该数为奇数;如果结果为 0,则该数为偶数。示例代码如下:
def is_odd(n): return n & 1 == 1print(is_odd(5)) # 输出 Trueprint(is_odd(6)) # 输出 False(二)快速乘法和除法通过左移和右移运算,可以实现快速的乘法和除法操作。左移一位相当于乘以 2,右移一位相当于除以 2(这里的除法是整数除法,结果向下取整)。
例如,计算 5 * 4 可以写成 5 <<2,计算 10 / 2 可以写成 10>> 1。示例代码如下:
print(5 << 2) # 输出 20print(10 >> 1) # 输出 5(三)交换两个数的值在不使用临时变量的情况下,可以利用异或运算交换两个数的值。这是因为异或运算具有交换律和结合律,且一个数与自身异或的结果为 0。示例代码如下:
a = 5b = 3a = a ^ bb = a ^ ba = a ^ bprint(a) # 输出 3print(b) # 输出 5(四)计算一个数的绝对值对于有符号整数,可以利用位运算来计算其绝对值。首先获取该数的符号位(通过右移 31 位得到,对于 32 位整数),然后根据符号位来决定是直接返回该数还是返回其相反数。
示例代码如下:
def abs_value(n): sign = n >> 31 return (n ^ sign) - signprint(abs_value(-5)) # 输出 5print(abs_value(5)) # 输出 5(五)统计一个数的二进制表示中 1 的个数可以通过不断将该数与 1 进行与运算,并将结果累加到一个计数器中,然后将该数右移一位,直到该数变为 0。示例代码如下:
def count_ones(n): count = 0 while n: count += n & 1 n >>= 1 return countprint(count_ones(5)) # 输出 2三、位运算在实际场景中的应用(一)图像压缩在位图图像中,每个像素点通常由多个字节表示颜色信息。通过位运算,可以对这些字节进行优化和压缩,减少存储空间。例如,可以将多个像素点的颜色信息进行合并,然后通过位运算在需要时还原出每个像素点的颜色。
(二)加密和解密位运算在加密和解密算法中也有广泛应用。通过对数据进行异或运算、移位运算等操作,可以打乱数据的原有顺序,从而实现加密。在解密时,再通过相反的位运算操作还原数据。
(三)状态标识在程序中,常常需要使用多个标志位来表示不同的状态。通过位运算,可以将这些标志位合并到一个整数中,通过对该整数进行位运算来设置、获取和修改各个标志位的状态。例如,在一个游戏中,可以用一个整数来表示玩家的各种状态,如是否拥有武器、是否处于隐身状态等。
四、总结位运算作为一种强大的编程工具,虽然在日常编程中可能不会经常使用,但在一些特定的场景下,它能够发挥出巨大的优势。通过掌握位运算的奇技淫巧,程序员可以写出更高效、更简洁的代码,解决一些看似棘手的问题。
切记:拿不定正确性的前提下使用位运算,都是在给自己挖坑