C#的常见几种位操作运算,与($)、或(|)、非(~)、异或(^)、左移(<<)、右移(>>)
位操作一般来说比加减乘除计算要快一些
与(&)操作符的位都为1时,才为1,其他都为0,因此与(&)操作符的结果范围在[0, Math.Min(x,y)],x,y均为正整数
或(|)操作符的位都为0时,才为0,其他都为1,因此或(|)操作符的结果范围在[Math.Max(x,y), x+y],x,y均为正整数
非(~)操作符按位取反,1转化为0, 0转化为1,因此非(~)操作符满足[x+~x=-1]一个数与其取反操作之和为-1
异或(^)操作符的位不同时为1, 位相同时为0
左移(<<)操作符:【最左侧位不要,在最右侧补0】,相当于乘以2个N次方,【移位是除以32后的余数,范围[0,31],即以32为一个周期】
右移(>>)操作符:【最右侧位不要,在最左侧补符号位。(正数补0,负数补1)】,相当于除以2个N次方,【移位是除以32后的余数,范围[0,31],即以32为一个周期】
相关测试程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace BitOperationDemo
{
class Program
{
///
/// 标识符字典
///
static readonly Dictionary dict = new Dictionary()
{
{ OperationSymbol.AND,"与(&)"},{ OperationSymbol.OR,"或(|)"},{ OperationSymbol.NOT,"非(~)"},{ OperationSymbol.XOR,"异或(^)"},
{ OperationSymbol.SHIFT_LEFT,"左移(<<)"},{ OperationSymbol.SHIFT_RIGHT,"右移(>>)"}
};
static void Main(string[] args)
{
Console.SetWindowSize(120, 50);
Console.WriteLine($"与(&)操作符的位都为1时,才为1,其他都为0,因此与(&)操作符的结果范围在[0, Math.Min(x,y)],x,y均为正整数");
Console.WriteLine($"或(|)操作符的位都为0时,才为0,其他都为1,因此或(|)操作符的结果范围在[Math.Max(x,y), x+y],x,y均为正整数");
Console.WriteLine($"非(~)操作符按位取反,1转化为0, 0转化为1,因此非(~)操作符满足[x+~x=-1]一个数与其取反操作之和为-1");
Console.WriteLine($"异或(^)操作符的位不同时为1, 位相同时为0");
Console.WriteLine($"左移(<<)操作符:【最左侧位不要,在最右侧补0】,相当于乘以2个N次方,【移位是除以32后的余数,范围[0,31],即以32为一个周期】");
Console.WriteLine($"右移(>>)操作符:【最右侧位不要,在最左侧补符号位。(正数补0,负数补1)】,相当于除以2个N次方,【移位是除以32后的余数,范围[0,31],即以32为一个周期】");
Console.WriteLine();
int x = 12345;
int y = 34567;//34567除以32,余数为7,相当于移动7位
string binaryX = Convert.ToString(x, 2).PadLeft(32, '0');
string binaryY = Convert.ToString(y, 2).PadLeft(32, '0');
Console.WriteLine($"整数【{x}】对应的32位二进制为【{binaryX}】");
Console.WriteLine($"整数【{y}】对应的32位二进制为【{binaryY}】");
Console.WriteLine("-----------------下面分别用二进制字符串逻辑处理 以及 系统内置的操作符进行操作计算-----------------");
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.AND);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.OR);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.NOT);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.XOR);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.SHIFT_LEFT);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.SHIFT_RIGHT);
Console.WriteLine("-----------------下面测试负数进行操作计算-----------------");
x = -12345;
binaryX = Convert.ToString(x, 2).PadLeft(32, '0');
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.AND);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.OR);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.NOT);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.XOR);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.SHIFT_LEFT);
PrintOperatorResult(x, y, binaryX, binaryY, OperationSymbol.SHIFT_RIGHT);
Console.ReadLine();
}
///
/// 打印结果比较
///
///
///
///
///
///
static void PrintOperatorResult(int x, int y, string binaryX, string binaryY, OperationSymbol operationSymbol)
{
string binaryResult = GetOperatorResult(binaryX, binaryY, operationSymbol);
int result = 0;
switch (operationSymbol)
{
case OperationSymbol.AND:
result = x & y;
break;
case OperationSymbol.OR:
result = x | y;
break;
case OperationSymbol.NOT:
result = ~x;
break;
case OperationSymbol.XOR:
result = x ^ y;
break;
case OperationSymbol.SHIFT_LEFT:
result = x << y;
break;
case OperationSymbol.SHIFT_RIGHT:
result = x >> y;
break;
}
Console.WriteLine($"{dict[operationSymbol]}操作符系统内置的操作符运算结果为【{result}】,使用二进制字符串还原后的整数结果为【{Convert.ToInt32(binaryResult, 2)}】");
Console.WriteLine();
}
///
/// 获取操作符的结果
///
/// 32位二进制字符串,第一个数
/// 32位二进制字符串,第二个数
/// 指定的操作符枚举
///
static string GetOperatorResult(string binaryX, string binaryY, OperationSymbol operationSymbol)
{
string result = string.Empty;
switch (operationSymbol)
{
case OperationSymbol.AND:
result = CalculateOperatorResult(binaryX, binaryY, (left, right) => (left == '1' && right == '1') ? "1" : "0");
break;
case OperationSymbol.OR:
result = CalculateOperatorResult(binaryX, binaryY, (left, right) => (left == '0' && right == '0') ? "0" : "1");
break;
case OperationSymbol.NOT:
result = CalculateOperatorResult(binaryX, binaryY, (left, right) => (left == '0') ? "1" : "0");
break;
case OperationSymbol.XOR:
result = CalculateOperatorResult(binaryX, binaryY, (left, right) => (left == right) ? "0" : "1");
break;
case OperationSymbol.SHIFT_LEFT:
result = CalculateShiftResult(binaryX, Convert.ToInt32(binaryY, 2), true);
break;
case OperationSymbol.SHIFT_RIGHT:
result = CalculateShiftResult(binaryX, Convert.ToInt32(binaryY, 2), false);
break;
}
Console.WriteLine($"{dict[operationSymbol]}操作符逻辑运算的32位二进制结果为【{result}】");
return result;
}
///
/// 计算逻辑运算的结果【与,或,非,异或】
///
/// 32位二进制字符串,第一个数
/// 32位二进制字符串,第二个数
/// 逻辑操作委托
///
static string CalculateOperatorResult(string binaryX, string binaryY, Func logicOperator)
{
string result = string.Empty;
for (int i = 0; i < 32; i++)
{
result += logicOperator(binaryX[i], binaryY[i]);
}
return result;
}
///
/// 计算移位操作【左移,右移】
///
///
/// 移动几位,该数需要转化为【除以32的余数】
/// true代表左移,false代表右移
///
static string CalculateShiftResult(string binaryX, int shiftCount, bool leftShift)
{
//比如移动32位,就相当于移动0位,移动33位,就相当于移动1位【32位作为一个周期】
shiftCount = (int)((uint)shiftCount % 32U);//确保余数在0~31之间波动
if (leftShift)
{
//左移:【最左侧位不要,在最右侧补0】
return binaryX.Remove(0, shiftCount).PadRight(32, '0');
}
else
{
//右移:【最右侧位不要,在最左侧补符号位。(正数补0,负数补1)】
return binaryX.Remove(32 - shiftCount, shiftCount).PadLeft(32, binaryX[0]);
}
}
}
///
/// 操作符号,运算符号
///
enum OperationSymbol
{
///
/// 与 【位都是1时结果为1,否则为0】
///
AND = 0,
///
/// 或 【位都是0时结果为0,否则为1】
///
OR = 1,
///
/// 非 【位取反】,非操作只考虑第一个数
///
NOT = 2,
///
/// 异或 【位不同是为1,相同为0】
///
XOR = 3,
///
/// 左移,相当于乘以2个N次方【最左侧位不要,在最右侧补0】
///
SHIFT_LEFT = 4,
///
/// 右移,相当于除以2个N次方【最右侧位不要,在最左侧补符号位。(正数补0,负数补1)】
///
SHIFT_RIGHT = 5
}
}