Operacje bitowe, maski bitowe

Przesunięcie bitowe w lewo, czyli sposób na szybkie mnożenie przez 2:
int a = 1, b = 2;
a = a << 1;
b = b << 2;
Wynikiem dla b jest liczba 8, wynikiem dla a jest liczba 2. Wartość zmiennej a (czyli w tym przypadku 1) jest mnożona przez 2 do potęgi podanej dla przesunięcia, czyli 2 do potęgi pierwszej (a << 1). Dzieje się tak ze względu na wartości bitów. Najmłodszy bit, czyli ten o najmniejszej wadze (wartości) ma wartość 21 , każdy kolejny ma wartość większą o kolejną potęgę liczby dwa, czyli: 21, 22, 23, 24 itd…
Czyli a << 1, to jest to samo co 1 * 21 i da wynik 2. Przesunięcia bitowe chyba w większości przypadków są szybsze od standardowego zapisu mnożenia. Używa się tego w momentach, kiedy szybkość liczenia ma duże znaczenie, np. w mikrokontrolerach. Co prawda kilka operacji zwykłego mnożenia niewiele zmieni jeśli chodzi o prędkość, ale przy setkach, tysiącach czy milionach operacji to jednak ma to znaczenie.
Wynik 8 dla zmiennej b wynika z działania 2 * 22
Przesunięcie bitowe w prawo, czyli sposób na szybkie dzielenie przez 2:
a = 4, b = 8; a = a >> 1; // 4 / 2^1 = 2 b = b >> 2; // 8 / 2^2 = 2
a >> 1 to jest to samo co 4 (wartość zmiennej a) podzielone przez 21(czyli 2), co daje wynik 2 (4:2 = 2).
b >> 2 o jest to samo co 8 (wartość zmiennej b) podzielone przez 22 (czyli 4), co daje wynik 2 (8:4 = 2)
Operacje bitowe:
Załóżmy, że:
int e = 232, int f = 111;
liczba 232 w systemie binarnym ma wartość 1110 1000
liczba 111 w systemie binarnym ma wartość 0110 1111
dostępne operacje bitowe to:
Załóżmy, że:
int e = 232, int f = 111;
liczba 232 w systemie binarnym ma wartość 1110 1000
liczba 111 w systemie binarnym ma wartość 0110 1111
dostępne operacje bitowe to:
AND zaznaczane jako znak &
int bin_and = e & f;
Wynikiem dla tej operacji jest liczba 104, czyli 0110 1000
e: 1110 1000
f: 0110 1111
bin_and = 0110 1000
czyli:
1 i 0 daje 0
0 i 1 daje 0
1 i 1 daje 1
0 i 0 daje 0
OR zaznaczane jako znak |
int bin_or = e | f;
wynikiem jest liczba 239, czyli 1110 1111
e: 1110 1000
f: 0110 1111
bin_or = 1110 1111
czyli:
1 i 0 daje 1
0 i 1 daje 1
1 i 1 daje 1
0 i 0 daje 0
XOR zaznaczane jako znak ^
int bin_xor = e ^ f;
wynikiem jest liczba 135, czyli 1000 0111
e: 1110 1000
f: 0110 1111
bin_or = 1000 0111
czyli:
1 i 0 daje 1
0 i 1 daje 1
1 i 1 daje 0
0 i 0 daje 0
NOT zaznaczane jako znak ~
f: 0110 1111
~f: 0110 1111
czyli;
0 to 1
1 to 0
przy negacji należy dodać, że nie do końca tak jest, jak podałem, ponieważ zanegowana liczba powinna być liczbą ujemną. Liczby ujemne, to bajka na kolejny wpis, jednak warto wiedzieć, że bardzo istotną rolę gra tutaj two`s complement, czyli uzupełnienie do dwóch – sposób zapisu liczb ujemnych.
Jako ciekawostkę mogę dodać, że jeśli bit najmłodszy (o najmniejszej wadze) jest ustawiony na 1, to liczba, którą reprezentuje postać binarna jest nieparzysta, jeśli wartość jest ustawiona na 0, to liczba jest parzysta.
1101 = 13 (nieparzysta)
1100 = 12 (parzysta)
Wszystkie podane operacje w jednym programie:
#include <iostream>
void binarnie(long long d)
{
std::cout << d << ": " << std::endl;
for(int i = 7; i >= 0; i--)
{
if(d < 0){ d *= -1; }
else { std::cout << ((d >> i)%2); }
} std::cout << std::endl;
}
int main()
{
//przesuniecie bitowe w lewo (mnozenie)
int a = 1, b = 2;
a = a << 1; // 1 * 2^1 = 2
b = b << 2; // 2 * 2^2 = 8
std::cout << a << " " << b << std::endl;
//przesuniecie bitowe w prawo (dzielenie)
a = 4, b = 8;
a = a >> 1; // 4 / 2^1 = 2
b = b >> 2; // 8 / 2^2 = 2
std::cout << a << " " << b << std::endl;
int e = 232, f = 111;
binarnie(e); // 1110 1000
binarnie(f); // 0110 1111
std::cout << std::endl << "binarne or: " << std::endl;
int bin_or = e | f;
binarnie(bin_or); // wyswietli 239: 1110 1111
std::cout << std::endl << "binarne and: " << std::endl;
int bin_and = e & f;
binarnie(bin_and); // wyswietli 104: 0110 1000
std::cout << std::endl << "binarne xor: " << std::endl;
int bin_xor = e ^ f;
binarnie(bin_xor); // wyswietli 135: 1000 0111
std::cout << std::endl << "zmiana czwartego bitu na 1 dzieki OR: " << std::endl;
// e = 1110 1000
int bin_mask = e | (1 << 4); // maska 0000 0001 przesunieta w lewo o 4 pozycje i wykonane OR
binarnie(bin_mask); // wyswietli 248: 1111 1000
std::cout << std::endl << "zmiana trzeciego bitu na 0 dzieki XOR: " << std::endl;
// bin_mask = 1111 1000
bin_mask = bin_mask ^ (1 << 3); // maska 0000 0001 przesunieta w lewo o 3 pozycje i wykonane XOR
binarnie(bin_mask); // wyswietli 240: 1111 0000
for(int i = 0; i < 8; i++)
{
if (( bin_mask & (1 << i )) > 0)
std::cout << "bit " << i << " jest wlaczony" << std::endl;
//if (( bin_mask & (1 << 2 )) == 0)
else
std::cout << "bit " << i << " jest wylaczony" << std::endl;
}
}