Co to jest?
Działania na grupach bitów. Z powodu sposobu przedstawienia w pamięci sens ma dla liczb całkowitych (w tym znaków).
Dane są przechowywane w pamięci w systemie dwójkowym. Przykłady wprowadzające:
Dalej będę się opierał tylko na 4 bitach. W pamięci komputera bajty składają się z 8. W pawnie wszystkie zmienne są 4 lub 8 bajtowe (32 lub 64 bity), zależnie od serwera.0010
1001
0110
Ilość dostępnych bitów określa definicja cellbits
1. Przesunięcia
Zmienia kolejność bitów przenosząc na miejsce sąsiednie.
a) w lewo
Operator: <<
1<<3Bity liczby jeden (0001) przesuwa w lewo o trzy pozycje. W brakujące miejsca dopisywane są zera, bity wykraczające poza zakres są tracone.
Zatem 1<<3 = '1000' co po przeliczeniu na system dziesiętny daje liczbę 8.0001 - początkowo
0010 - po przesunięciu o 1
0100 - po przesunięciu o 2
1000 - po przesunięciu o 3
Efekt: przesunięcie w lewo o n pozycji równoznaczne jest z mnożeniem przez (2 do potęgi n).
b)w prawo arytmetycznie
Operator: >>
7>>1Bity liczby siedem (0111) przesuwa w prawo o jedną pozycje. W brakujące miejsca dopisywane bity o wartości najstarszego bitu pierwotnej liczby, bity wykraczające poza zakres są tracone.
Zatem 7>>1 = '0011' co po przeliczeniu na system dziesiętny daje liczbę 3.0111 - początkowo
0011 - po przesunięciu o 1
Braki są uzupełniane bitem znaku.
15>>1
1111 - początkowo
1111 - po przesunięciu o 1
Efekt: przesunięcie w prawo o n pozycji równoznaczne jest z dzieleniem całkowitym przez (2 do potęgi n).
b)w prawo logicznie
Operator: >>>
15>>>1Bity liczby piętnaście(1111) przesuwa w prawo o jedną pozycje. W brakujące miejsca dopisywane są zera, bity wykraczające poza zakres są tracone.
Zatem 15>>>1 = '0111' co po przeliczeniu na system dziesiętny daje liczbę 7.1111 - początkowo
0111 - po przesunięciu o 1
Braki są uzupełniane zerami.
2. Operacje logiczne
Działania logiczne wykonywane między odpowiednimi bitami obu liczb.
a) koniunkcja inaczej iloczyn
Operator: &
8&2Zapis dziesiętny na binarny:
1000 //8 0010 //2Teraz bierzemy kolejne bity, wyznaczając ich iloczyn. Rozpiska:
1&1=1 1&0=0 0&1=0 0&0=0
1000
0010
Wykonujemy działanie 1&0 =0 zatem od lewej strony pierwszy bit wyniku=0
1000
0010
Wykonujemy działanie 0&0 = 0 zatem od lewej strony drugi bit wyniku=0
1000
0010
Wykonujemy działanie 0&1 = 0 zatem od lewej strony trzeci bit wyniku=0
1000
0010
I wykonujemy działanie 0&0 = 0 zatem od lewej strony czwarty bit wyniku=0
Zatem 8&2= '0000' co po przeliczeniu na system dziesiętny daje liczbę 0.

Operator: |
5|3Zapis dziesiętny na binarny:
0101 //5 0011 //3Teraz bierzemy kolejne bity, wyznaczając ich sumę. Rozpiska:
1|1=1 1|0=1 0|1=1 0|0=0
0101
0011
Wykonujemy działanie 0|0 = 0 zatem od lewej strony pierwszy bit wyniku=0
0101
0011
Wykonujemy działanie 1|0 = 1 zatem od lewej strony drugi bit wyniku=1
0101
0011
Wykonujemy działanie 0|1 = 1 zatem od lewej strony trzeci bit wyniku=1
0101
0011
I wykonujemy działanie 1&1 = 1 zatem od lewej strony czwarty bit wyniku=1
Zatem 5|3 = '0111' co po przeliczeniu na system dziesiętny daje liczbę 7.
c) różnica symetryczna inaczej XOR
Operator: ^
3^1Zapis dziesiętny na binarny:
0011 //3 0001 //1Teraz bierzemy kolejne bity, wyznaczając ich różnicę symetryczną. Rozpiska:
1^1=0 1^0=1 0^1=1 0^0=0
0011
0001
Wykonujemy działanie 0^0 = 0 zatem od lewej strony pierwszy bit wyniku=0
0011
0001
Wykonujemy działanie 0^0 = 0 zatem od lewej strony drugi bit wyniku=1
0011
0001
Wykonujemy działanie 1^0 = 1 zatem od lewej strony trzeci bit wyniku=1
0011
0001
I wykonujemy działanie 1^1 = 0 zatem od lewej strony czwarty bit wyniku=1
Zatem 3^1 = '0010' co po przeliczeniu na system dziesiętny daje liczbę 2.
d) negacja
Operator: ~
~1Zapis dziesiętny na binarny:
0001 //1Operacja jednoargumentowa - nie porównujemy bitów ze wzorcem, a jedynie zamieniamy każde 0 na 1 i odwrotnie. Stąd:
~0001 1110Przykład ukazuję ideę - nie ma sensu przeliczać na system dziesiętny, bo w Pawnie nie spotkamy 4bitowego typu int.
3. Używanie:
Gdy na liczbę w pamięci komputera spojrzymy jak na zbiór wartości logicznych (1 lub 0) to w prosty sposób wykorzystać możemy operacje bitowe do przechowywania i sprawdzania zawartości składowej w całości.
Dokładniej chodzi o to, że każdej wartości 0 lub 1 przypisana jest jakaś funkcja (znaczenie). Mamy ciąg
Możemy przeliczyć to na system dziesiętny, ale łatwiej pracować w takiej postaci. Każda liczba to informacja czy dana funkcja składowa jest aktywna (1) lub nie (0).0101
Przykład:
Do zaprezentowania możliwego użycia wybrałem prawa dostępu - chmod.
Określa jakie operacje wykonać można na danych pliku/katalogu. Składa się z 3 wartości. Każda z operacja ma swój odpowiednik literowy i liczbowy.
Ograniczam zagadnienie do 1 grupy (zwykle określa się chmod dla 3 grup) pokażę jak zamienić zapis literowy na liczbowy i odwrotnie."wykonywanie" "x" 1
"zapis" "w" 2
"odczyt" "r" 4
Pierwsze co musimy zrobić to zdecydować, które bity za co odpowiadają:
#define CHNONE 001>>1 //000=0 #define CHEXEC 001 //001=1 #define CHWRITE 001<<1 //010=2 #define CHREAD 001<<2 //100=4W tym wypadku kolejność ma znaczenie. Gdy będziemy tworzyć własne zestawy już nie będzie to takie ważne.
Napiszmy teraz funkcję, która przeliczy liczbę na skrót literowy. Pomijam sprawdzanie poprawności danych wejściowych, bo nie to jest tutaj istotne.
Funkcja strcat() dodaję podany ciąg na koniec wskazanego tekstu.
#include <amxmodx> #include <amxmisc> #define PLUGIN "Chmod" #define VERSION "1.0" #define AUTHOR "R3X" #define CHNONE 001>>1 //000=0 #define CHEXEC 001 //001=1 #define CHWRITE 001<<1 //010=2 #define CHREAD 001<<2 //100=4 public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) register_concmd("chmod_num2str","chmod_num2str",-1,"<chmod num>"); } public chmod_num2str(id,level,cid) { //sprawdzenie prawa dostępu komendy i liczby argumentów if (!cmd_access(id,level,cid,2)) return PLUGIN_HANDLED; //deklaracja zmiennych new chmod_num,tekst[2],chmod_str[4]=""; //pobranie argumentu read_argv(1, tekst, 1); //konwersja na liczbę chmod_num=str_to_num(tekst); //sprawdzenie bitu odpowiadającego za odczyt if(chmod_num & CHREAD) { //dodaje 'r' strcat(chmod_str,"r",3); } //sprawdzenie bitu odpowiadającego za zapis if(chmod_num & CHWRITE) { //dodaje 'w' strcat(chmod_str,"w",3); } //sprawdzenie bitu odpowiadającego za wykonywanie if(chmod_num & CHEXEC) { //dodaje 'x' strcat(chmod_str,"x",3); } console_print(id,"chmod[%d] -> ^"%s^"",chmod_num,chmod_str); return PLUGIN_HANDLED; }
Dlaczego używamy tutaj iloczynu?
Wyzerują się wszystkie nieistotne w danym przypadku bity i zostanie do porównania ten, o który nam chodzi.
chmod_num2str 6Przejdźmy fragment drogi chmod_num.
Przypisanie wartości z argumentu. Przyjmijmy, że będzie to 6 (110).
Pierwsze sprawdzenie:
chmod_num & CHREAD(szukamy więc iloczynu takich liczb:)
110 100Kolejno od lewej:
1&1=1
1&0=0
Ostatecznie wynik = 100 - nie jest równy 0 i przejdzie pozytywnie test logiczny if().0&0=0
Spróbuj samodzielnie wykonać test logiczny nr 2 i 3.