— Привіт, Аміго!
Ще хотів би розповісти про бітові маски та 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; //2 5 == 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?
Код | Опис |
---|---|
|
Як встановити в 1 біт 6? |
|
Як встановити 0 біт 6? |
|
Як отримати значення 6-го біта? |
— Дуже незвично, але не складно. Я тепер уже крутий програміст.
— І тепер ще маленька підказка. Як легко отримати числа зі знятим або встановленим певним бітом: 01000000 або 10111111.
Для цього у нас є операції зсуву >> і <<.
Ось 1 – це 2 у нульовому ступені. Тобто. число із встановленим нульовим бітом. Нам треба число із встановленим 6-м бітом.
int c = 1<<6 ; //0000 0001 <<6 == 0100 0000 == 64
< /pre>— Круто! Насправді корисна річ для таких справ.
А якщо мені потрібне число, де всі біти 1, а один певний – 0?
— Це теж не складно:
int d = ~(1<<6)< /span>; //~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)», знатимеш, що це хтось просто працює з бітовою маскою. А якщо часто зустрічатимеш, то незабаром усе саме запам'ятається.
— Саме запам'ятається… Добре звучить. Дякую за лекцію.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ