"Cześć, Amigo!"
„Chciałbym też porozmawiać o maskach bitowych i XOR”.
„Wiesz już, że liczby składają się z bitów i możesz wykonywać na nich różne operacje. Maska bitowa to reprezentacja kilku różnych wartości logicznych (wartości prawda/fałsz) jako pojedyncza liczba całkowita. W tym przypadku każda wartość logiczna odpowiada określony bit. Oto jak można to zrobić:
„Dwójkowa reprezentacja potęg dwójki (1, 2, 4, 8, 16, 32,…) wymaga ustawienia tylko jednego bitu:”
Numer | Reprezentacja binarna |
---|---|
1 | 0000 0001 |
2 | 0000 0010 |
4 | 0000 0100 |
8 | 0000 1000 |
16 | 0001 0000 |
19 (nie potęga dwójki) | 0001 0011 |
31 (nie potęga dwójki) | 0001 1111 |
„Tak więc każdą liczbę całkowitą można traktować jako tablicę bitów lub tablicę wartości logicznych”.
„Oto, jak możesz przechowywać różne wartości logiczne w jednej liczbie:”
boolean a = true;
boolean b = false;
boolean c = true;
boolean d = false;
int result = 0;
if (a) result += 1; // 1 == 20 — bit 0
if (b) result += 2; // 2 == 21 — bit 1
if (c) result += 4; // 4 == 22 — bit 2
if (d) result += 8; // 8 == 23 — bit 3
„Teraz każdy bit ma wartość 1, jeśli odpowiadająca mu zmienna boolowska była prawdziwa”.
W naszym przypadku zmienne a i c były prawdziwe, więc wynik jest równy 1+4 == 5
0000 0101
0000 dcba
– Chyba wiem, co się dzieje.
- Cóż, jeśli rozumiesz, przejdźmy dalej.
„Int ma 32 bity. Jeden z nich jest używany jako znak liczby, a pozostałe 31 może służyć do przechowywania wartości 31 zmiennych boolowskich”.
„Long ma 64 bity, w których możemy przechowywać 63 zmienne boolowskie”.
"Tak."
„Dziesiątki zmiennych upchniętych w jedną liczbę. To całkiem sporo”.
„Ale gdzie to się stosuje?”
„Głównie w sytuacjach, w których trzeba przechowywać wiele informacji o obiektach. Kiedy przechowuje się wiele informacji o obiekcie, zawsze istnieje kilkadziesiąt zmiennych boolowskich. „Dzięki temu podejściu wszystkie są wygodnie przechowywane w jednej liczbie ”.
„Z naciskiem na słowo „przechowywane”. Ponieważ w rzeczywistości używanie numeru nie jest takie wygodne”.
„Nawiasem mówiąc, właśnie o to chciałem zapytać. Jak wyodrębnić wartość logiczną z liczby?”
„To wcale nie jest skomplikowane. Powiedzmy, że musisz ustalić, czy bit 6 jest ustawiony na 1 (2 do potęgi piątej to 32). Możemy to sprawdzić w ten sposób:”
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
„Tak więc praca z maskami bitowymi obejmuje trzy operacje:”
1) Ustaw określony bit na 0
2) Ustaw określony bit na 1
3) Sprawdź wartość określonego bitu.
„Weź na przykład bit 6”.
„Jak ustawić bit 6 na 1?”
Kod | Opis |
---|---|
|
Jak ustawić bit 6 na 1? |
|
Jak ustawić bit 6 na 0? |
|
Jak uzyskać wartość bitu 6? |
„To bardzo niezwykłe, ale nie trudne. Człowieku, teraz jestem zapalonym programistą”.
„I jeszcze jedna mała wskazówka, jak łatwo uzyskać liczby z określonym bitem ustawionym na 0 lub 1: 01000000 lub 10111111”.
W tym celu mamy operatory >> i << .
„1 to 2 do potęgi zerowej. Innymi słowy, liczba z bitem 0 ustawionym na 1. Potrzebujemy liczby z bitem 6 ustawionym”.
int c = 1 << 6; // 0000 0001 << 6 == 0100 0000 == 64
„Świetnie! To naprawdę pomaga w takich przypadkach”.
„Ale co, jeśli potrzebuję liczby, w której każdy bit jest ustawiony na 1, z wyjątkiem jednego konkretnego bitu ustawionego na 0?”
"To też nie jest trudne:"
int d = ~(1 << 6); // ~0100 0000 == 10111111
„Innymi słowy, wszystko jest bardzo proste:”
Kod | Opis |
---|---|
|
Jak ustawić bit 6 na 1? |
|
Jak ustawić bit 6 na 0? |
|
Jak uzyskać wartość bitu 6? |
„To nie wygląda na bardzo trudne. Ale nie zapamiętam tego od razu”.
„Ale jeśli napotkasz przerażające wyrażenie, takie jak„ wynik &= ~(1 << 6) ”w czyimś kodzie, będziesz wiedział, że ten ktoś po prostu pracuje z maską bitową”.
„A jeśli często się z nim spotykasz, zapamięta się za ciebie”.
„Pamiętaj o sobie… To brzmi dobrze. Dziękuję za lekcję”.