Position och modulus

Vad händer när timmen passerar 12?

Klockan visar 11. Tre timmar senare, vad visar den? Inte 14. Den visar 2. Vi räknar inte obegränsat uppåt, vi börjar om när vi passerar 12. Det är ett räknesystem med en gräns som återstartar, och det mönstret finns överallt: veckodagar, kompassriktningar, turordningen i ett spel, positionerna i ett alfabet.

Räknesättet bakom klockan heter modulus, och den har du mött förut: i Villkoret växer var det % som avgjorde om ett tal var jämnt eller udda. Då räckte det att veta om resten blev noll. Här är det resten i sig som gör jobbet. Modulus är det första av två verktyg i den här delen. Det andra är Index En heltalsposition som identifierar ett element i en lista. Indexering börjar alltid på noll. Negativa index räknar bakifrån: -1 är sista elementet. Se: Position och modulus , sättet att peka ut en bestämd plats i en sekvens. Var för sig är de små. Tillsammans löser de ett problem du snart står inför.

Modulus, resten som räknas

Operatorn % ger resten efter en heltalsdivision. Inte kvoten, resten. Du har sett den på tvåan, här är den på tal som går runt:

Editor

Redo.

Läs de fyra svaren tillsammans. 17 % 5 är 2, för fem går tre hela gånger med två över. 14 % 12 är 2, alltså klockan igen: fjorton timmar är ett varv plus två. 29 % 29 är 0, ett helt varv tillbaka till start. Och 31 % 29 är 2, ett varv och två steg.

Det tredje svaret är det viktigaste. När räkningen går exakt jämnt upp landar du på noll, alltså på första platsen igen. Det är hela mekanismen bakom allt som ska börja om.

Editor

Redo.

Klockan är 22 och något tar fem timmar. Utan modulus hade svaret blivit 27, ett klockslag som inte finns. % 24 kastar bort hela dygnsvarv och lämnar bara resten. Byt 24 mot 12 och kör igen: samma matematik, ett annat system.

Position, var något står i ordningen

Modulus blir användbar först när den får något att peka på. Det andra verktyget är index. En sträng är en sekvens av tecken, precis som en lista är en sekvens av element, och båda kan du peka in i med hakparenteser:

Editor

Redo.

Kör koden. Tre saker är värda att lägga märke till. alfabet[0] ger a, alltså börjar räkningen på noll och inte på ett. alfabet[3] ger d, den fjärde bokstaven. Och alfabet[-1] ger ö, för negativa index räknar bakifrån.

Sista raden skriver ut 29, längden på det svenska alfabetet. Att len() är 29 medan högsta index är 28 är ingen inkonsekvens, det följer av att räkningen börjar på noll.

Ibland vill du gå åt andra hållet: du har värdet och vill veta var det står. Då använder du .index():

Editor

Redo.

alfabet.index("d") svarar 3, alltså exakt det index du kan skicka tillbaka in i hakparenteserna. De två hör ihop: [] går från plats till värde, .index() går från värde till plats.

När räknaren växer men listan inte gör det

Nu står de två verktygen bredvid varandra, och här är problemet som får dem att höra ihop.

Ett spel har tre spelare som ska turas om, varv efter varv. Turen räknas uppåt: tur 1, tur 2, tur 3, tur 4. Listan har tre platser. Räknaren har ingen övre gräns.

Editor

Redo.

Kör koden. De tre första turerna fungerar, och på den fjärde stannar programmet med IndexError Uppstår när du försöker komma åt ett index som inte finns i listan. Se: Position och modulus . Det är inte ett slarvfel, det är två saker som inte går ihop: tur fortsätter växa, men spelare har bara platserna 0, 1 och 2.

Du kan inte hindra räknaren från att växa, den ska växa. Det du behöver är att få det växande talet att landa inom listans platser, och det är precis vad modulus gör.

Byt ut spelare[tur] mot spelare[tur % len(spelare)] och kör igen:

Editor

Redo.

Sju turer fördelas på tre spelare, och efter Cem är det Alva igen. tur växer hela tiden, men tur % len(spelare) blir aldrig större än 2, alltså alltid ett giltigt index. Modulus håller räkningen inne, index plockar ut rätt spelare.

Lägg till en fjärde spelare i listan och kör igen. Turordningen anpassar sig utan att du rör loopen, för len(spelare) frågar listan varje gång i stället för att lita på ett tal du skrivit in för hand.

Håll kvar den bilden. I milstolpen är alfabetet listan, bokstavens position är räknaren, och nyckeln är det som får den att växa förbi kanten.

Uppgift: Turordningen

Skapa filen turordning.py.

  1. Skapa en lista med tre spelare och skriv ut den första och den sista spelaren, utan att skriva in någon siffra för hand i den sista utskriften.

  2. Skriv en loop som kör tio turer och skriver ut vems tur det är, med modulus mot listans längd.

  3. Bygg ut loopen så att var femte tur också skriver ut “Bonusrunda!“. Använd modulus även här.

  4. Lägg till en fjärde spelare i listan och kör om programmet utan att ändra något annat.

  5. Gå till Source Control-panelen i VS Code, stagea filen, skriv ett meningsfullt commit-meddelande och pusha.

Vad händer om

Du byter ut % len(spelare) mot % 3 och sedan lägger till en femte spelare. Kör programmet och beskriv exakt vad som händer med den femte spelaren, och vilken av de tre feltyperna det är.

Motivera & reflektera

Motivera varför turordningen fungerar för hur många turer som helst trots att listan bara har några få platser. Vad är det modulus gör med talet innan det används som index?

Nästa nivå

Skriv ett litet tidszonsprogram. Användaren anger klockslaget i Sverige och hur många timmars skillnad det är till en annan plats, till exempel -6 för New York eller +8 för Tokyo, och programmet svarar med den lokala tiden där.

Testa särskilt två fall: ett som passerar midnatt framåt, och ett negativt som går bakåt förbi midnatt. Vad ger (2 - 6) % 24 i Python, och varför är det svaret rätt trots att uträkningen på vägen blir negativ?