Úvod do dvojkovej sústavy ste mali v predchádzajúcej lekcii Čísla v dvojkovej sústave. Teraz si ukážeme, ako vieme s binárnymi číslami pracovať v Pythone, a na čo je to dobré.
V Pythone pracujeme s číslami v desiatkovej sústave, ako to robíme kdekoľvek inde. Avšak Python si vie čísla reprezentovať v rôznych sústavách, ku ktorým sa vieme dostať napríklad takto:
# Desiatkova (decimalna) sustava
x = 42
# Dvojkova (binarna) sustava
a = bin(x)
# Osmickova (oktalna) sustava
b = oct(x)
# Sestnastkova (hexadecimalna) sustava
c = hex(x)
print(f'dec: {x}, bin: {a}, oct: {b}, hex: {c}')
# dec: 42, bin: 0b101010, oct: 0o52, hex: 0x2a
V tejto lekcii sa zameriame ďalej len na binárne čísla.
Ako môžete vidieť, binárne číslo je len rad núl a jednotiek (hovoríme tomu aj bitový reťazec, bit string,
pretože tie nuly a jednotky voláme bity), ktorý špecifikuje dané číslo.
V Pythone vieme zadať číslo aj rovno v binárnom tvare, Python si ho potom sám prekonvertuje do desiatkovej sústavy.
Urobíme to tak, že k bitovému reťazcu pridáme prefix 0b
, ktorý Pythonu hovorí, že nasledujúci reťazec reprezentuje binárne číslo:
x = 0b101010
print(x)
# 42
print(x == 42)
# True
Bitové operácie pracujú na bitovom reťazci, ktorý prechádzajú po jednom bite, na ktorom vykonávajú nejakú operáciu.
Bitové operácie sú pre programátorov veľmi dôležité, pretože každý výpočet, ktorý prebehne v počítači je jedna z týchto operácií. Počítač v najzákladnejšej forme nevie robiť nič iné, ako spracovávať binárne čísla pomocou binárnych operácií, avšak len tento základ stačí na to, aby sme vedeli robiť aritmetiku v desiatkovej sústave, spúšťať algoritmy a nakoniec robiť všetko, čo dokáže moderný počítač.
AND
Poďme sa pozrieť na našu prvú bitovú operáciu, ktorú možno z logiky poznáte ako konjunkcia alebo v bežnej reči "a" alebo AND
.
Operácia AND
prechádza dva binárne reťazce po bitoch, na miestach, kde sa zhodujú na jednotke vráti jednotku, inak nulu.
V Pythone operátor pre AND
značíme ako &
:
a = 0b101010 # 42
b = 0b110011 # 51
print(bin(a & b))
# 0b10010
V tomto bode vám možno napadne, že takéto prechádzanie dvoch binárnych reťazcov naraz bit po bite funguje len na bitové reťazce rovnakej dĺžky.
Čo ak chceme robiť AND
napríklad na číslach 42 (101010
) a 455 (111000111
)?
Rieši sa to jednoducho, iba kratšiemu reťazcu pripíšeme na začiatku nuly, podobne ako keby sme to robili v desiatkovej sústave.
Python to, samozrejme, robí automaticky.
OR
Okrem AND
máme aj operáciu OR
, teda "alebo", respektíve z logiky to možno poznáte ako disjunkciu.
Podobne ako pri AND
, znova prechádzame dva binárne reťazce naraz bit po bite,
ibaže tentokrát vo výstupnom reťazci bude jednotka na všetkých miestach,
kde aspoň jeden reťazec má jednotku. Operátor OR
v Pythone značíme ako |
:
a = 0b101010 # 42
b = 0b110100 # 52
print(bin(a | b))
# 0b111110
NOT
Ďalšou bitovou operáciou je negácia alebo NOT
, ktorá pracuje len s jedným bitovým reťazcom, pričom z každého nulového bitu spraví jednotkový a naopak.
Teda ak máme napríklad reťazec 1010
(v desiatkovej sústave 10), tak po negácii bude z neho 0101
(v desiatkovej sústave 5).
V Pythone operátor negácie značíme ako ~
.
Tu to začína byť zaujímavejšie. Ako sme spomínali pred chvíľou, tak,
ako napríklad číslo 42
v desiatkovej sústave vieme v zásade zapísať aj ako 042
, 0042
, atď.,
tak aj binárne číslo 101010
vieme zapísať ako 0101010
, 00101010
, alebo aj 000000000000101010
.
Keď urobíme NOT
na čísle 101010
, dostaneme číslo 010101
.
Z tohoto čísla ale Python oreže začiatočné nuly (tak ako ich oreže z čísla 042
), takže dostaneme číslo 10101
.
Ako teda získať z negácie presne toľko bitov, ako by sme chceli?
S týmto problémom sa vieme popasovať tak, že ohraničíme, s akým dlhým binárnym reťazcom pracujeme.
To vieme urobiť napríklad tak, že na výsledok negácie aplikujeme ešte AND
s binárnym reťazcom tvoreným jednotkami.
Napríklad, ak chceme, aby sme mali výsledok s dĺžkou 8 bitov, AND
aplikujeme na znegované číslo a binárne číslo, ktoré má 8 jednotiek:
a = 0b101010 # 42
b = 0b11111111 # 255
c = ~a & b
print(bin(c))
# 0b11010101
Ak chceme pootáčať len bity, ktoré máme v pôvodnom binárnom reťazci a
, logicky sa to dá spraviť napríklad jedným z týchto spôsobov:
print(bin(~a & 0b111111))
# 0b10101
print(bin(~a & 2 ** 6 - 1))
# 0b10101
Zamyslite sa, ako funguje ten druhý spôsob, a prečo sme ako výsledok dostali 5 bitov, keď sme ich na začiatku mali 6.
XOR
Trochu vyššie sme sa bavili o operácii OR
. Operácia XOR
je niečo podobné.
XOR
sa celým menom volá exclusive OR alebo teda exkluzívna disjunkcia.
Exkluzívna preto, že vráti jednotku, iba ak sú dva bity rozdielne.
XOR
sa teda správa rovnako ako OR
, avšak s tým rozdielom, že neakceptuje prípad, keď sa zhodujú jednotky.
Normálny OR
preto voláme tiež aj inkluzívna disjunkcia.
V slovenčine XOR
zodpovedá spojeniu "buď, alebo", čiže naproti normálnemu "alebo" nepripúšťame, že by sa dve veci mohli stať zároveň.
V Pythone operátor XOR
značíme ako ^
:
a = 0b101010 # 42
b = 0b110100 # 52
print(bin(a ^ b))
# 0b11110
Vo výsledku vyššie si opäť môžete všimnúť, že Python nám z neho odstránil prvú nulu.
XOR
sa v praxi často využíva, keď chceme zistiť, na ktorých miestach sa dva binárne reťazce líšia, alebo spočítať počet takýchto miest.