Binääri- ja heksadesimaalijärjestelmä
Tässä osassa esitellään perusteet kymmenkantajärjestelmästä, kaksikantajärjestelmästä eli binäärijärjestelmästä ja 16-kantajärjestelmästä eli heksadesimaalijärjestelmästä.
Kymmenjärjestelmä
Nykytietokoneissa kaikki tieto on tallennettuna bitteinä ja esimerkiksi kokonaisluvut binäärilukuina eikä siis kymmenjärjestelmän ( eli desimaalijärjestelmän tai kymmenkantajärjestelmän) lukuina toisin kuin ennen vanhaan. Johdatuksena eri kantalukujärjestelmiiin palautetaan kuitenkin mieliin, miten kymmenjärjestelmän luvut muodostuvat.
Kymmenkantajärjestelmässä luvut ilmaistaan käyttäen kantalukuna lukua 10 ja numeroina 0…9. Numeron paikka luvussa ilmaisee, onko kyse ykkösistä, kymmenistä, sadoista tai muista kantaluvun kymmenen potensseista. Siten esimerkiksi
\[\begin{align*} 1982 &= 1 \cdot 1000 + 9 \cdot 100 + 8 \cdot 10 + 2 \cdot 1 \\ &= 1 \cdot 10^3 + 9 \cdot 10^2 + 8 \cdot 10^1 + 2 \cdot 10^0 . \end{align*}\]Seuraavaksi perehdytään binäärilukuihin ja heksadesimaalilukuihin.
Binääriluvut
Binääriluku on kaksikantaisen järjestelmän eli binäärijärjestelmän luku. Binäärijärjestelmässä on numerot 0 ja 1. Näitä kutsutaan biteiksi. Kaksikantajärjestelmässä numeron paikka luvussa ilmaisee, onko kyse ykkösistä, kakkosista, nelosista, kahdeksikoista tai muista kantaluvun 2 potensseista. Siten esimerkiksi:
\[\begin{align*} 0\text{b} 1001 &= \mathbf{1} \cdot 2^3 + \mathbf{0} \cdot 2^2 + \mathbf{0} \cdot 2^1 + \mathbf{1} \cdot 2^0 \\ &= \mathbf{1} \cdot 8 + \mathbf{0} \cdot 4 + \mathbf{0} \cdot 2 + \mathbf{1} \cdot 1 \\ &= 8+0+0+1 \\ &= 9. \end{align*}\]Jotta voidaan erottaa binääriluvut kymmenjärjestelmän luvuista, binääriluvun eteen asetetaan etuliite 0b tai luvun loppuun alaindeksi 2 tällä tavalla: 0b1001 tai 10012. Tässä materiaalissa käytetään binääriluvun edessä etuliitettä 0b, sillä se on yleinen binääriluvun merkintätapa useissa ohjelmointikielessä (ainakin Python, Java ja C). Lisäksi bittejä jaotellaan lukemisen helpottamiseksi välilyöntejä esimerkiksi tällä tavalla: 0b 1100 1010. Ohjelmointikielissä ei kuitenkaan yleensä voi kirjoittaa välilyöntejä bittien väliin, vaan sen sijaan on käytettävä alaviivaa. Esimerkiksi Java-kielessä voi määritellä binäärilukuja näin:
int a = 0b11001010;
int b = 0b1100_1010;
int c = 0b1_100_1010;
// int d = 0b_1100_1010; Tämä ei kuitenkaan toimi!
// Java 11:ssa etuliitteen 0b ja binääriluvun välissä ei saa olla alaviivaa.
// Kuitenkin esimerkiksi Python 3:ssa siinä voi olla alaviiva.
Pythonissa esitystapa on sama, mutta ilman puolipistettä ja tyyppimerkintää int
.
Kahdeksan bitin eli tavun mittaisen binääriluvun muuntaminen kymmenjärjestelmän luvuksi onnistuu kätevästi seuraavan taulukon avulla.
Taulukon ylimmällä rivillä näkyy kahden potenssit, jotta siitä näkee miksi nuo luvut ovat 1, 2, 4, … Kun harjoittelet lukumuunnoksia, sitä potenssimerkintäriviä ei tarvita. Harjoittele tekemään lukumuunnoksia kynällä ja ruutupaperilla (ilman noita kahden potenssien merkintöjä).
- Tee tuollainen taulukko ruutupaperille (ilman noita kahden potenssien merkintöjä).
- Jos muunnettava binääriluku on pidempi kuin 8 bittiä, laita taulukon yläriville vasemmalle lisää kahden potensseja 256, 512, 1024, … Siis siten, että esimerkiksi 11 bittiä pitkässä luvussa on ylärivillä vasemmalta lukien kahden potenssit 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1.
- Merkitse binääriluvun bitit taulukkoon.
- Laske ne ylärivin luvut yhteen, joiden alla on bitti 1.
Esimerkki binääriluvun 0b 1001 0011 muuntamisesta kymmenjärjestelmän luvuksi:
Lukujen 128, 16, 2 ja 1 alla on bitti 1. Siten
\[\begin{align*} 0\text{b}\hspace{0.2em}1001\hspace{0.2em}0011 &= 128+16+2+1 \\ &= 147. \end{align*}\]Kymmenjärjestelmän luvun muuntaminen binääriluvuksi
Tässä esitellään kaksi tapaa muuntaa kymmenjärjestelmän lukuja binääriluvuiksi.
Käytä muunnostaulukkoa
Pienten lukujen muuntaminen onnistuu kätevästi muunnostaulukon avulla. Piirrä ruutupaperille taulukko, jossa on riittävästi kahden potensseja lukuun nähden. Esimerkiksi jos luku on pienempi kuin 28 eli 256, riittää piirtää muunnostaulukko seuraavasti:
Muunnetaan nyt luku 169 binääriluvuksi. Suurin kahden potenssi, mikä mahtuu lukuun 169 on 128. Merkitään luvun 128 alle bitti 1:
Koska \(169 - 128 = 41\), ei tarvita lukua \(64\) ilmaisevaa bittiä. Laitetaan luvun \(64\) alle bitti 0. Lisäksi huomataan, että tarvitaan luvun \(32\) ilmaiseva bitti. Laitetaan sen alle bitti 1.
Koska \(169 - 128 = 41\) ja \(41 - 32 = 9\), ei tarvita lukua \(16\) ilmaisevaa bittiä, mutta tarvitaan luvun \(8\) ilmaiseva bitti. Laitetaan siis luvun \(16\) kohdalle 0 ja luvun \(8\) kohdalle 1.
Koska \(169 - 128 - 32 - 8 = 1\), ei tarvita luvun \(4\) ja luvun \(2\) ilmaisevaa bittiä, mutta tarvitaan luvun \(1\) ilmaiseva bitti. Laitetaan 0 niihin kohtiin mitä ei tarvita ja 1 luvun \(1\) kohdalle ja saadaan:
Nyt muunnostaulukko on täytetty ja nähdään, että \(169 = 0\text{b}\hspace{0.2em}1010\hspace{0.2em}1001\).
Käytä jakoyhtälöä
Isompien lukujen muuntamisessa kynällä paperille tai lukuja ohjelmallisesti muuntaessa saatat haluta tehdä lukumuunnoksen toistamalla jakoyhtälöä, kunnes osamäärä on 0.
Käytetään tässä esimerkkinä kuitenkin pientä lukua. Muunnetaan kymmenjärjestelmän luku 50 binääriluvuksi soveltamalla jakoyhtälöä. Jaetaan siis muunnettava luku kahdella, merkitään jakojäännös. Sitten jaetaan osamäärä kahdella ja merkitään jakojäännös. Tätä toistetaan, kunnes osamäärä on 0. Muunnosalgoritmissa ei tarvitse kirjoittaa oikeanpuoleista jakoyhtälöä. Ne ovat taulukossa mukana vain havainnollistamisen vuoksi.
Jakolasku | Osamäärä | Jakojäännös | Jakoyhtälö |
---|---|---|---|
50 : 2 | 25 | \(0\) | \(50=2\cdot 25+\mathbf{0}\) |
25 : 2 | 12 | \(1\) | \(25=2\cdot 12+\mathbf{1}\) |
12 : 2 | 6 | \(0\) | \(12=2\cdot 6+\mathbf{0}\) |
6 : 2 | 3 | \(0\) | \(6=2\cdot 3+\mathbf{0}\) |
3 : 2 | 1 | \(1\) | \(3=2\cdot 1+\mathbf{1}\) |
1 : 2 | 0 | \(1\) | \(1=2\cdot 0+\mathbf{1}\) |
Saimme lopulta jakolaskun osamääräksi luvun 0. Jos jakamista kahdella jatkettaisiin, saataisiin enää vain nollia, eikä se enää vaikuttaisi luvun suuruuteen. Nyt haluttu binääriluku saadaan valitsemalla jakojäännökset alhaalta ylös luettuna.
Siis \(50 = 0\text{b}110010\). Jos tämä luku haluttiin ilmaista vaikkapa 8-bittisenä lukuna, on lisättävä riittävä määrä nollia vasemmalle. Siten 8-bittisenä luku on \(0\text{b}\hspace{0.2em}0011\hspace{0.2em}0010\).
Miksi jakojäännökset valitaan alhaalta ylös? Muistisääntöjä:
- Huomaa, että ensin jaettiin luku kahdella ja saatiin jakojäännökseksi 0. Jos luku olisi pariton, jakojäännökseksi olisi tullut 1. Koska binääriluvun oikeanpuoleisin bitti ilmaisee ykkösiä, on parillisessa luvussa sen oltava 0 ja parittomassa 1.
- Lopussa osamäärä on 0. Jos jakamista kahdella jatkettaisiin, saataisiin enää vain nollia jakojäännökseksi. Alimpien jakojäännösten siis pitääkin olla luvussa vasemmanpuoleisina, etteivät ne vaikuta luvun suuruuteen.
Heksadesimaaliluvut
Heksadesimaaliluvut ovat 16-kantaisia lukuja. Koska 16-kantaisessa järjestelmässä tarvitaan 16 numeroa, on käytössä kirjaimet A – F kuvaamaan ”numeroita” 10 – 15. Niinpä numerot nollasta yhdeksään ovat samat, mutta: 10 = A, 11 = B, 12 = C, 13 = D, 14 = E ja 15 = F.
Kuten kymmenjärjestelmässä on kymmenen potenssit eli ykköset, kymmenet, sadat ja niin edelleen ja binäärijärjestelmässä kahden potenssit eli ykköset, kakkoset, neloset ja niin edelleen, niin heksadesimaalijärjestelmässä on luvun 16 potenssit eli ykköset, kuudettoista, kaksisataaviisikymmentäkuudet ja niin edelleen.
Numeron paikka siis ilmaisee, millä kantaluvun 16 potenssilla numero on kerrottava. Siten esimerkiksi
\[\begin{align*} 0\text{xA}95 \\ &= \text{A}\cdot 16^2 + 9\cdot 16^1 + 5 \cdot 16^0 \\ &= \text{A}\cdot 256 + 9\cdot 16 + 5\cdot 1 \\ &= 10\cdot 256 + 9\cdot 16 + 5\cdot 1 \\ &= 2560+144+5 \\ &= 2709 \end{align*}\]Tässä materiaalissa käytetään heksadesimaalilukujen edessä etuliitettä 0x. Sama etuliite on käytössä myös useissa ohjelmointikielissä, kuten Javassa, Pythonissa ja C:ssä.
# Python 3
elsa = 0xA95
// Java
int elsa = 0xA95;
Heksadesimaalilukujen muunnos kymmenjärjestelmään on siis suoraviivaista, vaikkakin isommissa luvuissa työlästä tehdä käsin. Kannattaa opetella muuttamaan päässälaskuna kuitenkin ainakin tavun eli 8 bitin kokoisia lukuja. Vasemmanpuoleinen numero kerrotaan luvulla 16 ja lisätään oikeanpuoleinen numero:
\[\begin{align*} 0\text{xCA} \\ &= \text{C}\cdot 16 + \text{A} \\ &= 12\cdot 16 + 10 \\ &=192+10 \\ &=202 \end{align*}\]Päässälaskuna tai paperille on hyödyllistä harjoitella muuntamaan myös toisin päin eli kymmenjärjestelmästä heksadesimaalijärjestelmään ainakin tavun mittaisia lukuja. Jos luku on tavun mittainen eli välillä 0…255, muunnos tehdään seuraavan esimerkin tavoin. Käytetään esimerkkinä lukua 179:
- Jaetaan luku 179 luvulla 16. Saadaan osamäärä 11 ja jakojäännös 3.
- Siten \(179 = 11\cdot 16 + 3 = \text{B}\cdot 16 + 3 = 0\text{xB}3.\)
Suurempien lukujen muuntaminen heksadesimaaliluvuksi tehdään jakoyhtälöä toistuvasti hyödyntäen samanlaisella algoritmilla kuin aiemmin kymmenjärjestelmän luvusta binääriluvuksi muuntaessa, mutta jakajana on luku 16 ja jakojäännöksien luvut 10…15 on muunnettava kirjaimiksi A…F. Algoritmin havainnollistamiseksi alla esimerkki:
# Python 3
def dec_to_hex(luku: int):
if luku < 0:
return None
heksanumerot = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
heksaluku = ""
osamaara = luku
while True:
jakojaannos = osamaara % 16
heksaluku += heksanumerot[jakojaannos]
osamaara = osamaara // 16
if osamaara == 0:
return "0x"+heksaluku[::-1]
# Huomaa käänteinen järjestys ::-1
print(dec_to_hex(2000000000))
Binääriluvusta heksadesimaaliluvuksi
Koska yksi heksadesimaalinumero vastaa 4 bittiä (\(0\text{x}0 = 0 = 0\text{b}0000\) ja \(0\text{xF} = 15 = 0\text{b}1111\)), on selvästi lyhyempää ilmaista binäärilukuja heksadesimaalimuodossa. Muuntaminen tapahtuu jakamalla binääriluku oikealta lukien neljän bitin osiin ja sen jälkeen muuttamalla nämä osat 4 bittiä kerrallaan kymmenjärjestelmän kautta heksadesimaaliluvuksi. Ei haittaa, jos bittejä ei ole neljällä jaollinen määrä, koska 4 bitin osiin jakaminen aloitettiin oikealta. Tässä esimerkki:
0b 1 1001 1101 1010 1001 0111 1 9 13 10 9 7 0x 1 9 D A 9 7 Saadaan heksadesimaaliluku 0x19DA97
Heksadesimaaliluvusta binääriluvuksi
Heksadesimaaliluvun muuntaminen binääriluvuksi tehdään muuttamalla heksadesimaaliluku numero (0…F) kerrallaan kymmenjärjestelmän luvun kautta binääriluvuksi. Sen voi tehdä vaikka kynällä paperille. Siis esimerkiksi näin:
0xCAB1729 0x C A B 1 7 2 9 12 10 11 1 7 2 9 0b 1100 1010 1011 0001 0111 0010 1001
Näin saatiin muutettua luku binäärilukumuotoon.