Operatory bitowe

Na początku chciałem zaznaczyć, że operatory bitowe są bardzo specyficzne jeśli chodzi o działanie. Stosuje się je do bardziej skomplikowanych czynności. Tak więc na początku na pewno nie będziesz ich potrzebował. Po za tym operują one wartościach w postaci bitowej. Tak więc jeśli nie znasz systemu dwójkowego to.. Nie, nie przerywaj czytania. Skocz sobie do działu systemy liczbowe i wróć, gdy skończysz. Jak już wiesz komputerom najlepiej pracuje się na liczbach w systemie 16-wym lub 2-wym Aby zrozumieć operatory bitowe trzeba znać nieco system 2-wy. Skoro tutaj doszedłeś to zakładam, iż posiadasz pewną wiedzę na ten temat. Jeśli nie, to raz jeszcze odsyłam na inną stronę. Link znajduje się nieco wyżej. Tabelka z zestawionymi operatorami bitowymi:

nazwa skrót symbol
suma bitowa OR |
iloczyn bitowy AND &
różnica bitowa XOR ^
negacja bitowa NOT !
przesunięcie bitowe w lewo <<
przesunięcie bitowe w prawo >>

Ponieważ część tych operatorów jest zbliżonych do siebie działaniem, zatem omówię je na jednym przykładzie. Użyjemy dwóch liczb: 34 i 23.

dec bin
34 00100010
23 00010111

operator |
czyli suma bitowa lub bitowe OR. Działanie jest zasadniczo proste. Tutaj najlepiej jest wyjść od przykładu:

dec bin
34 00100010
23 00010111
34 | 23 00110111

Bitowe OR sprowadza się do prostej czynności sprawdzenia układu zer i jedynek w liczbach poddawanych operacji. Każde wystąpienie jedynki zarówno w pierwszej, jak i w drugiej liczbie oznacza jedynkę. Widzisz tutaj zbliżone działanie do operatora sumy logicznej. Oczywiście! Tutaj też jest ta sama taktyka. Przynajmniej jedno z dwóch musi być prawdą [jedynka].

operator &
czyli iloczyn bitowy lub bitowe AND. Działa on analogicznie, jak iloczyn logiczny. Mały przykład powinien wystarczyć:

dec bin
34 00100010
23 00010111
34 & 23 00000010

Tuaj jest identycznie, jak w przypadku iloczynu logicznego. Aby umieścić jedynkę w wartości wynikowej w obu wartościach poddawanych operacji muszą być też jedynki. Wszystko najlepiej widać na przykładzie powyżej

operator ^
czyli symetryczna różnica bitowa lub po prostu bitowe XOR. Ten operator nie ma swojego odpowiednika wśród operatorów logicznych, więc nie będzie żadnej analogii 🙁 Zasada działania jest nadal taka sama, czyli dokonanie pewnych modyfikacji na bitach. Zaczynamy jak zwykle od przykładu:

dec bin
34 00100010
23 00010111
34 ^ 23 00110101

W zasadzie nie trzeba tutaj nic objaśniać, ale.. powiem krótko. Wszędzie tam, gdzie występują takie same znaki piszemy zero. W miejscach, gdzie są różne jedynkę. To tyle. Popatrz sobie na przykład i przeanalizuj go.

operator !
czyli negacja bitowa lub bitowe NOT. Jeśli zrozumiałeś działanie logicznego operatora negacji to właściwie te słowa są zbędne. No ale jak już zacząłem..

dec bin
34 00100010
!34 11011101

Cóż mogę powiedzieć. Chyba tylko tyle, że jego działanie polega na zamianie bitów. Warto też zapamiętać, iż ten operator jest jednoargumentowy, w wyniku czego powyżej nie ma już liczby 23.

operator <<
służy do przesuwania bitów w lewo. Początkowo może się to wydać nieco dziwne, a nawet zbędne. Zaręczam jednak, że tak nie jest. Przesunięcia bitowe są bardzo przydatne. Czasem mogą zostać użyte zamiast mnożenia, które jest bardzo powolne w stosunku do przesunięć. Weźmy liczbę 11, która w systemie binarnym ma postać: 00001011.

Oczywiście same jedynki w przykładzie to czysty przypadek. Zapis 11 << 1 znaczy tyle co: W liczbie 11 zapisanej binarnie dokonaj przesunięcia bitów o jedno miejsce w lewo. Najlepiej to widać w formie słupkowej.

dec bin
11 00001011
11 << 1 00010110

W wyniku tej operacji wszystkie bity zostały przesunięte o jedno miejsce w lewo. Bit znajdujące się na lewym końcu wyszedł po za zakres bajtu. Teraz jest 7 bitów. Oznacza to, że jednego brakuje 🙁 Aby wszystko grało należy jeszcze doczepić jeden bit z prawej strony. Pytanie tylko: co tam umieścić? Tu jest pewien problem. W tym wypadku została dodana cyfra 0. Jednak to, czy podczas przesunięć zostanie użyte 0, czy 1 zależy po części od typu komputera. Na komputerach PC powinno być 0. Przyjmijmy więc, że zawsze będzie to ta cyfra. Wracając do naszego przykładu. Po przesunięciu otrzymaliśmy liczbę: 00010110. Jak myślisz ile to jest po naszemu? Bez jakichkolwiek przeliczeń mogę stwierdzić, że jest to 22. Pomyśl chwilę, jak do tego doszedłem. Dobra już mówię. Była liczba: 00001011. Po przesunięciu jest: 00010110. Jak Ci wiadomo w systemie dwójkowym liczby są reprezentowane w następujący sposób:

operacja 128 64 32 16 8 4 2 1
0 0 0 0 1 0 1 1
11 << 1 0 0 0 1 0 1 1 0

Tak się składa, że poruszając się w lewo o jedno miejsce wartość zwiększa się dwukrotnie. Skoro wszystkie bity zostały przesunięte o jedno miejsce w lewo to nastąpiło jakby pomnożenie całej liczby przez 2. Jak nie wierzysz to spróbuj na innych liczbach. Następnie mamy przykład: 11 << 2, co już mogę powiedzieć jest szybszym odpowiednikiem 11 * 22. Zatem wygląda to tak:

operacja 128 64 32 16 8 4 2 1
0 0 0 0 1 0 1 1
11 << 2 0 0 1 0 1 1 0 0

Tym razem mamy przesunięcie o dwa miejsca. Jak już powiedziałem podczas przesuwania w lewo o jedno miejsce wartość zwiększała się dwukrotnie. Dokładniej brzmi to tak: Podczas przesu…. zwiększa się o 2liczba o jaką przesuwamy. W pierwszym przykładzie było: 11 << 1, zatem 11 * 21. Teraz mamy: 11 << 2, czyli: 11 * 22. Identycznie jest z zapisem: 11 << 3. Chyba nie muszę mówić jak to policzyć, co? Żeby nie było to powiem krótko. 11 << 3 to inaczej 11 * 23. Z tego wychodzi: 11 * 8 = 88. I na tym zakończę opisywanie tego operatora.

operator >>
służy do przesuwania bitów w prawo. Jak zapewne się domyślasz ten operator działa odwrotnie do swego poprzednika. Oznacza to, że można stosować go do dzielenia liczb. Tak się jednak nieciekawie składa, że owe dzielenie może być wykonane tylko na liczbach całkowitych 🙁 Oczywiście nikt Ci nie broni używać go do liczb zmiennoprzecinkowych. Jednak uważaj, bo wynik zostanie zaokrąglony do liczby całkowitej, co nie zawsze nam odpowiada. Na nasze szczęście >> stosuje się znacznie rzadziej niż <<. Prawdę mówiąc sam nigdy go nie stosowałem. Tradycyjnie objaśnię to na przykładzie.

Zaczniemy od rozrysowania pierwszego przykładu.

operacja 128 64 32 16 8 4 2 1
0 0 0 0 0 1 1 0
6 >> 1 0 0 0 0 0 0 1 1

Tym razem dokonujemy przesunięcia w prawo, zatem należy w tę stronę przesunąć wszystkie bity w liczbie 6. Jak widać bit po prawej stronie został zgubiony. Obecnie jest 7 bitów. Należy dopełnić do 8-iu bitów. Tutaj znów pojawia się problem odnośnie tego, czym zostanie dopełniony bajt. Podobnie, jak w przypadku przesunięcia w lewo jest to zależne od samej maszyny. W większości jest to 0. I tego właśnie będziemy się trzymać. Powiedziałem, że >> jest odwrotnością <<. Żeby to sprawdzić wykonajmy 6 >> 1. Pamiętasz jeszcze jak to się robiło? Jeśli nie to przypomnę. Będzie to 6 / 21 [zaczekaj chwilę muszę skorzystać z kalkulatora 🙂 ] Wynikiem jest oczywiście liczba 3. Sprawdźmy, czy się zgadza. Spójrz ta tabelkę powyżej. Jest tam liczba 00000011. Czy aby przypadkiem nie jest to 3. No właśnie. Korzystając z przesunięcia w prawo wykonaliśmy jednocześnie jakże skomplikowane 🙂 podzielenie liczby 6 przez 2. Na razie jest dobrze. Widać wyraźnie, że operatory >> i << działają analogicznie. Teraz będzie trochę pod górkę. Ale nie martw się jakoś sobie poradzimy. Przyjrzyj się poniższej tabelce.

operacja 128 64 32 16 8 4 2 1
0 0 0 0 0 1 1 0
6 >> 2 0 0 0 0 0 0 0 1

Jeśli patrzyłeś dokładnie to zapewne zorientowałeś się, że operacja 6 >> 2 da w wyniku 1. Dlaczego tak się stało? Przecież 6 >> 2 oznacza 6 / 22, czyli: 6 / 4. Wynikiem tego równania jest 1.5. Coś tu chyba jest nie tak. Przecież pracowaliśmy na liczbach całkowitych! Prześledźmy dokładniej co tutaj zaszło. Operacja: 6 >> 2 w systemie dziesiętnym wygląda tak: 6 / 22. Więc mamy: 6 / 4. Teraz uważaj. Po wykonaniu tej operacji otrzymamy dokładnie 1.5. Zatem jest to liczba nie całkowita. Dlatego też przy przesuwaniu jedna jedynka zostanie zgubiona i wynik zostanie zaokrąglony do liczby całkowitej. Został jeszcze jeden przypadek, czyli: 6 >> 3. Przeliczając to na system decymalny otrzymamy: 6 / 23, czyli 6 / 8. Otrzymamy tutaj 0.75, co też zostanie zaokrąglone, ale.. w dół! Wiem, że bardziej logiczne wydaje się tutaj zaokrąglenie w górę, lecz komputery działają nieco inaczej niż ludzie 🙂 Najłatwiej jest to wychwycić na przykładzie tabelki zamieszczonej poniżej. Wyraźnie widać, że występują tam tylko same zera!

operacja 128 64 32 16 8 4 2 1
0 0 0 0 0 1 1 0
6 >> 3 0 0 0 0 0 0 0 0

Nastąpiło przesunięcie bitów o trzy miejsca. Dziwnym trafem wszystkie bity wyszły po za zakres bajtu i zostały zgubione.

To właściwie wszystko. Na początek powinno wystarczyć. Co do operatorów, którymi posługujemy się na co dzień to chyba nie ma żadnych niejasności. Nowością mogą być operatory ++ oraz –, które są jedynie rozwinięciem już istniejących + i -. Operator % może się z początku wydawać trudny, ale potrzeba jego użycia wyjdzie dopiero po pewnym czasie, kiedy zaznajomisz się bardziej z C++. Jeśli chodzi o operatory logiczne to również powinieneś zaskoczyć 🙂 Pozostałe, czyli operatory bitowe są nieco trudniejsze do zrozumienia, ale wszystko można opanować. Jeśli nie rozumiesz ich działania to nie przejmuj się. Nie są niezbędne. Jednak, gdy bardzo chcesz zrozumieć zasadę ich działania to raz jeszcze przeczytaj sobie o nich i dokładnie przeanalizuj wszelkie przykłady. Możesz też poćwiczyć na innych liczbach, posługując się choćby kalkulatorem Window’sowskim. Jeśli wybierzesz widok profesjonalny ujrzysz kilka nowych przycisków. Chodzi mi o przyciski: And, Or, Xor, Not, Lsh i Mod. Działanie czterech pierwszych powinieneś już znać. Tak tak operacje logiczne na bitach. Przycisk Mod służy do dzielenia modulo. Natomiast Lsh do przesunięć bitowych w lewo. Jeśli chcesz zastosować przesunięcie w prawo musisz najpierw zaznaczyć pole Inv znajdujące się po lewej stronie. Pamiętaj też, że możesz szybko i łatwo przeliczać liczby na inne systemy liczbowe. Służą do tego celu przyciski Hex, Dec, Bin, Oct,. Chyba wiadomo co oznaczają? Trzy pierwsze na pewno kojarzysz. Są to kolejno: system 16-wy, 10-ny i 2-wy. Ostatni konwertuje liczbę do systemu ósemkowego. System ósemkowy działa podobnie, jak szesnastkowy. Jedyną różnicą jest liczba 8 w podstawie, zamiast 16. Prawdę mówiąc jeszcze nigdy nie spotkałem się nigdzie z wykorzystaniem tego systemu. To już naprawdę koniec tego rozdziału.

Autor: Kesay

[Artykuł pochodzi ze strony guidecpp.prv.pl, autor wyraził zgodę na publikację]