Битовые операции – это операции которые выполняются над отдельно взятыми двоичными битами в числах. В битовых или поразрядных операциях, числа рассматриваются как последовательность нулей и единиц двоичной системы счисления.
Разрядные операции делятся на:
- логические;
- операции смещения;
Побитовые операторы можно применять ко всем целочисленным типам данных.
Логические операции
Побитовое отрицание или инверсия ~
“~” – унарный оператор, который инвертирует все биты аргумента. Все разряды с нулей переходят в единицы, а единицы в нули.
byte x = 0b00001111;
var y = (byte)~x; // 11110000
Побитовое сложение |
Логическое сложение(дизъюнкция) – бинарная операция выполняется над двоичными разрядами числа, если один из битов, которые суммируются, равен единице, то результатом будет единица, в противном случае ноль.
int a = 0b00011010;
int b = 0b00110001;
var c = a | b; //00111011
Побитовое умножение &
Логическое умножение(конъюнкция) – бинарная операция, во время которой перемножаются отдельно взятые биты числа.
int d = 0b00011010;
int e = 0b00110111;
var f = d & e; //00010010
Исключительная дизъюнкция ^
Логическое сложение по модулю (eXclusive OR) – бинарная операция, при которой результирующий бит принимает значение 1 только в случае, когда только один из слагаемых разрядов равен единице.
int g = 0b00010011;
int h = 0b00110101;
var k = g ^ h; //00100110
Операции смещения
Операции смещения – предназначены для смещения битового представления числа влево или вправо.
Оператор смещения влево <<
Бинарный оператор, который используется для смещения разрядов двоичного числа на N позиций влево, количество позиций передается в качестве второго операнда.
long num1 = 0b00001110;
long num2 = num1 << 3; 0b01110000;
Оператор смещения вправо >>
Бинарный оператор, который используется для смещения битов двоичного числа на N позиций вправо, количество позиций на которые нужно сместить число,передаются как второй операнд.
long num3 = 0b00001100;
long num4 = num3 >> 2; 0b00000011;
Использование поразрядных операций
Битовые флаги
Логические операции позволяют читать и записывать значения отдельно взятого бита числа. Это в свою очередь расширяет возможности хранения данных, поскольку отдельный бит числа может выполнять роль флажка.
Рассмотрим код программы для работы с битовыми флагами:
using System;
class Program
{
private static int GetFlag(int data, int position)
{
//битовая маска
var mask = 0b00000001;
//смещение на позицию указанную как аргумент метода
data = data >> position;
//возвращаем значение флажка на заданной позиции
return data & mask;
}
private static int SetFlag(int data, int bitValue, int position)
{
var mask = 0b00000001;
//смещаем на указанное количество бит
mask = mask << position;
if (bitValue == 1)
{
//выставляем в бит с индексом position значение 1
return data | mask;
}
else
{
//для сброса бита в ноль, сначала инвертируем маску
return data & ~mask;
}
}
static void Main(string[] args)
{
int flagSet = 0b10101010; //начальное значение
flagSet = SetFlag(flagSet, 1, 4); //10111010
flagSet = SetFlag(flagSet, 0, 5); //10011010
Console.WriteLine(Convert.ToString(flagSet, 2));
var flag = GetFlag(flagSet, 7);
Console.WriteLine("Flag value : {0}", flag);
Console.ReadLine();
}
}
Быстрое умножение и деление на степень двойки
С помощью операторов смещения, можно быстро находить результат умножения и деления на 2N(2, 4, 8, 16…).
using System;
class Program
{
private static int MultTo2N(int num, int n)
{
return num << n;
}
private static int DivTo2N(int num, int n)
{
return num >> n;
}
static void Main(string[] args)
{
Console.WriteLine("5 * 16 = {0}", MultTo2N(5, 4)); // в метод передаем степень двойки (16 = 2 в 4-й)
Console.WriteLine("64 / 8 = {0}", DivTo2N(64, 3)); // 8 = 2 в 3-й
Console.ReadLine();
}
}
XOR шифрование данных
На базе логического оператора XOR, можно реализовать простое шифрование данных:
int key = 0xACACAC; //ключ шифрования нужно выбирать большим за данные которые шифруются
int password = 123456789; //важные данные которые необходимо зашифровать
int encryptedPass = password ^ key;
Console.WriteLine("Зашифрованный пароль: {0}", encryptedPass);
int decryptedPass = encryptedPass ^ key;
Console.WriteLine("Расшифрованный пароль: {0}", decryptedPass);