Tiedon kategoriat, binääri- ja heksadesimaalijärjestelmät, monitavuisen tiedon tallennus
Tietokoneen käsittelemät tiedot voidaan jakaa (ainakin) kolmeen eri kategoriaan. Ensinnäkin meillä on ihmisen kanssa kommunikointiin käytettävä tieto. Sellaisiin sisältyy teksti, jota voi lukea normaaliin tapaan tai tunnustella pistekirjoitusnäytöltä. Myös ääni, kuvat ja video ovat tällaista ihmiselle sopivaa tietoa. Toki tietokonekin pystyy käsittelemään tällaista tietoa.
Toisena ääripäänä on suorittimen ymmärtämä tieto. Se on hyvin jäsenneltyä ja yleensä hyvin pienimuotoista, yhden konekäskyn käsiteltävissä olevaa tietoa. Suorittimen ymmärtämät tietotyypit vaihtelevat eri suorittimilla, mutta usein niihin sisältyvät kokonaisluvut, liukuluvut, merkit ja merkkijonot sekä totuusarvot. Huomaa, että ihmisen ymmärtämä teksti-kategoria voi tarkoittaa suorittimen tasolla näitä kaikkia edellä mainittuja, koska tavallisilla kirjaimilla voidaan kuvata kaikkia em. tietotyyppejä. Tärkeä suorittimen ymmärtämä tietotyyppi on myös sen oma konekäskykanta. Tämä heijastaa tietokoneessa muutenkin selkeää jakoa koodin ja datan välillä. Koodi antaa käskyt, jotka käsittelevät dataa.
Kolmas kategoria on järjestelmän sisäiset tietotyypit. Ne määrittelevät, mitä tietoa ja missä muodossa sitä talletetaan keskusmuistiin tiedon käsittelyä varten. Niihin sisältyvät kaikki suorittimen ymmärtämät tietotyypit, joita voidaan sellaisenaan käsitellä konekäskyillä. Niihin sisältyy myös kaikki muu tieto, jota järjestelmässä suorittavat ohjelmat käsittelevät. Tämä voi olla esimerkiksi kuvia, ääniä, sormenjälkiä tai hajuja. Niitä ei voi suoraan käsitellä konekäskyllä, vaan niiden käsittely tapahtuu aliohjelmilla, joiden toiminta perustuu em. tietotyyppien standardoituihin tai itse keksittyihin esitysmuotoihin. Yleensä esitysmuodot ovat sovittuja koodaustapoja kokonaislukuja, liukulukuja tai tekstiä käyttäen. Samalla tiedolla (esim. kuvalla) voi olla erikseen järjestelmän sisäinen esitysmuoto (esim. kissakuva.jpg), joka sitten muutetaan ihmiselle sopivaan muotoon (visuaalisesti soma kuva kissasta näytöllä) tarvittaessa.
Binäärijärjestelmä
Kaikki tieto esitetään tietokoneessa loppujen lopuksi binäärijärjestelmän numeroina eli bitteinä. Miksi bitteinä eikä esimerkiksi desimaalijärjestelmän numeroina? Bitit on helppo toteuttaa digitaalipiireillä ja digitaalipiirejä on helppo käsitellä matemaattisesti Boolen algebran avulla.
110110112 = 27+26+24+23+21+20 = 128+64+16+8+2+1 = 219 21910 = 2*102+1*101+9*100 = 200+10+9 = 219
11011011.101012 = 27 + 26 + 24 + 23 + 21 + 20 + 2-1 + 2-3 + 2-5 = 128 + 64 + 16 + 8 + 2 + 1 + 0.5 + 0.125 + 0.03125 = 219.65625 219.6562510 = 2*102+1*101+9*100+6*10-1+5*10-2+6*10-3 + 2*10-4 + 5*10-5 = 200 + 10 + 9 + 0.6 + 0.05 + 0.006 + 0.0002 + 0.00005 = 219.65625
Esitysmuodon muunnos desimaalijärjestelmästä binäärijärjestelmään
Esitysmuotojen muunnokset binäärijärjestelmän ja desimaalijärjestelmän välillä ovat triviaaleja. Edellä esitettiinkin jo, kuinka binäärijärjestelmän luku muutetaan desimaalijärjestelmän luvuksi. Muunnos toiseen suuntaan on vain vähän monimutkaisempi.
Esimerkki: Mikä on 5710 binäärilukuna? 57/2 = 28 jakojäännos 1 28/2 = 14 jakojäännös 0 14/2 = 7 jakojäännös 0 7/2 = 3 jakojäännös 1 3/2 = 1 jakojäännös 1 1/2 = 0 jakojäännös 1 joten 5710 = 1110012
Desimaaliosan muunnos tehdään kertomalla desimaaliosa kahdella (2), ottamalla tuloksen kokonaisosa (0 tai 1) talteen seuraavana binääriosan numerona, ja toistamalla tätä (pelkän desimaaliosan kertomista kahdella) tarpeeksi monta kertaa. Algoritmi päättyy, jos desimaaliosaksi tulee nolla (0.0), koska sen jälkeen tilanne ei muutu mihinkään. Usein algoritmi ei pääty koskaan, koska kaikilla desimaaliluvuilla ei ole täsmällistä vastinetta binäärijärjestelmässä. Tällöin tyydytään etukäteen määriteltyyn tarkkuuteen binääriosan numeroiden lukumäärän suhteen. Esimerkiksi voidaan jo alkuaan sopia, että otetaan korkeintaan 30 numeroa mukaan binääriosaan, jolloin binääriluvun tarkkuus vastaa noin 9 desimaalinumeron tarkkuutta.
Esimerkki: Mikä on 0.187510 binäärilukuna?
0.1875 * 2 = 0.375 = 0 + 0.375 0.375 * 2 = 0.75 = 0 + 0.75 0.75 * 2 = 1.5 = 1 + 0.5 0.5 * 2 = 1.0 = 1 + 0.0 joten 0.187510 = 0.00112
Esimerkki: kokonaisosan etunollat ja binääriosan loppunollat
57.187510 = 111101.00112 = 00111101.001100002 = 111101.0011000000000000000002
Jos desimaaliluvulla ei ole täsmällistä binäärilukuvastiketta, likiarvon laskeminen pitää lopettaa sitten kun numeroita on tarpeeksi haluttuun laskentatarkkuuteen.
Esimerkki: Mikä on 0.110 binäärilukuna? 0.1 * 2 = 0.2 = 0 + 0.2 0.2 * 2 = 0.4 = 0 + 0.4 0.4 * 2 = 0.8 = 0 + 0.8 0.8 * 2 = 1.6 = 1 + 0.6 0.6 * 2 = 1.2 = 1 + 0.2 0.2 * 2 = 0.4 = 0 + 0.4 0.4 * 2 = 0.8 = 0 + 0.8 0.8 * 2 = 1.6 = 1 + 0.6 0.6 * 2 = 1.2 = 1 + 0.2 0.2 * 2 = 0.4 = 0 + 0.4, jne. Nyt, 0.110 = 0.0001100110011..2 = 0.000112
Edellä olevissa esimerkeissä on vähän erikoista esitystavasta aiheutuva esitystarkkuuden muutos. Alkuperäisessä luvussa 57.187510 oli 6 desimaaliluvun tarkkuus, mutta sitä vastaavassa binääriesityksessä 111101.0011000000000000000002 näyttää olevan 27 binäärinumeron tarkkuus, vaikka oikeasti tarkkuus on sama (noin 20 binäärinumeroa) kuin desimaaliluvussakin. Lopussa olevat 0-bitit voivat oikeasti olla mitä vain. Toisessa esimerkissä desimaaliluvun 0.110 tarkkuus on vain yksi desimaalinumero, kun taas sen 30-numeroinen binääriesitys 0.0001 1001 1001 1001 1001 1001 1001 102 näyttää kovin täsmälliseltä, vaikka senkään oikea tarkkuus ei oikeasti ole yhtään parempi kuin lähtötiedon 0.110 tarkkuus (noin 3 binäärinumeroa).
Tietokoneille on tyypillistä, että esitystavan vuoksi lukujen tarkkuus näyttää olevan parempi kuin todellisuudessa onkaan. Jos data talletetaan 32-bittisenä, siellä on aina 32-bittiä tietoa, vaikka osa niistä olisikin puppua! Laskennan lopputulos on todellisuudessa aina korkeintaan yhtä tarkka kuin alkuperäiset operandit, ja yleensä epätarkempi. Ei siis pidä sokeasti luottaa tietokoneiden antamiin lopputuloksiin.
Heksadesimaalijärjestelmä
Bittien informaatioarvo on pieni, joten niitä tarvitaan paljon. Niiden kirjoittaminen ja lukeminen on ihmiselle jonkin verran virhealtista, joten yleensä ne esitetään 16-järjestelmän (heksadesimaalijärjestelmän) avulla.
Heksadesimaalijärjestelmän numerot ovat lukuarvoltaan 0-15, ja ne ovat 0-9, A, B, C, D, E ja F. Numeroiden A-F lukuarvot ovat 10-15. Luvun A4B arvaa aika helposti esittävän 16-järjestelmän lukua, mutta esimerkiksi luvun 345 kohdalla voi helposti tulla sekaannus käytössä olevasta lukujärjestelmästä. Tämän vuoksi tapana on kirjoittaa 16-järjestelmien luvuille etuliite 0x. Esimerkiksi, desimaaliluvulla 837 on sama arvo kuin heksadesimaaliluvulla 0x345.
3*162 + 4*16 + 5 = 3*256 + 4*16 + 5 = 768 + 64 + 5 = 837
Kukin 16-järjestelmän numero vastaa neljää bittiä ja ne ryhmitellään aina oikealta vasemmalle ennen binääripistettä ja vasemmalta oikealle sen jälkeen. Ryhmittelyssä binäärilukuihin laitetaan sopivasti etunollia kokonaisosan eteen ja binääriosan loppuun, jotta bittien lukumäärä molemmissa olisi neljällä jaollinen.
Esimerkiksi, 32-bittinen luku 0000 0101 0111 1010 on helpompi kirjoittaa muodossa 0x057A. Esitysmuodon muutokset binääri- ja heksadesimaalijärjestelmien välillä ovat triviaaleja. Kukin neljän bitin ryhmä vastaa heksadesimaaliarvoa välillä 0-F (eli 0-15), ja kukin heksadesimaalijärjestelmän numero on helppo vastaavasti purkaa biteiksi. Bittiesityksestä voi poistaa kokonaisosan etunollia ja binääriosan loppunollia halutessaan, tai laittaa niitä lisää.
Esimerkki: Muunnokset binääri- ja heksadesimaaliesitysten välillä binääri: 0100 0111 1001 1010 1111.0100 heksad.: 4 7 9 A F . 4 eli 0x479AF.4 = 479AF.416 heksad.: 0x120ADF.C8 = 1 2 0 A D F . C 8 binääri: 0001 0010 0000 1010 1101 1111.1100 1000 = 1 0010 0000 1010 1101 1111.1100 1
Kukin 16-järjestelmän numero vastaa siis neljää bittiä. Nyt yhden tavun bitit (8 bittiä) voidaan ilmaistaan (kirjoittaa näkyville) kahdella heksadesimaalinumerolla. Esimerkiksi tavun sisältö 0x62 tarkoittaa, että tavun bitit ovat vasemmalta oikealle 0110 0010. Nämä bitit voivat esittää esimerkiksi kokonaislukua +98, merkkiä 'a' tai operaatiokoodia ADD tulkintatavasta riippuen.
On tärkeätä muistaa, että samat bittiyhdistelmät voivat tarkoittaa ihan eri asioita riippuen siitä, miten niitä käsitellään tai halutaan tulkita. Konekielessä on omia konekäskyjä raakadatan (bitit ilman merkitystä) käsittelyyn (esim. SHL eli siirrä bittejä vasemmalle) ja omia konekäskyjä tiettyjen tietotyyppien käsittelyyn (esim. ADD eli kokonaislukujen yhteenlasku). Viimeksi mainitut perustuvat tietotyyppien sovittuihin esitysmuotoihin, joihin tutustumme seuraavassa aliluvussa. Minkä tahansa tietotyypin esitysmuodossa olevaa tietoa voidaan käsitellä kuitenkin myös raakadatana pelkkinä bitteinä siihen tarkoitukseen sopivilla konekäskyillä.
Monitavuinen tieto muistissa
Tallennuksen yksikkö on yksi tavu, mutta muistissa tietoa talletetaan 32-bittisinä sanoina. Merkkijonot talletetaan muistiin peräkkäisiin tavuihin, jotka ovat peräkkäisissä sanoissa. Olisi luontevaa, että tavut talletettaisiin samassa järjestyksessä kuin me ihmiset olemme oppineet niitä käsittelemään. Siten esimerkiksi lukua 1350 tarkoittava merkkijono "1350" talletettaisiin muistiosoitteeseen 0x1A0 siten, että merkki '1' on tavussa 0x1A0, merkki '3' tavussa 0x1A1, merkki '5' tavussa 0x1A2 ja lopulta merkki '0' tavussa 0x1A3. Tällainen monitavuisen tiedon sanan (tai kaksoissanan) sisäinen talletusmuoto on nimeltään Big-Endian koska lukuarvoltaan eniten merkitsevä tavu on ensimmäisenä. Näin ei kuitenkaan tietokoneessa aina tehdä. Toisen talletusmuodon Little-Endian mukaan sanassa vähiten merkitsevä tavu laitetaan ensimmäiseksi, jolloin kyseiset tavut tulevat tavallaan käänteisessä järjestyksessä muistiin. Tiedon osoite on joka tapauksessa sen muistissa olevan ensimmäisen tavun osoite.
Esimerkki: Talleta merkkijono "autotie" muistiin osoitteeseen 0xA10, eli tavuihin 0xA10, 0xA11, 0xA12, 0xA13. Merkkijonon lopetusmerkki on '\0'. Tavujen järjestys vaihtelee, mutta vain yhdessä sanassa kerrallaan. Big-Endian: 'a' 'u' 't' 'o' 't' 'i' 'e' '\0' tavuosoite 0xA10 0xA11 0xA12 0xA13 0xA14 0xA15 0xA16 0xA17 Little-Endian: 'o' 't' 'u' 'a' '\0' 'e' 'i' 't'
Esimerkki: Talleta luku 0x11223344 (287454020) muistiin osoitteeseen 0x1200 eli tavuihin 0x1200, 0x1201, 0x1202 ja 0x1203. Big-Endian: 0x11 0x22 0x33 0x44 tavuosoite 0x1200 0x1201 0x1202 0x1203 Little-Endian: 0x44 0x33 0x22 0x11
Tietokoneen kannalta tällä ei ole paljoa merkitystä, kunhan vain tavujen järjestys on etukäteen sovitun mukainen. Yleisesti ottaen suorittimen suunnittelija tekee tämän päätöksen ja sitten ALU-operaatiot tehdään toimivaksi sen mukaisesti. Big-Endian'issa on se etu, että me ihmiset olemme tottuneet siihen. Little-Endian'issa etuna on, että monitavuisen tiedon lyhyempien esitysmuotojen osoite on aina sama kuin alkuperäisenkin datan.
Esimerkki: Talleta luku 0x35 = 0x00000035 muistiin osoitteeseen 0x1200 (tavut 0x1200, 0x1201, 0x1202, 0x1203) Big-Endian: 0x00 0x00 0x00 0x35 tavuosoite 0x1200 0x1201 0x1202 0x1203 Little-Endian: 0x35 0x00 0x00 0x00 Big-Endian'issa luvun 35 sanan osoite on 0x1200, puolikassanan (2 tavua) 0x1202 ja tavun 0x1203. Little-Endian'issa luvun 35 sanan osoite on 0x1200, puolikassanan 0x1200 ja tavun 0x1200.
Joissakin suorittimissa ovat molemmat monitavuisen tiedon esitystavat käytössä. ALU-piirit tietenkin tekevät toimensa vain yhdellä esitystavalla, jolloin operandien ja tuloksen tavut käännetään eri järjestykseen tarvittaessa. Suorituksessa oleva ohjelma ilmoittaa, kumpaa järjestystä käytetään. Voi myös olla, että etuoikeutetussa tilassa laskettaessa käytetään aina jotain tiettyä tavujen järjestystä.
Tämä on tyypillinen ongelma myös siirrettäessä tietoa verkon ylitse. Verkkoprotokollat (sovitut käytännöt tietoliikenteen toteuttamiseen) tietävät lähettäjän ja vastaanottajan käyttämät monitavuisen tiedon esitystavat, ja kääntävät tavut oikeaan järjestykseen tarvittaessa.
Muistathan tarkistaa pistetilanteesi materiaalin oikeassa alareunassa olevasta pallosta!