Skip to main content Link Menu Expand (external link) Document Search Copy Copied

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.

Binäärilukumuunnostaulukko

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:

Binäärilukumuunnos -esimerkki

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:

Tyhjä tavutaulukko

Muunnetaan nyt luku 169 binääriluvuksi. Suurin kahden potenssi, mikä mahtuu lukuun 169 on 128. Merkitään luvun 128 alle bitti 1:

Tavutaulukko 128

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.

Tavutaulukko 128+32

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.

Tavutaulukko 128+32+8

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:

Tavutaulukko 128+32+8

Nyt muunnostaulukko on täytetty ja nähdään, että \(169 = 0\text{b}\hspace{0.2em}1010\hspace{0.2em}1001\).

Binääriluvun pituus on huomioitava: Esimerkissä muunnettiin luku 169 binääriluvuksi. Lopputuloksena saatiin 8-bittinen luku. Jos luku pitäisi ilmaista vaikkapa 16-bittisenä, luvun vasemmalle puolelle pitää lisätä riittävä määrä nollia. Niinpä luku 169 on esimerkiksi 16-bittisenä 0b 0000 0000 1010 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:

  1. Jaetaan luku 179 luvulla 16. Saadaan osamäärä 11 ja jakojäännös 3.
  2. 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
Huomioi luvun pituus: Esimerkissä muunnettiin luku 0b 1 1001 1101 1010 1001 0111 heksadesimaaliluvuksi. Lopputuloksena saatiin 24-bittinen luku 0x19DA97. Jos luku pitäisi ilmaista vaikkapa 32-bittisenä, luvun vasemmalle puolelle pitää lisätä riittävä määrä nollia. Niinpä luku 0x19DA97 on esimerkiksi 32-bittisenä 0x0019DA97.

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.

Huomioi luvun pituus: Esimerkissä muunnettiin luku 0xCAB1729 binääriluvuksi. Lopputuloksena saatiin 28-bittinen luku. Jos luku pitäisi ilmaista vaikkapa 32-bittisenä, luvun vasemmalle puolelle pitää lisätä riittävä määrä nollia. Niinpä luku 0xCAB1729 on esimerkiksi 32-bittisenä 0b 0000 1100 1010 1011 0001 0111 0010 1001.

Copyright © 2021 Harri Kähkönen. (Github: epicharri)