位运算是直接对二进制数字的位级别进行操作的运算方式,不依赖数字的整体十进制值。
numpy 提供了一套高效的位运算工具,支持对数组元素进行矢量化逐位操作,性能远超 python 原生位运算(尤其处理大规模数据时),广泛应用于底层数据优化、状态标志处理、数据压缩等场景。
一、核心概念与优势
- 位运算本质:操作二进制数的每一位(0 或 1),遵循布尔逻辑或移位规则。
numpy 优势:
- 矢量化处理:直接作用于数组整体,无需循环遍历元素。
- 多类型支持:兼容整数、布尔值等多种数据类型。
- 性能优化:基于 c 语言实现,运算速度快。
numpy 位运算函数均以 bitwise_ 开头,同时支持与 python 原生位运算符对应的简写形式。
二、numpy 位运算核心函数与运算符总览
下表完整梳理了 numpy 中所有位运算的函数、对应运算符及核心功能:
| 操作类型 | numpy 函数 | 对应运算符 | 核心描述 |
| 按位与 | numpy.bitwise_and(x1, x2) | & | 两数对应位均为 1 时结果为 1,否则为 0 |
| 按位或 | numpy.bitwise_or(x1, x2) | | | 两数对应位有一个为 1 时结果为 1,否则为 0 |
| 按位异或 | numpy.bitwise_xor(x1, x2) | ^ | 两数对应位不同时结果为 1,相同时为 0 |
| 按位取反 | numpy.invert(x) | ~ | 对数字每一位取反(0→1,1→0),有符号数需考虑补码规则 |
| 左移 | numpy.left_shift(x1, x2) | << | 将 x1 的二进制位向左移 x2 位,右侧补 0 |
| 右移 | numpy.right_shift(x1, x2) | >> | 将 x1 的二进制位向右移 x2 位,左侧根据符号位补 0 或 1(正数补 0) |
三、各运算详细用法与实例
1. 按位与(bitwise_and / &)
运算规则
两数对应二进制位均为 1 时结果为 1,否则为 0。规则表如下:
| a | b | and 结果 |
| 1 | 1 | 1 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 0 | 0 | 0 |
实例:整数与数组运算
import numpy as np
# 单个整数运算
a, b = 13, 17
print(f"13 的二进制:{bin(a)},17 的二进制:{bin(b)}") # 0b1101 0b10001
print("按位与结果:", np.bitwise_and(a, b)) # 等价于 13 & 17,输出 1
# 数组运算(矢量化)
arr1 = np.array([13, 25], dtype=int)
arr2 = np.array([17, 10], dtype=int)
print("数组按位与:", arr1 & arr2) # 输出 [1 8]运算过程解析(13 & 17)
对齐二进制位后逐位计算:
01101 (13)
& 10001 (17)
= 00001 (1)
2. 按位或(bitwise_or / |)
运算规则
两数对应二进制位有一个为 1 时结果为 1,否则为 0。规则表如下:
| a | b | or 结果 |
| 1 | 1 | 1 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |
实例:整数运算
import numpy as np
a, b = 13, 17
print(f"13 的二进制:{bin(a)},17 的二进制:{bin(b)}") # 0b1101 0b10001
print("按位或结果:", np.bitwise_or(a, b)) # 等价于 13 | 17,输出 29运算过程解析(13 | 17)
01101 (13)
| 10001 (17)
= 11101 (29)
3. 按位异或(bitwise_xor / ^)
运算规则
两数对应二进制位不同时结果为 1,相同时为 0。
实例:布尔数组运算
异或在布尔值上等价于 “逻辑异或”(true 为 1,false 为 0):
import numpy as np
arr1 = np.array([true, false, true], dtype=bool)
arr2 = np.array([false, true, false], dtype=bool)
# 函数与运算符等价
result1 = np.bitwise_xor(arr1, arr2)
result2 = arr1 ^ arr2
print("异或结果:", result1) # 输出 [ true true true]
print("结果一致:", np.array_equal(result1, result2)) # 输出 true4. 按位取反(invert / ~)
关键说明
- 对无符号整数(如
uint8):直接逐位取反(0→1,1→0)。 - 对有符号整数(如
int8):遵循二进制补码规则:取反后 +1,且最高位为符号位(0 正,1 负)。
实例 1:无符号整数取反
import numpy as np
# uint8 类型(0-255,8位二进制)
x = np.array([13], dtype=np.uint8)
x_invert = np.invert(x)
print(f"13 的 8 位二进制:{np.binary_repr(13, width=8)}") # 00001101
print(f"取反后的值:{x_invert[0]}") # 242
print(f"242 的 8 位二进制:{np.binary_repr(242, width=8)}") # 11110010实例 2:有符号整数取反
import numpy as np
x = 5 # 默认 int 类型(32位)
x_invert = ~x
print(f"5 的二进制(简化):00000101")
print(f"~5 的二进制(补码):11111010")
print(f"~5 的十进制:{x_invert}") # 输出 -6补码计算步骤(以~1 为例)
- 原码:1 →
00000001(8 位有符号); - 逐位取反:
11111110(符号位为 1,代表负数); - 求补码(除符号位外取反 +1):
10000001+ 1 =10000010; - 转换为十进制:-2。
5. 左移(left_shift / <<)
运算规则
将数字的二进制位向左移动指定位数,右侧用 0 填充。等价于乘以 2 的 n 次方(n 为移位数)。
实例
import numpy as np
x = 10 # 二进制:00001010
shifted = np.left_shift(x, 2) # 等价于 10 << 2
print(f"10 左移 2 位结果:{shifted}") # 输出 40
print(f"40 的二进制:{np.binary_repr(40, width=8)}") # 00101000原理
10 << 2 即二进制 00001010 左移 2 位 → 00101000(40),对应数学运算 10 × 2² = 40。
6. 右移(right_shift / >>)
运算规则
将数字的二进制位向右移动指定位数,左侧根据符号位补 0(正数)或 1(负数)。等价于整除 2 的 n 次方(n 为移位数)。
实例
import numpy as np
x = 40 # 二进制:00101000
shifted = np.right_shift(x, 2) # 等价于 40 >> 2
print(f"40 右移 2 位结果:{shifted}") # 输出 10
print(f"10 的二进制:{np.binary_repr(10, width=8)}") # 00001010原理
40 >> 2 即二进制 00101000 右移 2 位 → 00001010(10),对应数学运算 40 ÷ 2² = 10。
四、运算符使用注意事项
- 优先级问题:位运算符优先级低于算术运算符,计算时建议加括号。例:
10 & 1 + 2等价于10 & 3(结果 2),而非(10 & 1) + 2(结果 2)。 - 数组兼容性:参与运算的数组需满足 numpy 的 “广播规则”(如形状一致或可广播)。
- 数据类型影响:取反运算的结果受数组
dtype影响(无符号 vs 有符号),需明确指定类型避免歧义。
五、典型应用场景
- 底层数据处理:操作二进制文件(如图片、音频)的字节数据。
- 状态标志位控制:用单个整数的不同位表示多个状态(如用
0b101表示 3 个状态的组合)。 - 性能优化:替代乘法 / 除法(左移 / 右移速度更快)。
- 加密与校验:基于异或等运算实现简单的数据加密或校验(如 crc 校验)。
六、总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论