• No results found

Formaterad in- och utmatning

8.1.2 Dokumentation av programmet.

Vi har tidigare ber¨ort vikten av att dokumentera program med kommentarer i koden. F¨or stora program r¨acker inte detta s¨att att dokumentera vad programmet g¨or, och vilket dess gr¨anssnitt mot omv¨arlden ¨ar. Om programmet b¨orjar omfatta tusentals rader med kod ¨ar det inte praktiskt att bl¨addra igenom koden p˚a jakt efter kommentarer som avsl¨ojar allt om programmet. I s˚adana fall b¨or man producera en separat dokumentation som talar om hur man anv¨ander programmet, vad programmet utf¨or och vad som kr¨avs f¨or att programmet skall kunna k¨ora (till exempel vilka data som m˚aste matas in i programmet och i vilket format). Den h¨ar typen av dokumentation - Anv¨andarhandbok, engelska Users Guide - skall kunna l¨asas av n˚agon som inte har n˚agra egentliga kunskaper i det programmeringsspr˚ak som anv¨ants i det aktuella fallet. D¨aremot ¨ar det viktigt att dokumentera till exempel matematiska algoritmer som anv¨ands av programmet om dessa har betydelse f¨or hur man skall f¨orst˚a resultaten. Inom den h¨ar kursen ¨ar det knappast troligt att ni kommer att skriva s˚apass stora program att de beh¨over dokumenteras p˚a den h¨ar niv˚an, i allm¨anhet kommer kommentarer i koden att r¨acka till.

Verkliga proffs l˚ater dokumentationen av programmet ing˚a i design-fasen, jag har sj¨alv sett exempel p˚a duktiga programmerare som f¨orst har utarbetat dokumentationen av programmet och diskuterat den med anv¨andarna av programmet i olika omg˚angar tills de varit n¨ojda, och f¨orst d¨arefter b¨orjat arbetet med att skriva programmet. Det ¨ar v¨al kanske on¨odigt att till¨agga att de flesta av oss inte alls lever som vi l¨ar utan s¨atter oss ned och f¨ors¨oker koda programmet rakt av och g¨ora n˚agon slags ”design as you go”. Har man lite vana fungerar det ocks˚a, f¨or det mesta, men vi skulle nog skriva b¨attre program, och f˚a dem klara lite tidigare om vi lade ned lite mer m¨oda p˚a design och dokumentation.

8.2 Formaterad in- och utmatning

Hitills har vi inte haft n˚agot s¨arskilt elegant s¨att att kommunicera med v˚ara m-filer: vi har kunnat skicka variabler mellan kommandof¨onstret och m-filen genom att utnyttja att de anv¨ander samma workspace, och vi har kunnat anv¨anda kommandot disp f¨or att skriva ut textstr¨angar i kommandof¨onstret. F¨or att kunna skriva anv¨andbara program m˚aste vi ha en elegantare och flexiblare metod f¨or att skicka information mellan de olika komponenterna.

8.2.1 L¨as data och str¨angar fr˚an kommandof¨onstret - kommandot input.

F¨or att mata in data och textstr¨angar i en m-fil kan vi anv¨anda kommandot input.

Kommandot f¨orekommer i tv˚a former beroende p˚a om vi vill l¨asa in en variabel: x = input(str¨ang), eller om vi vill l¨asa in en textstr¨ang: text = (str¨ang,’s’). I b¨agge fallen ¨ar str¨ang en textstr¨ang som skrivs ut i kommandof¨onstret f¨or att g¨ora oss uppm¨arksamma p˚a att programmet f¨orv¨antar sig att vi skriver in n˚agot. En specialitet ¨ar att mark¨oren kom-mer att stanna omedelbart efter det att str¨angen skrivits ut, f¨or att f˚a ett radbyte m˚aste vi inkludera specialtecknet \n i str¨angen. \n kallas en escape-sekvens, det finns fler s˚adana, de mest anv¨andbara ¨ar:

\n radbyte

\t tab: flyttar utskriftspunkten till n¨asta tabstopp, mycket anv¨andbart om man vill skriva ut en snygg tabell

\b backar utskriftspunkten ett steg

Om vi l˚ater v˚art program f¨or primtalsfaktorer ha den litet hurtiga artighet som k¨annetecknar

en del moderna program skulle v˚art program kunna b¨orja:

namn=input(’Hej och v¨alkommen till PRIMFAKT - \n Vad heter du? ’,’s’);

out=[’Hej ’ namn’\n Mata nu in det tal du vill s¨oka faktorer f¨or\n’];

x=input(out);

f¨or den fortsatta behandlingen finns nu det tal f¨or vilket vi s¨oker primfaktorer lagrat i vari-abeln x.

8.2.2 Formatera str¨angar f¨or utmatning - Formatkoder och kommandot sprintf

N¨ar vi vill skriva ut ett resultat fr˚an en m-fil till kommandof¨onstret s˚a kan vi anv¨anda kom-mandot num2str(x) som omvandlar en siffra till motsvarande textstr¨ang. Vi kan d˚a bygga upp en textstr¨ang som vi sedan skriver ut i kommandof¨onstret med kommandot disp:

out = [’Primfaktorerna ¨ar ’ num2str(f(1)) ’ och ’ num2str(f(2))] f¨oljt av disp(out);.

Problemet med den konstruktionen ¨ar att vi m˚aste veta fr˚an b¨orjan hur m˚anga tal vi vill skriva in i str¨angen. Ett mer flexibelt s¨att att g¨ora samma sak ¨ar att anv¨anda komman-dot sprintf. Kommankomman-dot sprintf l˚ater oss skriva in text och variabler till en textstr¨ang med anv¨andande av formateringsregler, vi kan sedan skriva ut str¨angen p˚a sk¨armen med anv¨andande av disp, precis som vanligt. Att beskriva hur formaterad utskrift g˚ar till kan bli v¨aldigt abstrakt, s˚a l˚at oss b¨orja med ett exempel och f¨ors¨oka f¨orst˚a det hela utifr˚an det exemplet. I kommandot

y=2;

x=3;

string = sprintf(’Svaret ¨ar %f eller kanske %g ’,y ,x) skapar sprintf en text-str¨ang som kallas string av den str¨ang som st˚ar till v¨anster om det f¨orsta kommatecknet i parantesen. Men varje g˚ang en formatkod - ordet som inleds med % - f¨orekommer s˚a ers¨attes formatkoden med en variabel h¨amtad efter det f¨orsta kommatecknet. Antag att y = 2 och x

= 3, str¨angen string blir d˚a lika med ” Svaret ¨ar 2.000000 eller kanske 3”. Men varf¨or skrivs y ut med 6 decimaler och g utan decimaler? Det beror p˚a att formatkoden inte bara visar att man skall stoppa in v¨ardet av en variabel p˚a den platsen i str¨angen, utan ocks˚a hur den skall formateras. %f s¨ager att det tal som skall stoppas in ¨ar ett decimaltal, och om vi inte anger annat s˚a kommer det att skrivas med 6 decimaler. %g anger att talet skall skrivas ut p˚a ”l¨ampligt” s¨att - om det ¨ar ett tal st¨orre ¨an 10−4 och mindre ¨an 106 skrivs det ut som ett decimaltal, men utan efterf¨oljande nollor. Ligger talet utanf¨or det intervallet skrivs det som ett decimaltal g˚anger en exponent av tio. Vill man alltid ha det senare formatet kan man anv¨anda formatkoden %e. Prova till exempel f¨oljande (f¨or att skriva ut ett procenttecken i en textstr¨ang skriver man %%):

y=2.17;

x=34567.98765;

string = sprintf(’x och y med formatet %%f %f %f ’,x,y) disp(string)

string = sprintf(’x och y med formatet %%g %g %g ’,x,y) disp(string)

string = sprintf(’x och y med formatet %%e %e %e ’,x,y) disp(string)

Vi kan p˚averka b˚ade hur stor bredd sifferf¨altet skall uppta i textstr¨angen och hur m˚anga decimaler talet skall skrivas ut med. Det g¨ors genom att skriva in siffror mellan procent-tecknet och formatkoden. Den f¨orsta siffran talar om vilken minsta bredd sifferf¨altet skall uppta, den andra siffran talar om hur m˚anga decimaler vi vill se utskrivna, mellan dessa siffror skrivs en punkt. S˚a betyder %7.3f att vi vill skriva ut ett decimaltal s˚a att totala

8.2. FORMATERAD IN- OCH UTMATNING 89 bredden blir minst 7 tecken och att talet skall ha 3 decimaler. Prova

y=2.17;

x=34567.98765;

string = sprintf(’x har v¨ardet %7.3f och y har %7.3f med formatet %%7.3f ’,x,y);

disp(string)

f¨or att se hur det fungerar. L¨agg m¨arke till dels att talet skrivs ut med st¨orre bredd ¨an den minimibredd vi anger om detta ¨ar n¨odv¨andigt f¨or att vi skall f˚a plats med hela talet inklusive det antal decimaler vi ber om, dels att om talet ¨ar kortare s˚a fylls det p˚a med blanktecken f¨or att minimikravet p˚a bredd skall uppfyllas (vill vi att siffrorna skall st˚a till v¨anster i f¨altet skriver vi %-7.3f ist¨allet). Oftast vill man ju inte ha dessa blanka tecken inuti str¨angen utan skriver %0.3f f¨or att ange antalet decimalsiffror, men ibland kan man vilja linjera upp siffror som skrivs ut i p˚a varandra f¨oljande rader, och d˚a kan en fix vidd vara anv¨andbar. Prova ocks˚a vad som h¨ander om ni anv¨ander formaten

string = sprintf(’x is%7.3g and y is %7.3g with format %%7.3g ’,x,y); och string = sprintf(’x is %7.3e and y is %7.3e with format %%7.3e ’,x,y);

Ut¨over e, f och g s˚a finns det ett antal andra formatkoder. De som vi kan komma att beh¨ova i den h¨ar kursen ¨ar c och s. %c anger att vi vill att en bokstav skall stoppas in, %s anger att vi vill stoppa in en hel str¨ang, oavsett hur l˚ang den ¨ar. Det som g¨or sprintf l¨amplig att anv¨anda f¨or att skriva ut resultat n¨ar vi inte vet hur m˚anga variabler vi vill skriva ut ¨ar att om det finns fler variabler till h¨oger om det f¨orsta kommat inom parantesen efter sprintf s˚a b¨orjar tolkningen om fr˚an b¨orjan. Fel anv¨ant blir det inte s¨arskilt snyggt, prova hur out=sprintf(’Resultatet ¨ar %g ’,x,y) ser ut. Ist¨allet f˚ar vi konstruera fler str¨angar, varav en bara best˚ar av det ok¨anda antalet variabler som vi vill skriva ut, f¨or att sedan l¨agga ihop str¨angarna till en l˚ang str¨ang som vi l¨agger ut med hj¨alp av disp:

x=1:7;

out1=sprintf(’Resultatet ¨ar’);

out2=sprintf(’ %g,’,x);

out3=sprintf(’\b’);

out=[out1 out2 out3];

disp(out)

Observera att str¨angen out2 inneh˚aller ett mellanslag. (Funderar du ¨over po¨angen med str¨angen out3 s˚a prova utan! Det h¨ar ¨ar ett av ganska f˚a exemplen p˚a hur \b ¨ar anv¨andbar).

Vi ¨ar nu mogna att koda den sista delen av v˚art program, d¨ar vi skriver ut primfaktorerna:

out1=sprintf(’Talet %0.0f har %0.0f primfaktorer \n De ¨ar’, x, ... AntalFaktorer);

out2=sprintf(’ %g,’,Faktor);

out3=sprintf(’’

¯);

out=[out1 out2 out3];

disp(out)

8.3 Ovningsuppgifter ¨

1. Samla ihop alla delarna av programmet f¨or att ber¨akna primfaktorer till ett fungerande program.

2. Skriv ett program som ber¨aknar en approximation till e, basen f¨or den naturliga loga-ritmen, fr˚an summan.

e =

X

k=0

1 k!

L˚at programmet l¨asa in hur m˚anga termer som skall finnas med i summan, och skriv sedan i kommandof¨onstret ut hur m˚anga termer som summerats, och skillnaden mellan approximationen och exp(1), genom en l¨ampligt formaterad textstr¨ang.

3. Modifiera programmet s˚a att det ist¨allet fr˚agar efter hur liten liten mellan approxima-tionen och exp(1) som efterstr¨avas och sedan ber¨aknar hur m˚anga termer som beh¨ovs innan approximationen blir tillr¨ackligt bra.

Kapitel 9

Mer grafik och programmering

9.1 Mer om 2D-grafik

I detta avsnitt samlar vi n˚agra kommandon som kan anv¨andas f¨or mer avancerad 2D-grafik.

9.1.1 Avancerade kommandon f¨or 2-D grafik Fler grafikf¨onster - kommandot figure

Normalt ritas alla grafer i ett f¨onster som heter figure(1). Ibland n¨ar man till exempel analyserar resultaten fr˚an en laboration s˚a vill man k¨ora igenom ett program som g¨or hela analysen och spara ett antal olika plottar. Detta kan man g¨ora genom att ge kommandot figure(#) d¨ar # ¨ar ett tal. Alla plottar som ritas efter detta kommando kommer att ritas i ett grafikf¨onster som heter figure(#) ¨anda tills vi ger ett nytt kommando med ett nytt f¨onsternamn.

Fyllda polygoner - kommandot fill

Vi kan rita en godtycklig polygon i en graf genom att ge kommandot fill(x, y, ’f¨arg’).

Argumentet till detta kommando ¨ar tv˚a vektorer x och y som inneh˚aller x- och y-koordinater f¨or polygonens h¨orn, samt en kod f¨or fyllningsf¨arg (se avsnitt 6.1.3). Ett vanligt anv¨ andnings-omr˚ade f¨or detta kommando ¨ar n¨ar man vill l¨agga in ett f¨argat band som visar var data kan f¨orv¨antas ligga, till exempel ett medelv¨arde plus-minus en standardavvikelse. Vill man anv¨anda fill tillsammans med data i samma graf kan man beh¨ova t¨anka sig f¨or litet, det

¨

ar det senast utf¨orda plot- eller ritkommandot som hamnar ¨overst, vill vi att datapunkter skall synas m˚aste de allts˚a plottas ovanp˚a fill-arean, det kan d¨arf¨or ibland vara n¨odv¨andigt att plotta tv˚a g˚anger:

clear all;

gvalue =[9.400 9.770 9.900 10.400 9.940 9.300 9.710 8.430 9.450 9.620];

clf figure(1)

xvalues=1:length(gvalue) max = length(gvalue) boxx=[0 max max 0];

boxy=[9.9 9.9 9.7 9.7];

fill(boxx,boxy,’y’) hold on

plot(xvalues, gvalue, ’b*’) hold off

91

Att l¨asa av koordinater i en graf - kommandot ginput.

Ibland vill vi kunna l¨asa av koordinater f¨or en punkt i en graf, antingen f¨or att kunna identifiera vilken punkt i en l˚ang serie av data som ¨ar vilken, eller f¨or att vi vill kunna rita ett element f¨or hand med fill eller line till en viss punkt i en graf. Detta kan vi g¨ora genom att ge kommandot [x,y] = ginput och sedan v¨alja grafikf¨onstret. Vi ser d˚a att mark¨oren f¨orvandlats till ett h˚arkors. Varje g˚ang vi klickar p˚a musknappen l¨aggs koordinaterna f¨or den punkt d¨ar mark¨oren befinner sig in i vektorerna x och y. Vi avslutar genom att trycka p˚a returtangenten.