CMD + K
IKT-teori: maskinvare, digital representasjon og Git (TDT4109)
Bak all programvare ligger maskinvare og tallsystemer. Vi ser hvordan bits og bytes representerer tall (binær og heksadesimal) og tekst, hvordan CPU, RAM og lager samarbeider, og hvordan Git versjonshåndterer kode med commit og push. Dette stoffet er ensidig for TDT4109.
- 01Forklare arbeidsdelingen mellom CPU, RAM og lager, og begrunne hvorfor minnehierarkiet bytter hastighet mot kapasitet og varighet
- 02Konvertere et tall mellom binær, heksadesimal og desimal form og forklare hvorfor én byte tilsvarer to hekssiffer
- 03Beskrive hvordan tekst representeres som tall via ASCII/Unicode, og knytte det til at all data til slutt er byter
- 04Forklare hva en commit er og redegjøre for flyten git add → git commit → git push gjennom arbeidsmappe, scene og repositorium
> Hele dette kapittelet hører til TDT4109. IKT-teori — maskinvare, digital representasjon og versjonskontroll — er en egen del av 4109-pensum og testes på eksamen der.
Maskinen under programmet
Når du kjører et Python-program, er det lett å tro at koden «bare skjer». Men hver eneste linje du skriver, ender til slutt opp som signaler i fysisk maskinvare. Tenk på et helt vanlig uttrykk: x = 2 + 3. Tallene 2 og 3 må lagres et sted, addisjonen må utføres et sted, og resultatet 5 må legges et sted igjen. «Et sted» er ikke ett sted — det er tre forskjellige deler av maskinen, og forskjellen mellom dem forklarer hvorfor noen operasjoner er lynraske og andre tar evigheter.
Den delen som faktisk regner, er cpu. Den henter instruksjoner, tolker dem, og utfører aritmetikk og logikk — milliarder av ganger i sekundet. Men CPU-en har nesten ingen plass til å lagre noe selv. Den jobber mot ram, et hurtig arbeidsminne som holder data og kode mens programmet kjører. RAM er flyktig: skru av strømmen, og alt er borte. Derfor trenger vi et tredje lag — lager, altså harddisk eller SSD, som beholder data permanent.
Hierarkiet er styrt av en ubønnhørlig avveining: jo raskere minne, desto dyrere og mindre av det. CPU-registre er superraske men bittesmå. RAM er raskt og romslig nok for én økt. Lager er tregt men enormt og permanent. Et tilgangsmønster der CPU-en venter på lageret i stedet for RAM, kan være tusenvis av ganger langsommere — det er derfor det er så viktig å forstå hvor data faktisk ligger.
La oss følge x = 2 + 3 gjennom maskinen. Når programmet starter, leses koden fra lageret inn i RAM. CPU-en henter så instruksjonen «legg sammen» fra RAM, kopierer tallene 2 og 3 inn i sine egne registre, utfører addisjonen i regneenheten (ALU-en), og skriver 5 tilbake til en plass i RAM. Skriver du 5 til en fil med open(...), vandrer verdien helt ned til lageret og overlever at maskinen slås av. Hvert hopp nedover i hierarkiet koster tid, og en dyktig programmerer prøver å holde de dataene som brukes ofte, så høyt oppe som mulig.
Tallene som beskriver maskinens kapasitet, følger totallsystemet. Én kilobyte er strengt tatt 1024 byte (2^10), ikke 1000, fordi minneadresser telles binært. En megabyte er 1024 kilobyte, og en gigabyte er 1024 megabyte. Det er derfor en «500 GB» disk ofte viser litt mindre i operativsystemet enn på esken — produsenten regner med tusentall, mens maskinen regner med 1024.
Hvorfor binært
Når et tall skal lagres i denne maskinen, lagres det ikke som siffer på et ark. Det lagres som tilstander i transistorer: strøm eller ikke strøm, høy eller lav spenning. Det finnes bare to stabile tilstander, og derfor regner maskinen i totallsystemet.
Den minste enheten er én bit — et siffer som enten er 0 eller 1. Én bit alene sier lite, så vi grupperer dem. Åtte bits utgjør én byte, og én byte kan representere 256 ulike verdier (2^8 = 256). En byte er nok til ett tegn i den klassiske tegnkodingen, eller et heltall mellom 0 og 255.
Et tall skrevet i binær form leses akkurat som desimaltall, men med base 2 i stedet for base 10. Der desimaltallet 213 betyr 2·100 + 1·10 + 3·1, betyr binærtallet 11010101 summen 128 + 64 + 0 + 16 + 0 + 4 + 0 + 1. Hver posisjon er en dobling av den forrige: 1, 2, 4, 8, 16, 32, 64, 128. Legg sammen posisjonene som har et ett-tall, og du har desimalverdien.
python# Python kan oversette mellom basene for deg tall = 213 print(bin(tall)) # 0b11010101 — binær print(hex(tall)) # 0xd5 — heksadesimal print(int("11010101", 2)) # 213 — fra binær tilbake til desimal
Binære tall blir fort lange og uleselige. Derfor bruker vi heksadesimal notasjon som en kortform. Heksadesimal har base 16, med sifrene 0–9 og deretter a–f for verdiene 10–15. Det fine er at akkurat fire bits tilsvarer nøyaktig ett heksadesimalt siffer. Byten 11010101 deles i 1101 og 0101, som blir d og 5 — altså 0xd5. Én byte blir alltid to hekssiffer, og det gjør hex til programmererens foretrukne måte å lese rå data på.
Fra tall til tekst
Så langt har vi bare snakket om tall, men en maskin som bare kan lagre tall, må også representere bokstaver som tall. Det gjøres med en tegnkoding. Den eldste utbredte er ASCII, der hver bokstav, hvert siffer og hvert skilletegn får et tallnummer mellom 0 og 127. Den store A er 65, liten a er 97, og sifferet 0 er 48. Maskinen lagrer altså ordet Hei som tre tall — 72 101 105 — som igjen er tre byter med bits.
pythonprint(ord("A")) # 65 — tegn til tallkode print(chr(72)) # 'H' — tallkode til tegn print([ord(t) for t in "Hei"]) # [72, 101, 105]
ASCII holder for engelsk, men ikke for æ, ø og å. Derfor bruker moderne systemer Unicode med kodingen UTF-8, som kan representere alle verdens tegn og samtidig er bakoverkompatibel med ASCII for de første 128 tegnene. Poenget for IKT-teorien er prinsippet: alt — tall, tekst, bilder, lyd — koker til slutt ned til byter, og byter er bare grupper av bits.
Det samme prinsippet forklarer noe du møter konstant som programmerer: hvorfor 0.1 + 0.2 ikke gir nøyaktig 0.3 i Python. Desimaltall lagres binært, og akkurat som 1/3 ikke kan skrives eksakt med endelig mange desimaler, kan 0.1 ikke skrives eksakt med endelig mange binærsiffer. Maskinen runder av, og de små avrundingsfeilene hoper seg opp. Dette er ikke en feil i Python — det er en direkte konsekvens av at maskinen tenker i toer-potenser, og det er nettopp den slags innsikt IKT-teorien skal gi deg.
Versjonskontroll: hvorfor Git finnes
Skift nå perspektiv fra maskinen til arbeidsflyten. Du skriver et program over flere uker. Du gjør en endring som ødelegger noe, og vil tilbake til hvordan det var i går. Du jobber sammen med en medstudent, og dere redigerer den samme fila samtidig. Du vil prøve en risikabel idé uten å miste den fungerende versjonen. Alle disse problemene løses av versjonskontroll, og verktøyet alle bruker, er git.
Git tar «øyeblikksbilder» av prosjektet ditt. Hvert øyeblikksbilde kalles en commit, og hver commit har en unik identifikator, en melding som beskriver hva du gjorde, og en peker til commit-en før. Dermed bygger commit-ene en sammenhengende historie du kan vandre fram og tilbake i. Mister du noe, kan du hente det tilbake; ødelegger du noe, kan du se nøyaktig hvilken endring som gjorde det.
For å forstå Git må du forstå at koden din lever i tre soner. Først arbeidsmappen, der du faktisk redigerer filene. Så «scenen» (staging area / index), et venterom for endringer du har bestemt skal være med i neste commit. Til slutt selve repositoriet, der commit-ene lagres permanent. En endring må vandre gjennom alle tre: fra arbeidsmappe, til scenen, til repositoriet.
Det er nettopp dette KommandoEt typisk Git-forløp fra redigering til delt server gjør, steg for steg. Du redigerer en fil. git add legger den på scenen. git commit fryser scenen til et permanent øyeblikksbilde med en beskjed. git push sender commit-ene dine opp til en delt server, for eksempel GitHub, slik at medstudenten din kan hente dem ned med git pull. Underveis bruker du git status for å se hva som er endret og hva som ligger på scenen, og git log for å lese historikken.
To kommandoer fortjener spesiell oppmerksomhet fordi nybegynnere blander dem. git add flytter endringer til scenen, men lagrer ingenting permanent — glemmer du å committe, finnes endringen bare i arbeidsmappen din. Og git commit lagrer lokalt på din egen maskin; ingenting deles med andre før du kjører git push. En commit uten push er som et notat du har skrevet men aldri sendt.
En god commit-melding er kort og forklarer hvorfor endringen ble gjort, ikke bare hva. Skriver du git commit -m "fiks", sier du ingenting til deg selv om tre uker. Skriver du git commit -m "Retter avrundingsfeil i rentekalkulatoren", kan du lese loggen som en historie over prosjektet. Det er denne loggen som gjør Git verdifull: den lar deg svare på spørsmålet «hvorfor ser koden slik ut?» lenge etter at du har glemt det selv.
Det siste byggeklossen du trenger å kjenne til, er branch (gren). En branch lar deg jobbe på en risikabel idé i en egen kopi av historien, uten å røre den fungerende versjonen. Når ideen virker, fletter du grenen tilbake; viser den seg verdiløs, kaster du den. Dette er ryggraden i hvordan større prosjekter — og hele bransjen — samarbeider om kode uten å tråkke i hverandres arbeid.
Hvorfor IKT-teorien henger sammen
Det kan virke som om binære tall og Git hører til to ulike verdener, men de deler en kjerneidé som går igjen i hele informatikken: abstraksjon i lag. CPU, RAM og lager skjuler transistorene for deg. Heksadesimal skjuler de rå bitene. ASCII og Unicode skjuler tallene bak teksten. Git skjuler de rå øyeblikksbildene bak enkle kommandoer som add, commit og push. Hvert lag lar deg jobbe uten å tenke på laget under — helt til noe går galt, og da er det nettopp forståelsen av laget under som lar deg løse problemet. Det er denne forståelsen TDT4109 vil at du skal ha med deg.
Mine notater
Skriv egne notater for dette kapittelet. De lagres automatisk og dukker opp i «Mine notater»-oversikten paa fag-siden.