Pseudokode

Fra Holstebro HTX Wiki
Skift til: navigering, søgning

Der findes mange forskellige værktøjer til at styre og dokumentere programmeringsprocessen, hvor nogle tager udgangspunkt i visningen, andre tager udgangspunkt objekter, og nogle tager udgangspunkt i programflow.

Man kan vælge mange forskellige teknikker, men en let forståelig er pseudokode (Det udtales ”søudokode”).

Beskrivelsen er inspireret er et notat fra Per Holck[1] der har taget udgangspunkt i Programmering i Pascal[2].

Hvad er Pseudokode

Kort sagt er den en simpel tekstlig måde at udtrykke et programs funktion på, ud fra at man skriver i normal dagligt sprog, hvad er det programmet skal lave, og hvilken rækkefølge skal det skrives i.

Beskrivelsen af de handlinger, som skal til for at løse opgaven, skal være både generel og letforståelig. Blandt andet derfor bruger vi almindelige danske ord til beskrivelsen. På den måde undgår man også at spilde tid på at overveje særlige detaljer i programmeringssproget, som f.eks. om der skal bruges komma eller semikolon mellem de variable i en procedureerklæring.

Samtidig med at man bruger danske ord til beskrivelsen af delopgaverne, skriver man disse ord i en opsætning, som minder om programmeringssprog. Derfor navnet pseudokode. Teksten bliver en slags kode ligesom Pascal eller javaScipt. Der findes blot ingen programmer, som kan oversætte det til maskinkode, eller fortolke det som en browser fortolker javaScript.

Ved at vælge en beskrivelse som ligger midt imellem daglig tale og f.eks. Pascal eller Basic, får man slået bro mellem på den ene side det sprog, opgaven er beskrevet i, og på den anden side det sprog, som løsningen skal skrives i.

Hvorfor bruge Pseudokode

Med Pseudokode kan man på en simpel måde at illustrere over for andre, på en generel facon, hvad det er ens program skal kunne, endnu inden man har valgt hvilket programsprog det skal skrives i, og uden at skulle have selve koden til at fungere.

Fordelen er at man kan illustrere over for folk der ikke er programmører, hvad det er et program laver, og på den måde få dem til at godkende, at det er det de vil have et program til at lave.

Samtidigt er det også en måde at dokumentere funktionen af et program.

Pseudokode bruges til at konstruere algoritmer til at løse et allerede fastlagt problem. Det er altså ikke et værktøj til at designe skærmbillede eller fastlægge bruger-program storyboard eller nogen af alle de andre aspekter af programkonstruktionen. Metoden bruges til at finde ud af hvordan man kan få sit program til at udføre de ønskede handlinger.

Metoden er ment som en hjælp til at konstruere kode til løsning af komplicerede problemer. Hvis problemet er så let, at man kan lave koden med det samme, skal man ikke bruge pseudokode.

Hvordan bruger man Pseudokode

Der er ikke nogen direkte regler for hvordan man skriver Pseudokode, det vigtigste er at man er konsekvent i det man laver, så det er læseligt og forståeligt, så man kan lave koden der virker ligesom beskrivelsen.

Formålet med pseudokode er som sagt at finde en algoritme som løser en fastlagt opgave. Princippet i pseudokode er det gamle ”Del og hersk”. Hvis opgaven er simpel nok, skriver man blot noget kode, som klarer sagen. Hvis opgaven er kompleks, opdeler man den i små delopgaver, som hver især er så simple, at man kan skrive kode til dem.

Dette lyder jo nemt nok, men hvis du tænker dig om, vil du indse, at der nu er to nye problemer: Dels hvordan skal opdelingen i delopgaver laves og dels hvordan undgår man at miste overblikket med alle disse delopgaver?

Problemet med hvordan man opsplitter sin opgave i mange små delopgaver, klarer man ved at anvende metoden på metoden selv: man laver denne opsplitning lidt ad gangen i overskuelige trin.

Problemet med at bevare overblikket klarer man ved at bruge grafik. Man indrammer simpelthen de dele som hører sammen. Mennesker er nemlig bedst til at skaffe sig overblik ved at se på tegninger og diagrammer.

Selve metoden

For at holde styr på hvor langt man er i denne opsplitning af problemet, beskriver man løsningen i en række udgaver, hvor den første er meget generel, og de efterfølgende er stadig mere detaljerede.

I sin første udgave af løsningen deler man opgaven op i nogle få (typisk 3 til 7) delhandlinger. Det er vigtigt at tænke i handlinger. I sidste ende ønsker man jo at edb-maskinen skal gøre noget.

De delhandlinger, som er komplicerede, splitter man yderligere op i 2.udgave, og sådan fortsætter man. Til sidst er alle delopgaverne så simple, at man umiddelbart kan skrive den nødvendige kode i det valgte programmeringssprog.

Efterhånden får man fastlagt navne og typer på de variable. Hvis datastrukturen er kompliceret må man supplere med tegninger. Klumper af handlinger, som udgør en logisk helhed, identificeres og udskilles som separate navngivne procedurer eller funktioner. Hver af disse procedurer kan så konstrueres færdig separat.

Processen stopper når man føler, at alle dele af pseudokoden er klar til at blive skrevet i det valgte programmeringssprog.

Skrivemåde

En vigtig del af pseudokodemetoden er at bruge en bestemt opstilling for at danne sig et grafisk over-blik.

En sekvens af handlinger som skal udføres efter hinanden skrives under hinanden i rækkefølge.

handling 1
handling 2
handling 3

Forgreninger skrives som:

Pseudo forgren.png
Her markerer rammerne de handlinger som skal udføres sammen.

Ud over indramningen anvender man også indrykning for at gøre det mere overskueligt.

Løkker kan skrives på mange måder her er fire eksempler

Pseudo loekker.png
De forskellige løkkestrukturer kører på forskellige betingelse, og vil selvfølgelig blive lavet ned forskellige løkke-strukturer, men det er ikke sådan at man skal begrænse sig efter et antal kendte strukturer. Man skal i stedet skrive den pseudokode der passer til den opgave man skal have løst, og så må man finde ud af hvordan man skriver koden bagefter.

Alternativ skrivemåde

Hvis man ikke vil tumle så meget med grafikken, så kan man reducere skrivemåden ved at nøjes med indrykninger. Det er måske ikke helt så klart, men hvis man laver en fornuftig opsætning, så kan det også give en god læselighed.

Forgreninger kan så skrives som:

hvis ..... så
        handling 1
        handling 2
        handling 3
ellers
        handling 4


De fire eksempler på Løkker kan så skrives som:

gentag
        handling 1
        handling 2
        handling 3
indtil alle tal er brugt
Så længe der er flere bogstaver
        handling 1
        handling 2
gentag for hver linie i filen
        handling 1
        handling 2
        handling 3
For hvert ulige tal mellem 33 og 72
        handling 1
        handling 2
        handling 3
        handling 4

Ikke den første, men den bedste løsning

Hver gang man har lavet en ny udgave skal man stoppe op og overveje, om det nu også er den bedste løsning man har fundet.

En god måde at tjekke det på, er ved at håndteste pseudokoden igennem med forskellige eksempler, for at se om den opfører sig som den skal.

Findes der alternativer som måske er bedre? Nogle alternativer kræver blot små ændringer, andre kræver at programmets grundlæggende struktur laves om.

Det er selvfølgelig bedst, at man undervejs identificerer den optimale løsning på hvert detaljeringsniveau, så man ikke fortsætter med flere og flere detaljer i en løsning, som alligevel ikke var den rette. I virkelighedens verden opdager man somme tider først under aftestningen af programmet, at løsningen er forkert! Man skal så vende tilbage til sin pseudokode og se hvor den skal laves om. Men hvis man er omhyggelig i hvert trin kan man undgå den slags ærgerlige fejl.

Husk: ”Den ultimative form for dovenskab er at gøre tingene rigtigt første gang”.

Eksempel der illustrerer brugen af Pseudokode

Opgaven.

Den valgte opgave til eksemplet, er simpel, men rummer alligevel problemer nok til at man kan se, hvordan pseudokode bruges. Der tænkes på en situation hvor opgavestilleren modtager post fra en afsender som ikke har et dansk tastetur til sin computer. Opgavestilleren oensker at slippe for at laese tekst som ser saadan her ud.

Opgaven kan præciseres til at læse en tekst fra en tekstfil og erstatte alle forekomster af ”ae” med ”æ”, af ”oe” med ”ø” og af ”aa” med ”å”. I første omgang ser vi bort fra problemerne med store bogstaver.

1. udgave.

   åben tekstfilen
   læs teksten og konverter til danske bogstaver
   skriv i en ny fil
   luk filen

Læg mærke til at dette faktisk er en løsning på opgaven, den er blot ikke detaljeret nok til at blive omskrevet til programmeringssprog endnu. Man kan allerede nu fastlægge lidt af datastrukturen: Der er en tekstfil med den oprindelige tekst, den kan man kalde indfil og den nye tekstfil udfil.

Linie nummer to er stadig for abstrakt, så den bliver udbygget i næste udgave.

2. udgave.

   åben indfil
   sålænge der er flere linier i indfil
       læs næste linie i indfil
       konverter linien
       skriv den konverterede linie til udfil
   luk indfil

Løkken ”sålænge…” er et eksempel på hvordan indrykningen bruges til at vise præcis hvilke linier som skal gentages.

Her kan man også straks se en fejl: Hvorfor nævnes udfil så lidt? Det er et eksempel på hvordan metoden sikrer at man bevarer overblikket og får rettet sine fejl. 1.udgave skulle have heddet: ”åben begge tekstfiler” osv.

Det er også tydeligt, at man får brug for et sted at have den linie, der er ved at blive konverteret, så der indføres en string variabel linie.

3.udgave.

   åben indfil og opret udfil
   sålænge der er flere linier i indfil
       læs næste linie i indfil og anbring den i linie
       konverter teksten i linie
       skriv linie til udfil
   luk indfil og udfil

Det gav ikke meget nyt, så man må i gang med den egentlig konvertering. Konverteringen er blevet isoleret til ”konverter teksten i linie” så der kan man arbejde videre på den alene. Muligvis vil det blive til en separat procedure i den endelige kode. Ind til videre kan man kalde den konverterTekst.

konverterTekst, udgave 1.

   læs bogstaverne i linie
   hvis det er ae, oe eller aa så erstat med æ,ø og å

Her er der problemer!

  1. Hvad vil det egentlig sige at læse bogstaverne i linien? Skal de læses ét ad gangen eller dem alle sammen på en gang?
  2. Hvornår skal ”hvis det er…” udføres, én gang eller efter hvert bogstav?
  3. ”hvis det er…” hvad referer ordet ”det” egentlig til?

Problemerne skyldes ikke at der ikke er detaljer nok, men at man har været alt for upræcis! så:

konverterTekst, udgave 1 rettet.

   læs bogstaverne i linie et ad gangen og for hver bogstav
       hvis det er ae, oe eller aa så erstat med æ,ø og å

Det er mere præcist, - så præcist at man klart kan se, at der er lavet en tanketorsk: Hvordan kan ét bogstav være f.eks. ae ?

Dette er en af pseudokode-metodens store fordele: Man kan fange sådanne design-mæssige brist længe før, man har skrevet metervis af kode. Kode som man dels må kassere og dels mentalt er fanget af, så det kan være næsten umuligt at få øje på alternativerne.

konverterTekst, udgave 2.

   for hvert bogstav i linie
       hvis bogstavet er a, så
           hvis det næste bogstav er e, så
               skriv æ
           ellers
               hvis det er a, så
                   skriv å
       ellers
           hvis bogstavet er o, så
               hvis det næste er e, så 
                   skriv ø

Her ses strukturen tydeligt med forgreninger inden i hinanden. Men det bliver værre for ”hvis det næste bogstav …” kræver jo at der er et næste bogstav. Der skal derfor undersøges om enden af linien er nået.

Ordene ”skriv æ” gemmer også problemer: Hvor skal æ skrives, i stedet for a? eller i stedet for både a og e? Hvis man gør det sidste så skal resten af teksten i linie rykkes en plads til venstre, og det vil igen kræve noget kode. Det kan løses på forskellig vis, men en løsning kan være at indføre to variable indlinie og udlinie i stedet for blot linie.

konverterTekst, udgave 3.

   for hvert bogstav i indlinie
       hvis bogstavet er a, så
           hvis der er flere bogstaver i indlinie, så
               hvis det næste bogstav er e, så
                   skriv æ
               ellers
                   hvis det er a, så 
                       skriv å
                   ellers 
                       skriv a
           ellers
               skriv a
       ellers
           hvis bogstavet er o, så
               hvis der er flere bogstaver i indlinie, så
                   hvis det næste er e, så 
                       skriv ø
                   ellers 
                       skriv o
               ellers
                   skriv o
           ellers
               skriv bogstavet

På dette sted i programkonstruktionen kan man overveje om dette virkelig er den letteste og eleganteste løsning. For at afklare dette kan man afprøve nogle alternativer:

konverterTekst, udgave 3 B.

  for hvert bogstav i linie undtagen det første
     hvis bogstavet er e, så
        hvis det foregående bogstav var a, så
           skriv æ
        ...
        ...

Denne løsning kan straks forkastes da den vil give en fejl: Kaere bliver til Kaære. For at reparere på det skal der slettes fra udlinie. Det kan lade sig gøre, men det bliver rodet. Og både ideen om at reparere på udlinie og det rodede indtryk er advarselslamper om, at her skal der overvejes alternativer.

Men ideen bag løsningen er god nok, så den bliver brugt i er nyt alternativ:

konverterTekst, udgave 3 C.

   for hvert bogstav i indlinie undtagen det sidste
       hvis bogstavet er a, så
           hvis det næste bogstav er e, så
               skriv æ
           ellers
               hvis det næste bogstav er a, så 
                   skriv å
               ellers 
                   skriv a
       ellers
           hvis bogstavet er o, så
               hvis det næste bogstav er e, så 
                   skriv ø
               ellers 
                   skriv o
           ellers
               skriv bogstavet
   skriv det sidste bogstav i linien

Dette ser mere lovende ud! Men måske kan det forbedres.

Der kan også være en fejl: hvis de to sidste bogstaver er ae, så bliver der godt nok skrevet æ, men efter løkken bliver det sidste bogstav så skrevet, så der kommer til at stå æe i stedet for æ som der skulle.

Der afprøves med en ny indgangsvinkel

konverterTekst, udgave 3 D.

   for hvert bogstavpar i indlinie
       hvis bogstavetparret er ae, så
           skriv æ
       ellers
           hvis bogstavetparret er oe, så
               skriv ø
           ellers
               hvis bogstavetparret er aa, så 
                   skriv å
           ellers 
               skriv bogstavparret
   skriv om nødvendigt det sidste bogstav i linien

Denne løsning er let læselig og den er logisk og klar. Men er det muligt at løbe bogstavpar i linien igennem?

Hvis man håndtester med nogen eksempler, så vil man se at det kan gå galt nogen gange.

Står der: stoerre i en linie vil det blive splittet op som st oe rr e, så det vil fint blive konverteret til større.

Står der: gaer i en linie, så vil der blive splittet op som ga er så det IKKE bliver konverteret til gær som egentlig var meningen.

Altså skal man tilbage til skrivebordet igen, og få tilrettet pseudokoden, inden man begynder at skrive programmet.

Eksemplet stopper her. Formålet var jo slet ikke at lave et program; men at vise pseudokode metoden og den skulle gerne nu stå klart.

Referencer

  1. http://www.emu.dk/gym/hhxhtx/pm/inspiration/tema/eksempler/Pseudo.zip Per Holck pho@ats.dk
  2. http://www.librarything.com/work/5134585 Thorkild Skjelborg: ”Datalogi: Programmering i Pascal”