— Привет, Амиго!

Еще хотел бы рассказать про битовые маски и XOR.

Ты уже знаешь, что числа состоят из битов и над этими битами можно производить различные операции. Битовая маска – это когда мы храним много различных логических значений (true/false) в виде одного целого числа. При этом каждому boolean-значению соответствует определенный бит. Вот как это можно делать:

Числа-степени двойки (1,2,4,8,16,32,…) занимают в двоичном представлении числа всего по одному биту:

Число Двоичное представление
1 0000 0001
2 0000 0010
4 0000 0100
8 0000 1000
16 0001 0000
19 (не степень двойки) 0001 0011
31 (не степень двойки) 0001 1111

Поэтому любое целое число можно рассматривать, как массив бит или массив boolean.

Вот как можно хранить различные логические значения в одном числе:

Значения логических переменных
boolean a = true;
boolean b = false;
boolean c = true;
boolean d = false;
Упаковка их в одно число:
int result = 0;
 if (a) result += 1; //1 == 20 — нулевой бит
 if (b) result += 2; //2 == 21 — первый бит
 if (c) result += 4; //4 == 22 — второй бит
 if (d) result += 8; //8 == 23 — третий бит

Теперь каждый бит равен 1, если соответствующая ему логическая переменная была true.

В нашем случае true были переменные a и c, значит число result равно 1+4 ==5

0000 0101
0000 dcba

— Вроде понятно, что происходит.

— Ну, раз понятно, то пошли дальше.

В числе int 32 бита, один из них используется для знака, а еще 31 можно использовать для хранения значений 31-й булевской переменной.

— А в числе long 64 бита. Мы там можем хранить 63 логических переменных.

— Ага.

— Полсотни переменных в одном числе. Немало.

А где такое применяется?

— В основном там, где надо компактно хранить много информации об объектах. Когда хранишь много информации об объекте, всегда наберется пара десятков логических переменных. Вот их всех удобно хранить в одном числе.

Именно хранить. Т.к. пользоваться им в работе не так уж удобно.

— Кстати, как раз хотел спросить. А как нам обратно получить логические значение их числа?

— Это совсем не сложно. Вот допустим тебе нужно узнать, установлен ли 5-й бит числа в единицу или нет (2 в пятой степени – это 32). Вот как это можно проверить:

Соединяем числа в одно:
int a = 32; //25 == 0010 0000
int b = 8; //23 == 0000 1000
int c = 2; //21 == 0000 0010

int result = a+b+c; //32+8+2 == 42 == 0010 1010
Восстанавливаем обратное значение – проверяем установлен ли определенный бит:
int a = result & 32; // 0010 1010 & 0010 0000 = 0010 0000
int b = result & 8; // 0010 1010 & 0000 1000 = 0000 1000
int c = result & 2; // 0010 1010 & 0000 0010 = 0000 0010

Т.е. фактически, для работы с битовыми масками нужны три операции:

1) Установить определенный бит в 0

2) Установить определенный бит в 1

3) Проверить, какое значение определенного бита.

Возьмем, например, бит номер 6.

Как установить в 1 бит 6?

Код Описание
result = result | 01000000;
result |= 01000000;
Как установить в 1 бит 6?
result = result & 10111111;
result &= 10111111;
Как установить в 0 бит 6?
с = result & 01000000;
Как получить значение 6-го бита?

— Очень необычно, но не сложно. Я ж теперь уже крутой программист.

— И теперь еще маленькая подсказка. Как легко получить числа со снятым или установленным определенным битом: 01000000 или 10111111.

Для этого у нас есть операции сдвига >> и <<.

Вот 1 – это 2 в нулевой степени. Т.е. число с установленным нулевым битом. Нам надо число с установленным 6-м битом.

int c = 1<<6; //0000 0001 <<6 == 0100 0000 == 64

— Круто! Действительно полезная вещь для таких дел.

А если мне нужно число, где все биты 1, а один определенный – 0?

— Это тоже не сложно:

int d = ~(1<<6); //~0100 0000 == 10111111

Т.е. все очень просто:

Код Описание
result = result | (1<<6);
result |= (1<<6);
Как установить в 1 бит 6?
result = result & ~(1<<6);
result &= ~(1<<6);
Как установить в 0 бит 6?
с = result & (1<<6);
Как получить значение 6-го бита?

— Выглядит не очень сложно. Но так сразу — не запомню.

— Зато, если встретишь где-то в чужом коде такое страшное выражение:

«result &= ~(1<<6)», будешь знать, что это кто-то просто работает с битовой маской. А если часто будешь встречать, то вскоре все само запомнится.

— Само запомнится… Хорошо звучит. Спасибо за лекцию.