LearnToCP
Prijavi se
Navigacija
PočetnaRoad-mapaProblemiO Nama
Teorija
Takmičarsko Znanje
Izbor Radnog Okruženja (IDE)Interaktivni ZadaciOutput-only Zadaci
Osnove
Tvoj Prvi ProgramTipovi podataka, Unos i IzlazC++ sintaksaModuloFunkcijeVektoriMatriceVremenska Složenost Algoritma
Sortiranje
SortiranjeSortiranje PrebrojavanjemRadix Sort
Tehnike Optimizacije
Dva PokazivačaZbir brojeva od 1 do nZbir PrefiksaBinarna PretragaPohlepni AlgoritmiFunkcije Binarne PretrageBinarna Pretraga po RešenjuPodeli, pa Vladaj
Binarni Brojevi
Binarni BrojeviBrojevi u koduOperacije nad BitovimaBitmaske
Matematika
Binarno StepenovanjeProsti BrojeviRastavljanje na proste činioceNZD i NZSEratostenovo SitoModifikovano Sito
Strukture Podataka
Niske (Stringovi)StekRedMapeSkupovi (Set)Red sa PrioritetomKorišćenje Proizvoljnih KriterijumaSegmentna StablaFenvikova StablaSparse TabeleDisjunktni SkupoviSqrt Dekompozicija
Kombinatorika
Pravilo SabiranjaPravilo MnoženjaKombinatorni ObjektiPrincip Uključenja Isključenja
Geometrija
Osnove GeometrijeVektoriVektorski i Skalarni ProizvodLinijePoligoniUgloviTačka u PoligonuRastojanja i Tačke PresekaKonveksni OmotačKrugovi
Rekurzija
PokazivačiRekurzijaGenerisanje Kombinatornih Objekata
Dinamičko Programiranje
O DP-uDP problemiDP nad StablimaDP nad Bitmaskama
Teorija Grafova
GrafoviDFS i BFSNajkraći PuteviStablaTopološko SortiranjeDajkstrin AlgoritamMinimalna Razapinjuća StablaAlgoritmi Najkraćih Puteva
Napredna Teorija Grafova
Dvostruka PovezanostJako Povezane KomponenteBipartitni GrafMaksimalni Protok u GrafuFord-Fulkersonov AlgoritamDualnost Protoka i Minimalnog PresekaTeško-Laka DekompozicijaCentroidna Dekompozicija
Napredne Strukture Podataka
2D i 3D Segmentna StablaLenjo PropagiranjeImplicitna Segmentna StablaPerzistentna Segmentna StablaNajbliži Zajednički PredakTrieBalansirana Binarna Stabla PretrageMoov Algoritam

Operacije nad Bitovima

U ovoj lekciji ćemo naučiti operacije koje direktno utiču na bitove nekog broja!

Kao što već znamo, celi brojevi u programima predstavljeni su nizom 0 i 1, najčešće u 32-bitnom ili 64-bitnom obliku.

Postoje operacije koje rade upravo sa tim bitovima i menjaju ih na različite načine.

Kada radite sa bitwise operacijama, najbolje je koristiti unsigned integer tipove!

Bitwise Not (~)

Operator bitwise not jednostavno obrće sve bitove nekog broja.

Na primer:

Ako imamo a = 1001
Onda je ~a = 0110

Kod:

int main(){

    unsigned int a =1;

	cout<<a<<'\n';
	cout<<~a;
}

Izlaz:
1
4294967294

Pošto je: 1 = 0000 0000 0000 0000 0000 0000 0000 0001
A :4294967294 = 1111 1111 1111 1111 1111 1111 1111 1110

Bitwise Shift (>>, <<)

Bitwise shift pomera sve bitove nekog broja ulevo ili udesno. Možemo da odredimo za koliko mesta će se bitovi pomeriti.

Primer:

a = 0011
a << 2 = 1100

Ili:

a = 0111
a >> 1 = 0011

Ako neki bitovi izađu van opsega (out of bounds), praktično se brišu. Njihovo mesto popunjavaju nule, bilo sa leve ili sa desne strane.

Kod:
int main(){

    unsigned int a =1;
    unsigned int b = a<<3;

	cout<<a<<'\n';
	cout<<b;
}

Izlaz:
1
8

Pošto je: 1 = 0000 0000 0000 0000 0000 0000 0000 0001

A: 8 = 0000 0000 0000 0000 0000 0000 0000 1000

Zanimljiva stvar kod shift operacija je to što pomoću njih veoma lako možemo dobiti stepene broja 2, jer je 2^x isto što i 1 << x.

To je zato što radimo u binarnom sistemu, a pomeranje ulevo za jednu poziciju množi broj sa 2 (pod uslovom da ima dovoljno mesta da rezultat stane u dati tip podatka).

Bitwise AND (&)

Bitwise and (ne treba ga mešati sa logičkim operatorom &&) radi sa dva broja i za svaki bit izvršava sledeću operaciju:

  • Uporedi i-ti bit prvog broja sa i-tim bitom drugog broja
  • Ako su oba bita 1, rezultat je 1, u suprotnom je 0

Primer:

a = 1001
b = 1110

a & b = 1000

To znači da & može da služi kao maska, tako što propušta samo određene bitove. Ovo je veoma važna osobina koju treba zapamtiti.

Kod:
int main(){

    unsigned int a =12;
    unsigned int b = 6;

    unsigned int c = a & b;

	cout<<c;
}

Izlaz: 4

Pošto je:

a = 12 = 0000 0000 0000 0000 0000 0000 0000 1100
b = 6 = 0000 0000 0000 0000 0000 0000 0000 0110

c = a & b = 0000 0000 0000 0000 0000 0000 0000 0100 = 4

Još jedna korisna stvar je da za unsigned brojeve važi: a & b <= min(a, b)

Bitwise OR (|)

Bitwise or (ne treba ga mešati sa logičkim operatorom ||) takođe radi sa dva broja i za svaki bit radi sledeće:

  • Uporedi i-ti bit prvog broja sa i-tim bitom drugog broja
  • Ako su oba bita 0, rezultat je 0, u svim ostalim slučajevima rezultat je 1

Primer:

a = 1001
b = 1110

a | b = 1111

int main(){

    unsigned int a =12;
    unsigned int b = 6;

    unsigned int c = a | b;

	cout<<c;
}

Izlaz: 14

Pošto je:

a = 12 = 0000 0000 0000 0000 0000 0000 0000 1100
b = 6 = 0000 0000 0000 0000 0000 0000 0000 0110

c = a | b = 0000 0000 0000 0000 0000 0000 0000 1110 = 14

Bitwise XOR (^)

Bitwise xor je veoma zanimljiva operacija. Radi sa dva broja i za svaki bit radi sledeće:

  • Uporedi i-ti bit prvog broja sa i-tim bitom drugog broja
  • Ako su bitovi različiti, rezultat je 1, u suprotnom je 0

Primer:

a = 1001
b = 1110

a ^ b = 0111

Kod:

int main(){

    unsigned int a =12;
    unsigned int b = 6;

    unsigned int c = a ^ b;

	cout<<c;
}

Izlaz: 10

Pošto je:

a = 12 = 0000 0000 0000 0000 0000 0000 0000 1100
b = 6 = 0000 0000 0000 0000 0000 0000 0000 0110

c = a ^ b = 0000 0000 0000 0000 0000 0000 0000 1010 = 10

XOR ima mnogo zanimljivih osobina. Jedna od najvažnijih je da pomoću njega možemo da povratimo jedan operand ako znamo drugi operand i rezultat XOR operacije.

Ako važi: c = a ^ b
onda važi i: a = c ^ b
i: b = c ^ a

Još neke korisne osobine su:

x ^ x = 0 (Ako XOR-ujemo broj sam sa sobom, dobijamo 0.)

I:

x ^ 0 = x (Ako XOR-ujemo broj sa 0, dobijamo isti taj broj.)

bitwise-ops.png

Napomena:

Možemo koristiti i skraćeni zapis sa operatorom dodele:

a &= b; isto što i a = a & b;
a |= b; isto što i a = a | b;
a ^= b; isto što i a = a ^ b;
a <<= n; isto što i a = a << n;
a >>= n; isto što i a = a >> n;