位运算种类
(1) 逻辑运算(按位操作)
-
与(
&
):对应位均为1
时结果为1
,否则为0
。5 & 3 → 0101 & 0011 = 0001 (十进制1)
-
或(
|
):对应位至少一个为1
时结果为1
。5 | 3 → 0101 | 0011 = 0111 (十进制7)
-
异或(
^
):对应位不同时结果为1
。5 ^ 3 → 0101 ^ 0011 = 0110 (十进制6)
-
取反(
~
):所有位翻转(0
变1
,1
变0
)。~5 → ~0101 = 1010(假设4位,十进制-6,补码表示)
(2) 移位运算
-
左移(
<<
):所有位向左移动,低位补0
。5 << 1 → 0101 << 1 = 1010 (十进制10,相当于乘2)
-
右移(
>>
):所有位向右移动,高位补符号位(算术右移)或补0
(逻辑右移)。-5 >> 1 → 11111011 >> 1 = 11111101(算术右移,结果仍为负数)
左移都是等价于逻辑左移
对于有符号数来说,右移默认是算术右移。
#include <iostream>
using namespace std;
int main() {
// 无符号数:逻辑右移
unsigned int a = 0b10000000; // 128
cout << (a >> 2) << endl; // 结果 32 (0b00100000)
// 有符号数:通常是算术右移
int b = -8; // 二进制补码:111...1111000
cout << (b >> 1) << endl; // 结果 -4 (111...1111100)
// 强制逻辑右移(通过转为无符号)
cout << ((unsigned)b >> 1) << endl; // 结果 2147483644 (0b011...1111100)
return 0;
}
表格版
位运算所有符号表示及英文缩写
运算名称 | 符号 | 英文全称 | 缩写 | 示例 | 说明 | ||
---|---|---|---|---|---|---|---|
按位与(AND) | & |
Bitwise AND | AND | a & b |
对应位均为 1 时结果为 1 | ||
按位或(OR) | ` | ` | Bitwise OR | OR | `a | b` | 对应位至少一个为 1 时结果为 1 |
按位异或(XOR) | ^ |
Bitwise XOR | XOR | a ^ b |
对应位不同时结果为 1 | ||
按位取反(NOT) | ~ |
Bitwise NOT | NOT | ~a |
所有位取反(0→1,1→0) | ||
左移(Shift Left) | << |
Left Shift | SHL | a << n |
左移 n 位,低位补 0 | ||
算术右移 | >> |
Arithmetic Right Shift | SAR | a >> n |
右移 n 位,高位补符号位(带符号) | ||
逻辑右移 | >>> |
Logical Right Shift | SHR | a >>> n |
右移 n 位,高位补 0(无符号) | ||
循环左移 | 无 | Rotate Left | ROL | 无标准符号 | 左移时溢出的位补到低位 | ||
循环右移 | 无 | Rotate Right | ROR | 无标准符号 | 右移时溢出的位补到高位 |
说明:
-
循环移位(ROL/ROR) 在部分 CPU 指令或语言库中有提供,但无统一符号,通常用函数实现(如
_rotl
、_rotr
)。 -
逻辑右移(
>>>
) 仅在某些语言(如 Java、JavaScript)中支持,C/C++ 无此运算符。 -
算术右移(
>>
) 在 C/C++ 等语言中对有符号整数生效,保持符号位不变。
取反、补码运算
int a = 5; // 原码:00000101,补码:00000101
int b = ~a; // 按位取反:11111010(补码)
int c = -3; // 原码:10000011,补码:11111101
int d = ~c; // 按位取反:00000010(补码)
int x = 6; // 补码:00000110
int y = -x; // 取负:11111010(补码)
int z = -4; // 补码:11111100
int w = -z; // 取负:00000100(补码)
位运算的好用技巧
位运算的核心本质就是直接利用二进制的特性进行操作!
判断奇偶
在二进制中,如果是奇数最后一位一定是1
if ((n & 1) == 0) {
cout << "偶数" << endl;
} else {
cout << "奇数" << endl;
}
清除最低位的1
n&(n-1);
建立清除最低位的1,延申出的功能
计算一个数的二进制中1的数量
int bitCount(int n)
{
int count=0;
while(n>0)
{
n&=(n-1);
count++;
}
return count;
}
检查是否是2的幂
if(n>0&&(n&(n-1)==0))
{
就是2的倍数了
}
是不是4的幂
[4的幂]https://leetcode.cn/problems/power-of-four/description/
bool isPowerOfFour(int n)
{ return n > 0 && (n & (n - 1)) == 0 && (n & 0xaaaaaaaa) == 0; }
bool isPowerOfFour(int n) {
return n > 0 && (n & (n - 1)) == 0 && n % 3 == 1;
}
快速判断符号是否相同
bool func(int a,int b)
{
if((a^b)>=0)
{return true;}
else
{return false;}
}
提取最右侧的1
int rightmost_one = n & -n;
快速乘/除2的幂
n<<1;//n*2
n>>1;//n/2
掩码操作
// 获取低4位
int low_4_bits = n & 0xF;
// 设置第3位为1
n |= (1 << 2);
// 清除第5位为0
n &= ~(1 << 4);
循环移位(32位整数)
// 左移k位
n = (n << k) | (n >> (32 - k));
// 右移k位
n = (n >> k) | (n << (32 - k));
向上取整到最近的2的幂
unsigned int next_power_of_two(unsigned int n) {
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
}
取绝对值 (不实用)
等价于std::abs
在计算机中存储的是补码(对于正数来说,原码补码反码是一样的)
//如果是负数,要记得n是补码 mask=11...1,打印的话显示mask=-1
int mask=n>>31; //符号掩码(负数全1,正数全0) 因为遵守算术运算
//对于正数无影响 mask就是全0
int abs_n=(n^mask)-mask;//等价于(n+mask)^mask
对于计算机的负数取绝对值运算来说,
使用逐位检查一个具体的int变量需要多少个二进制位表示
应用前提:变量是大于0的数(正数)
交换两个数(不推荐使用,当两个数的地址是一个的时候会出错,这个更推荐使用std::swap())
a ^= b;
b ^= a;
a ^= b;