Mer om loopar, vektorer

Laborationen ger träning på grundläggande programmering, repetitionssatser, villkorssatser, vektorer.
Här finns en ledning (PDF) som jag brukade föreläsa, men pga ny lab på den mindre kursen så föreläser jag nu ett annat exempel.

Introduktion:
På mat-filen /chalmers/groups/thomas_math/MATL/pie.mat (en mat-fil innehåller data i Matlabs eget binära format) hittar du två vektorer, pi5 samt e5, med de 5000000 första siffrorna i pi respektive e.

Under Linux: Om du enkelt vill kunna läsa in filen utan att byta katalog (med cd-kommandot), kan du skapa en mjuk länk till filen, så här.
Gå till den katalog där du arbetar med Matlab. Skapa den mjuka länken (tänk alias eller pekare) genom att i ett terminalfönster ge kommandot:

ln -s /chalmers/groups/thomas_math/MATL/pie.mat

Du kan då referera till pie.mat (som "pekar" på, är ett alias för, /chalmers/groups/thomas_math/MATL/pie.mat). Matlab-kommandot load pie läser in variablerna från filen.

Under Windows hittar du filen i katalogen: \\sol.ita.chalmers.se\groups\thomas_math\MATL

Tänk på att du har att göra med rätt stora datamängder. Du vill t.ex. inte skriva ut vektorerna. Även om du packar sifrorna tätt (inte skriver ut en kolonnvektor, ett tal per rad), utan skriver 91 siffror per rad och 67 rader per sida och skriver med rätt litet typsnitt (10 punkters Courier) så krävs 1640 A4-sidor. Om du vill inspektera en del av vektorn i Matlab, skriv t.ex.

>> pi5(1:32)'  % ' = transponat
ans =
  Columns 1 through 16
     3     1     4     1     5     9     2     6     5     3     5     8     9     7     9     3
  Columns 17 through 32
     2     3     8     4     6     2     6     4     3     3     8     3     2     7     9     5

>> pi5(1000000:1000005)  % siffror nummer 1000000 till och med 1000005
ans =
     5
     1
     3
     0
     9
     2

>> pi5(end-5:end)'  % de sex sista siffrorna
ans =
     4     6     1     9     7     1

>> e5(1:16)'        % analogt för e
ans =
     2     7     1     8     2     8     1     8     2     8     4     5     9     0     4     5

Anledningarna till att jag har gett dig så stora datamängder, är bland andra:

Lite matematik:

Ett tal är normalt (med avseende på en given bas, i denna lab har vi basen 10) om varje siffra (dvs. något av talen 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) förekommer med ungefär samma relativa frekvens (1 / 10, för decimala tal). Man vet inte (enligt denna MathWorld-artikel) huruvida pi och e är normala tal, så din uppgift kommer att vara att undersöka de 5000000 första siffrorna i pi och e för att forma en hypotes. Verkar pi och e vara normala?

Vi vill undersöka ytterligare några egenskaper.

>> pi5(710100:710108)'  % sju treor i rad
ans =
     7     3     3     3     3     3     3     3     8

Man undrar då kanske:


Nu till uppgifterna:

Lös uppgifterna nedan genom att skriva Matlabfunktioner. När man skapar en funktioner är det viktigt att fundera över vilka in- och utparametrar funktionen skall ha. Man måste också fundera på vilka datastrukturer som skall användas (vektorer, skalärer etc).

I den första deluppgiften vill man givetvis kunna använda samma funktion för både pi5 och e5 (och för andra decimalutvecklingar). Man bör undvika att hårdkoda, som man säger, värden i funktionen. Det är t.ex. olämpligt om antalet siffror, 5000000, står explicit i funktionen för då fungerar den inte om man har annan längd på indatavektorn. Man bör också fundera över hur man skall förpacka resultatet (frekvenserna i detta fall).

Eftersom vi rör oss med rätt stora datamängder är det viktigt att funktionen är effektiv. Så, skall man räkna ut alla tio frekvenserna i ett svep eller skall man räkna ut frekvensen för en enstaka siffra? Vad är mest användbart för användaren av funktionen, ett anrop eller tio anrop?

För att underlätta rättningen så vill jag att du också tillhandahåller huvudprogram, lab2a.m, där du anropar dina funktioner. Man skall bara behöva skriva lab2a för att hela denna lab skall köras.

Problem
Skriv en Matlabfunktion som räknar ut frekvenserna för siffrorna 0-9 i pi5 (eller e5). Kommentara beräkningsresultatet? Det skall räcka att anropa funktionen en gång för att få ut alla resultat. Man anropar lämpligen funktionen från ett huvudprogram som sköter utskrifter och liknande.
 
Om du vill (frivilligt) kan du studera följande kvantitet. Låt f(n, d) vara antalet gånger siffran d förekommer bland de n första siffrorna i talet. Plotta f(n, d) / n (för olika d). Detta liknar ett gränsvärde, relativa andelen när antalet siffror ökar. Gränsvärdet är 0.1 om talet är normalt.


Problem
Skriv en Matlabfunktion som räknar ut längsta sekvensen av siffran d, när d = 0, 1, ..., 9. Programmet skall också tala om var i talet (pi5 eller e5) dessa längsta sekvenser finns. I exemplet ovan finns siffran tre, sju gånger i rad. Denna sekvens hittar man från siffra 710101 till och med siffra 710107. Det räcker att skriva ut de första gränserna, 710101, 710107, ifall det skulle finnas flera sekvenser med sju treor. Det skall räcka att anropa funktionen en gång för att få ut alla resultat (man skall inte behöva anropa den tio gånger, vilket inte hindrar att du kan ha ytterligare en funktion som anropas för en enstaka siffra, d). Man anropar lämpligen funktionen från ett huvudprogram som sköter utskrifter och liknande.


Problem
Skriv en Matlabfunktion som räknar ut antalet sekvenser av längd ett, antalet sekvenser av längd två etc. Slutsats?
Ex: tal = [1, 2, 2, 1, 1, 1, 4, 4, 4, 4, 5, 5, 5, 1, 7, 9] har fyra sekvenser av längd ett, en av längd två, två av längd tre och en av längd fyra. Det skall räcka att anropa funktionen en gång för att få ut alla resultat. Man anropar lämpligen funktionen från ett huvudprogram som sköter utskrifter och liknande.



Hur man testar sitt program:

Program testing can be used to show the presence of bugs, but never to show their absence!
Edsger Dijkstra

A bug-free program is an abstract. theoretical concept.
Dennie Van Tassel

All sufficiently complex programs have bugs.
Anonymous

An effective way to test code is to exercise it at its natural boundaries.
Brian Kernighan

Normalt kan vi inte vara helt säkra på att ett program fungerar i alla detaljer. De flesta program fungerar nog under normal drift, men kan nog räkna fel vid ovanliga indata. Här några skräckhistorier: Collection of Software Bugs, Software horror stories. Programmen i denna lab är dock tämligen enkla och vi kan genom omsorgsfull programmering och testning övertyga oss om att de (nog) är bugfria. Absolut säkerhet uppnår vi aldrig. Även om vårt program är korrekt, så körs det ju i Matlab (som är ett stort komplicerat program; jag har själv rapporterat flera buggar), på en mycket komplex apparat (en dator) som styrs av Linux, ännu ett stort programsystem.

När man testar sitt program bör man ha med några typiska fall, men även undantagsfall (som Brian Kernighan förordar). Man gör nog ofta rätt på normalfallet, men tänker sig inte för vid ovanliga fall. Slumpdata är inte så användbara som skulle kunna tro, eftersom de brukar vara rätt så snälla. Om man t.ex. vill testa en rutin för att beräkna egenvärden till en matris, så ger slumpdata snälla matriser. Svåra problem har t.ex. multipla egenvärden, ett undantagsfall.

Några typiska testdata för sekvensproblemet (den andra uppgiften):

tal = 1;                   % vektorlängd ett, dessutom finns inte alla siffror med
tal = [1, 1, 1, 1, 1];     % en sekvens som avslutas med att vektorn "tar slut"
tal = [1, 1, 1, 1, 1, 2];  % här avslutas sekvensen med annan siffra

% sekvenser av olika längder (med samma siffra), den längsta sekvensen kommer inte sist
tal = [2, 1, 1, 2, 3, 4, 1, 1, 1, 2, 2, 4, 5, 5, 5, 1, 1, 1, 1, 1, 5, 5, 1, 1, 1];

% slumpdata är normalt enkla, och därmed inte så intressanta ur testsynpunkt
tal = floor(10 * rand(50, 1));

I denna lab kör vi programmet i en kontrollerad omgivning. Om programmet skall användas av andra personer, eller anropas av ett annat program vill man nog bygga in mer säkerhet i koden. Den bör kunna hantera felaktiga indata, t.ex. en tom vektor, tal = []; eller en vektor som inte innehåller enbart decimala siffror, tal = [2, -5, 14]; . Skilj mellan felaktiga indata och ovanliga fall (ett ensiffrigt tal).


Back