位运算符
运算符号 |
位逻辑运算 |
格式 |
~ |
非运算 |
~a |
& |
与运算 |
a & b |
| |
或运算 |
a | b |
^ |
异或运算 |
a ^ b |
<< |
左移运算 |
a<<num num:移动位数 |
>> |
右移运算 |
a>>num |
非运算:~
运算规则:将0换成1,将1换成0
与运算:&
运算规则:1&0 = 0;1&1 = 1;0&0=0
算式 |
解析 |
结果 |
1&2 |
0001 & 0010 = 0000 |
0 |
5&6 |
0101 & 0110 = 0100 |
4 |
13&14 |
1101 & 1110 = 1100 |
12 |
或运算:|
运算规则:1|0 = 1;1|1 = 1;0|0=0
算式 |
解析 |
结果 |
1|2 |
0001 | 0010 = 0011 |
3 |
5|6 |
0101 | 0110 = 0111 |
7 |
13|14 |
1101 | 1110 = 1111 |
15 |
异或运算:^
运算规则:1^0 = 1;1^1 = 0;0^0=0 相同得0,相异得1
算式 |
解析 |
结果 |
1^2 |
0001 ^ 0010 = 0011 |
3 |
5^6 |
0101 ^ 0110 = 0011 |
3 |
13^14 |
1101 ^ 1110 = 0011 |
3 |
左移运算:<<
运算规则:左移相当于乘. 左移一位相当于乘2;左移两位相当于乘4;左移三位相当于乘8。左移n位相当于乘以2的n次幂
x<<1= x*2
x<<2= x*4
x<<3= x*8
x<<4= x*16
例子:3<<3
算式 |
解析 |
结果 |
3<<3 |
00011 -> 11000 相当于 3乘以2的3次幂 |
24 |
右移运算:>>
运算规则:右移相当于整除. 右移一位相当于除以2;右移两位相当于除以4;右移三位相当于除以8。
右移n位相当于整除2的n次幂
x>>1= x/2
x>>2= x/4
x>>3= x/8
x>>4=x/16
算式 |
解析 |
结果 |
3>>1 |
0011 -> 0001 |
1 |
16>>2 |
10000 -> 00100 |
4 |
应用
判断奇偶数
(x&1) == 0 true:偶数 false:奇数
用来替换使用取模运算来判断奇偶数(x%2 == 0)
使用位运算的实现会比使用取模运算的实现要快
实现和2的n次幂的乘除法
和2的n次幂的乘法
算术运算实现,速度较慢
public int Logic(int num,int count)
{
return num * (int)Math.Pow(2, count);
}
位运算实现,速度快
public int Logic(int num,int count)
{
return num<<count;
}
和2的n次幂的整除
算术运算实现,速度较慢
public int Logic(int num,int count)
{
return num / (int)Math.Pow(2, count);
}
位运算实现,速度快
public int Logic(int num,int count)
{
return num>>count;
}
交换两个整数
普通实现:借助临时变量实现
int a = 1;
int b = 2;
int temp = a;
a = b;
b = temp;
位运算实现,不占用内存
int a = 1;
int b = 2;
a ^= b;
b ^= a;
a ^= b;
状态标志管理
1、开发中有时需要处理一个对象多个状态的情况,相关操作包括移除位标志、添加位标志、检查位标志。
2、与普通实现方法相比(使用多个bool字段进行状态管理),使用位运算进行状态管理的优点有:节省内存、性能更好、更高效的网络传输。
3、枚举值必须是 2 的幂次方(即 1, 2, 4, 8, 16...
),以便按位运算正确工作:
整数状态标志管理
int None = 0; // 0000
int Read = 1; // 0001
int Write = 2; // 0010
int Execute = 4; // 0100
int Delete = 8; // 1000
int status = 0;
//添加位标志
status |= Read;
Debug.LogError(status);
status |= Write;
Debug.LogError(status);
status |= Execute;
Debug.LogError(status);
Debug.Log("---------------");
//检查标志位
Debug.LogError( (status&Read) == Read);
Debug.LogError( (status&Write) == Write);
Debug.LogError( (status&Execute) == Execute);
Debug.LogError( (status&Delete) == Delete);
Debug.Log("---------------");
//移除标志位
status &= ~Execute;
Debug.LogError( (status&Read) == Read);
Debug.LogError( (status&Write) == Write);
Debug.LogError( (status&Execute) == Execute);
Debug.LogError( (status&Delete) == Delete);
枚举状态标志管理
public enum Stauts
{
None = 0, // 0000
Read = 1, // 0001
Write = 2, // 0010
Execute = 4, // 0100
Delete = 8 // 1000
}
var flag = Stauts.None;
//添加位标志
flag |= Stauts.Read;
Debug.LogError(flag);
flag |= Stauts.Write;
Debug.LogError(flag);
flag |= Stauts.Execute;
Debug.LogError(flag);
Debug.Log("---------------");
//检查标志位
Debug.LogError( flag.HasFlag(Stauts.Read));
Debug.LogError( flag.HasFlag(Stauts.Write));
Debug.LogError( flag.HasFlag(Stauts.Execute));
Debug.LogError( flag.HasFlag(Stauts.Delete));
Debug.Log("---------------");
//移除标志位
flag &= ~Stauts.Execute;
Debug.LogError( flag.HasFlag(Stauts.Read));
Debug.LogError( flag.HasFlag(Stauts.Write));
Debug.LogError( flag.HasFlag(Stauts.Execute));
Debug.LogError( flag.HasFlag(Stauts.Delete));
优缺点
位运算是直接对整数在二进制位级别进行操作的低级运算,在C#中合理使用可以带来显著优势,但也存在一些限制。
优点:
1、极高的性能
2、节省内存
缺点:
1、可读性较低
2、不好维护,调试困难
3、类型限制:仅适用整数类型,不能用于float、double、decimal等
建议
1、在使用位运算的代码处添加详细注释
2、将复杂操作逻辑进行封装
3、普通业务逻辑优先选择可读性更好的写法
位运算如同C#中的"机械级工具",能显著提升性能,但滥用会增加代码维护成本。建议在性能分析确认瓶颈后再使用,并做好充分的文档说明。