Kontraktbaseret Programmering Anker Mørk Thomsen 1. udgave ISBN: 978-87-40-41315-1

Relaterede dokumenter
Kontraktbaseret Design. Anker Mørk Thomsen

Elementær Matematik. Mængder og udsagn

01017 Diskret Matematik E12 Alle bokse fra logikdelens slides

t a l e n t c a m p d k Matematiske Metoder Anders Friis Anne Ryelund 25. oktober 2014 Slide 1/42

26 Programbeviser I. Noter. PS1 -- Programbeviser I. Bevis kontra 'check af assertions' i Eiffel. Betingelser og bevisregler.

Baggrundsnote om logiske operatorer

Bevisteknikker. Bevisteknikker (relevant både ved design og verifikation) Matematisk induktion. Matematisk induktion uformel beskrivelse

Udsagnslogik. Anker Mørk Thomsen. 6. december 2013

1 < 2 og 1 > 2 (2.1) er begge udsagn. Det første er sandt det andet er falsk. Derimod er

Bevisteknikker (relevant både ved design og verifikation)

Sproget Rascal (v. 2)

Algoritmeskabeloner: Sweep- og søgealgoritmer C#-version

Læs selv om LOGIK. Erik Bjerre og Pernille Pind Forlaget Pind & Bjerre

Grådige algoritmer. Et generelt algoritme-konstruktionsprincip ( paradigme ) for optimeringsproblemer.

Hvad er formel logik?

Skriftlig Eksamen Algoritmer og Datastrukturer (dads)

Eksempel på den aksiomatisk deduktive metode

Gödel: Über formal unentschiedbare Sätze der Principia Mathematica und verwandter Systeme I, 1931

Logik. Helge Elbrønd Jensen og Tom Høholdt Fortolket af Michael Elmegård og Øistein Wind-Willassen.

Logik. Af Peter Harremoës Niels Brock

BOSK F2012, 1. del: Prædikatslogik

Opgaver i logik, torsdag den 20. april

Projekt 1.4 De reelle tal og 2. hovedsætning om kontinuitet

De rigtige reelle tal

Boolsk algebra For IT studerende

Euklids algoritme og kædebrøker

Introduktion til prædikatlogik

Punktmængdetopologi. Mikkel Stouby Petersen. 1. marts 2013

Introduktion til differentialregning 1. Jens Siegstad og Annegrethe Bak

DM517:Supplerende noter om uafgørlighedsbeviser:

Den sproglige vending i filosofien

Programmering, algoritmik og matematik en nødvendig sammenblanding?

Matematiske metoder - Opgavesæt

22 Hobe. Noter. PS1 -- Hobe. Binære hobe. Minimum-hob og maximum-hob. Den abstrakte datatype minimum-hob. Opbygning af hobe. Operationen siv-ned.

Sproget Limba. Til brug i G1 og K1. Dat1E 2003

Tal. Vi mener, vi kender og kan bruge følgende talmængder: N : de positive hele tal, Z : de hele tal, Q: de rationale tal.

Brug og Misbrug af logiske tegn

Design by Contract. Design and Programming by Contract. Oversigt. Prædikater

Boolsk algebra For IT studerende

Studieordning for diplomuddannelsen i informationsteknologi

Listen over reserverede ord er meget lang, men de væsentligste vil jeg beskrive her i denne artikel:

Skriftlig Eksamen Algoritmer og Datastrukturer (dads)

Noter til Perspektiver i Matematikken

Kalkulus 2 - Grænseovergange, Kontinuitet og Følger

Henrik Bulskov Styltsvig

Grådige algoritmer. Et generelt algoritme-konstruktionsprincip ( paradigme ) for optimeringsproblemer.

Programmering for begyndere Lektion 2. Opsamling mm

Differentialregning. Ib Michelsen

Om at løse problemer En opgave-workshop Beregnelighed og kompleksitet

Fraktaler Mandelbrots Mængde

Hjerner i et kar - Hilary Putnam. noter af Mogens Lilleør, 1996

Sproget Six. Til brug i rapportopgaven på kurset Oversættere. Vinter Abstract

Åben uddannelse, Efterår 1996, Oversættere og køretidsomgivelser

3. Om skalamønstrene og den indfoldede orden

Appendiks 6: Universet som en matematisk struktur

Ja! det beviste vi uge 16+17

Implikationer og Negationer

Udarbejdet af CFU Absalon

Sortering. Eksempel: De n tal i sorteret orden

Design by Contract Bertrand Meyer Design and Programming by Contract. Oversigt. Prædikater

Lad os som eksempel se på samtidigt kast med en terning og en mønt:

Om brugen af matematiske tegn og objekter i en god matematisk fremstilling

Jan B. Larsen HTX Næstved Computational Thinking Albena Nielsen N. Zahles Gymnasium 2018/2019

Ugeseddel 4 1. marts - 8. marts

HTX, RTG. Rumlige Figurer. Matematik og programmering

4 Oversigt over kapitel 4

Skriftlig Eksamen Algoritmer og Datastrukturer (DM507)

Matematisk induktion

DM13-1. Obligatorisk opgave E.05. Jacob Aae Mikkelsen

Grådige algoritmer. Et generelt algoritme-konstruktionsprincip ( paradigme ) for optimeringsproblemer.

DM507 Algoritmer og datastrukturer

Invarianter. Invariant: Et forhold, som vedligeholdes af algoritmen gennem (dele af) dens udførelse. Udgør ofte kernen af ideen bag algoritmen.

Lineære differentialligningers karakter og lineære 1. ordens differentialligninger

Grundlæggende Matematik

Forelæsning Uge 4 Torsdag

Matematisk Metode. Jesper Lützen og Ian Kiming

Et generelt algoritme-konstruktionsprincip ( paradigme ) for optimeringsproblemer. Ideen er simpel:

Skriftlig Eksamen Kombinatorik, sandsynlighed og randomiserede algoritmer (DM528)

Klassen er sammenlæst, altså 5 og 6 klasse på en og samme tid. Samtidig er klassen pt på ca 11 elever ialt.

Reeksamen i Diskret Matematik

Sortering af information er en fundamental og central opgave.

DM507 Algoritmer og datastrukturer

DM536. Rapport og debug

3. klasse 6. klasse 9. klasse

16. december. Resume sidste gang

Skriftlig Eksamen Diskret Matematik (DM528)

Affine rum. a 1 u 1 + a 2 u 2 + a 3 u 3 = a 1 u 1 + (1 a 1 )( u 2 + a 3. + a 3. u 3 ) 1 a 1. Da a 2

DM507 Algoritmer og datastrukturer

Sammenhængskomponenter i grafer

Årsplan matematik 8. klasse

Opgaver hørende til undervisningsmateriale om Herons formel

DM507 Algoritmer og datastrukturer

Gruppeteori. Michael Knudsen. 8. marts For at motivere indførelsen af gruppebegrebet begynder vi med et eksempel.

Vurdering af kvalitet en note af Tove Zöga Larsen

DM507 Algoritmer og datastrukturer

3 Algebraisk Specifikation af Abstrakte Datatyper.

Import af rekursivt (parent-child) hierarki i Palo

Sortering af information er en fundamental og central opgave.

Sortering. Eksempel: De n tal i sorteret orden

PHP 3 UGERS FORLØB PHP, MYSQL & SQL

Transkript:

-1 Kontraktbaseret Programmering Anker Mørk Thomsen 1. udgave ISBN: 978-87-40-41315-1

Forord Denne bog er blevet til gennem undervisning i faget Kontraktbaseret Udvikling på bacheloruddannelsen i Softwareudvikling. Emnet har jeg opdelt i to dele. Den første del omfatter konstruktion og udvikling af algoritmer ved at anvende formelle metoder. Denne første del indeholder også diskret matematik, som danner grundlag for at kunne arbejde med de formelle metoder. Bog 1 indeholder pensum for den første del af faget, som kaldes Kontraktbaseret Programmering. Bog 2 Kontraktbaseret Design omhandler design af programmodulerne i et objektorienteret sprog. Januar 2014 Anker Mørk Thomsen 0

Indhold I Matematik 9 1 Matematisk argumentation 10 1.0.1 Deduktive argumentationsformer....................... 11 1.0.1.1 Modus Ponens............................. 12 1.0.1.2 Modus Tollens............................. 12 1.0.1.3 Den hypotetiske syllogisme..................... 12 1.0.1.4 Den disjunktive syllogisme...................... 13 1.0.1.5 Reductio ad Absurdum........................ 14 1.0.1.6 Afslutningsvis om argumentation.................. 14 1.1 Notation.......................................... 15 1.2 Det direkte bevis..................................... 16 1.3 Det indirekte bevis.................................... 17 1.4 Bevis ved modstrid (Proof by contradiction)...................... 17 1.5 Bevis ved at opdele i flere tilfælde........................... 19 1.6 Simpel Induktion..................................... 19 1.7 Øvelser........................................... 21 1.8 Stærk Induktion...................................... 22 1.9 Strukturel induktion................................... 23 1.10 Beviser med fejl...................................... 24 1.11 Simple og vanskelige påstande............................. 25 1.12 Spilteori.......................................... 25 1.13 Øvelser........................................... 26 I

INDHOLD II 2 Mængder og logik 27 2.1 At definere mængder ved hjælp af egenskaber.................... 31 2.2 Mængdeoperationer boolsk algebra.......................... 32 2.2.1 Boolsk Algebra.................................. 35 2.3 Kardinalitet........................................ 36 2.4 Relationer......................................... 37 2.4.1 Relationelle databaser.............................. 38 2.4.2 Binære relationer................................. 39 2.4.3 Ordningsrelationer................................ 40 2.5 Funktioner......................................... 41 2.6 Venn-diagrammer..................................... 41 2.7 Øvelser........................................... 43 3 Udsagnslogik 45 3.0.1 Øvelser....................................... 47 3.1 Boolske operatorer.................................... 47 3.2 Boolske udtryk...................................... 49 3.2.1 Øvelser....................................... 51 3.3 Regneregler for de boolske operatorer......................... 51 3.3.1 Øvelser....................................... 52 4 Prædikatlogik 54 4.0.2 Øvelser....................................... 56 4.1 Tilfredsstillelsesmængden................................ 56 4.1.1 Øvelser....................................... 57 4.2 Kvantificerede udtryk.................................. 57 4.2.1 Kvantorer..................................... 59 4.2.2 Øvelser....................................... 60 4.3 Regneregler for kvantificerede udtryk......................... 61 4.3.1 Et-punkts-reglen................................. 61 4.3.2 Sammensætte og adskille termer........................ 61 4.3.3 Sammensætte og adskille rangen........................ 62 4.3.4 Distribution.................................... 62

INDHOLD III 4.3.5 Den tomme rang................................. 63 4.3.6 Konstant term................................... 63 4.3.7 Øvelser....................................... 63 4.4 Associativitet....................................... 64 4.4.1 Associative operatorer.............................. 64 4.4.2 Venstre-associative operatorer......................... 64 4.4.3 Højre-associative operatorer........................... 64 4.5 De logiske kvantorer................................... 64 4.5.1 Alkvantoren.................................... 64 4.5.2 Eksistenskvantoren................................ 65 4.5.3 Øvelser....................................... 65 4.6 Mere om prædikater og kvantificerede udtryk.................... 66 II Programkonstruktion 67 5 Imperative Programmer og Programtilstande 68 5.1 Lidt om Java........................................ 68 5.1.1 Variabler i Java.................................. 71 5.1.2 Værdier og referencer.............................. 72 5.1.3 Lidt om udførelse af Java-programmer.................... 72 5.1.4 Programtilstande................................. 73 5.1.5 Øvelser....................................... 77 5.2 Korrekthed......................................... 77 5.2.1 Øvelser....................................... 79 5.3 Hvad er programmering?................................ 79 5.4 Specifikationer....................................... 80 5.4.1 Øvelser....................................... 86 6 Programnotation 87 6.1 Programmeringssprogets kommandoer........................ 87 6.1.1 skip......................................... 87 6.1.2 abort........................................ 88 6.1.3 Sekvens af kommandoer............................. 88

INDHOLD IV 6.1.4 Tilordningskommandoen............................ 89 6.1.5 Selection eller alternativer, IF.......................... 91 6.1.6 Iteration eller gentagelse, DO.......................... 93 6.1.7 Non-determinisme................................ 94 6.1.8 Klasser og interface-moduler.......................... 95 6.1.9 Funktioner..................................... 95 6.1.10 Procedurer..................................... 95 6.2 Eksempler......................................... 96 6.2.1 Udvalgssortering................................. 96 6.2.2 Beregning af de første n Fibonacci-tal..................... 96 6.3 Øvelser........................................... 97 7 Prædikattransformeren WP 98 7.1 Korrekthed......................................... 98 7.2 Semantik.......................................... 101 7.2.1 Prædikattransformeren wp........................... 101 7.3 Prædikattransformeren wp s egenskaber........................ 102 7.3.1 Øvelser....................................... 104 7.4 Programmeringssprogets semantik - skip, abort og tilordning................................ 104 7.4.1 Sætningen skip................................... 104 7.4.2 Sætningen abort.................................. 104 7.4.3 Tilordningssætningen.............................. 105 7.4.4 Øvelser....................................... 107 7.5 Semantik: Array-variabler................................ 107 7.5.1 Øvelser....................................... 110 7.6 Programmeringssprogets semantik: Sekvens..................... 110 7.7 Programmeringssprogets semantik: IF-sætningen.................. 112 7.7.1 Øvelser....................................... 114 7.8 Programmeringssprogets semantik: DO-sætningen................. 115 7.8.1 Kaffekandeproblemet............................... 115 7.8.2 DO-sætningens semantik............................ 116 7.8.3 Øvelser....................................... 118 7.9 Checklisten for løkker.................................. 119 7.9.1 Øvelser....................................... 121

INDHOLD V 8 Udvikling af programmer uden løkker 125 8.1 At beregne udtryk i tilordningssætninger....................... 126 8.1.1 Øvelser....................................... 129 8.2 Udvikling af IF-sætninger................................ 130 8.2.1 Øvelser....................................... 134 9 Konstruktion af løkker 136 9.1 Konstruktion af løkker.................................. 136 9.2 Metoden.......................................... 137 9.2.1 Opsummering af metoden............................ 141 9.3 Effektivisering....................................... 142 9.4 Øvelser........................................... 143 10 At slette en konjunkt 144 10.1 Slette en konjunkt..................................... 144 10.1.1 Heltalsdivision.................................. 144 10.1.2 Beregne heltalsdelen af n........................... 147 10.1.3 Ubegrænset lineær søgning........................... 149 10.1.4 Anvendelser af ubegrænset lineær søgning.................. 152 10.1.5 Sortering af tre værdier............................. 153 10.1.5.1 Konstruktion af invariant og variant................ 153 10.1.5.2 Løkken................................. 154 10.1.6 Begrænset lineær søgning............................ 156 10.1.7 Øvelser....................................... 158 11 Erstatte en konstant med en variabel 160 11.1 Erstatte konstanter med variabler............................ 160 11.1.1 Øvelser....................................... 163 11.2 Beregne heltalsdelen af n............................... 163 11.3 Binær søgning generelt.................................. 166 11.4 Anvendelser af binær søgning.............................. 170 11.4.1 Den mest brugte anvendelse af binær søgning................ 170 11.4.2 Beregne heltalsdelen af n........................... 172 11.4.3 Øvelser....................................... 172 11.5 Begrænset lineær søgning (igen)............................ 173

INDHOLD VI 12 At forøge en variabels virkefelt 176 12.1 At forøge en variabels virkefelt.............................. 176 12.1.1 Den sociale bedrager............................... 177 12.1.2 Øvelser....................................... 181 A Løsninger til udvalgte øvelser 182

Introduktion En kravspecifikation er en aftale mellem systemudvikleren og aftageren. Kravspecifikationen beskriver de egenskaber, der kræves af det færdige produkt. Til brug for skrivning af kravspecifikationer anvendes mange forskellige beskrivelsesværktøjer, hvoraf nogle er formelle og andre er uformelle, dvs. baseret på figurer, tegninger, eksempler, benchmarks og tekstlig beskrivelse. De formelle specifikationer kan være formuleret i diagrammer eller formelle sprog. I praksis anvendes en blanding af de forskellige beskrivelsesformer. Se Søren Lauesen: Software Requirements. Styles and Techniques Lauesen [2000], som indeholder en udførlig beskrivelse af metoder og teknikker til at danne kravspecifikationer i samarbejde med brugere. Bogen indeholder desuden en række gennemarbejdede eksempler. Se også hjemmesiden Søren Lauesen. En kravspecifikation er i denne sammenhæng en aftale mellem systemudvikleren og slutbrugeren. I Kontraktbaseret Udvikling fokuserer vi på aftaler mellem systemudviklere, hvor den ene er klient og den anden aftager. Den samme systemudvikler eller programmør kan have begge roller. Kontrakterne er i Kontraktbaseret Udvikling aftaler om programmodulers funktionelle egenskaber. Lad os antage, at en programmør skal udvikle et programmodul, og at hun har tænkt sig at anvende et modul, som andre har skrevet. Det modul, der skal anvendes kalder vi en server. Det modul, som skal udvikles, kalder vi en klient. I kontraktbaseret udvikling udstyrer vi serveren med en specifikation, der beskriver, i hvilke procestilstande programmøren må anvende modulet. Programmøren, der skal udvikle klienten, skal altså sikre sig, at procedurer og funktioner i serveren kun kaldes i de programtilstande, som er anført i kravspecifikationen som gyldige tilstande. Under forudsætning af, at serveren anvendes korrekt, så skal specifikationen beskrive serverens funktion. Specifikationen skal altså beskrive serverens virkning. Vi siger, at der er en kontrakt mellem klient og server. På den anden side, hvis serveren anvendes forkert, så kan klienten ikke stille krav til serverens funktion. Kontrakten beskriver på den måde, hvad programmet eller programmodulet skal udføre. Det er så programudviklerens opgave at sikre konstruktion af et korrekt program, det vil sige et program, der lever op til kontrakten. Kontrakter indgås altså mellem programudvikleren, som kan være en systemudvikler eller en programmør, og de systemudviklere, der skal anvende programmet til konstruktion af andre programmer. I Kontraktbaseret Udvikling beskæftiger man sig altså ikke med aftaler med slutbrugere. Design af brugergrænsefalden og databasedesign ligger derfor udenfor emneområdet for Kontraktbaseret Udvikling. I forhold til en slutbruger kan det opfattes som en dyd at skrive programmer, der kan acceptere ethvert input, som brugeren kan finde på at anvende. Vi kan godt lide robuste programmer. 1

INDHOLD 2 Man kan vejlede eller tvinge slutbrugeren til at gøre det rigtige. Mellem programmoduler er sagen en anden. Her stiller vi eksplicitte krav til klienten. En kontrakt mellem klient og programmør kan være mere eller mindre formaliseret. I mange tilfælde er kontrakter løst formulerede og upræcise. Prøv blot at kigge på dokumentationen af klasserne i Java. Se Java SE 7 API Documentation. En kontrakt kaldes også en specifikation, og den består af mindst følgende to dele: En præbetingelse, der beskriver i hvilke tilstande, programmet eller programdelen må udføres. For en metode er præbetingelsen en beskrivelse af de tilstande 1, hvor man må kalde metoden. Hvis man ikke overholder præbetingelsen, kan man ikke kræve, at programmet opfylder postbetingelsen. Den, der kalder en metode i en ugyldig tilstand, kan ikke stille krav til resultatet. En postbetingelse, der beskriver programmets eller programmodulets resultat. Postbetingelsen beskriver de mulige tilstande, som programmet vil etablere under udførelsen, forudsat at programmet starter udførelsen med præbetingelsen opfyldt. Eksempel 0.1. En procedure, der sorterer en liste af typen Person, kan beskrives uformelt ved en specifikation i stil med /*@ pre Det forudsættes, at alle elementer i listen er af typen Person @ post Listen l er sorteret i ikke-aftagende orden @*/ void sorter(list l) hvor pre er præbetingelsen og post er postbetingelsen. Den uformelle specifikation er altså skrevet som en kommentar. Nøgleordt pre angiver præbetingelsen, og nøgleordet post angiver postbetingelsen. Specifikationen anvender JML-syntaks. Se figur 0.0.1. Her følger et eksempel på en uformel specifikation af en funktion, der returnerer det største tal i en talrække. Variablen r gør det muligt at referere til funktionens returværdi (resultat). /*@ pre t.length>0 @ post r >= alle tal i t @*/ func max(int[] t)->double r 1 En tilstand er en funktion fra mængden af variabler til de tilhørende værdier. Man medtager i beskrivelsen af tilstande kun de variabler, som er berørt af programmet eller programmodulet.

INDHOLD 3 Figur 0.0.1: Kontrakt for et program Udover pre- og postbetingelsen består kontrakter for procedurer og funktioner desuden af et hoved, der beskriver modulets navn, metodens parametre og evantuelt returtype. Modulets hoved kaldes ofte modulets signatur. For at anvende modulet (kalde funktionen eller proceduren) korrekt, skal man overholde de typer, som signaturen angiver for parametre og returtype. Signaturen er en syntaktisk specifikation. Præ- og postbetingelser er semantiske specifikationer, som omhandler virkningen af at anvende metoden. Formaliserede kontrakter er formuleret i et matematisk sprog eller i et programmeringssprog og består af udsagn om programmets variabler. Sådanne udsagn kaldes prædikater. Prædikater er udsagn, der kan være sande eller falske. Et prædikat P(x, y) er altså et udsagn eller påstand om variablerne x og y. Udsagnets værdi er enten sand eller f alsk afhængig af indholdet af variablerne x og y. I programmeringsssprog kalder vi ofte prædikater for logiske udtryk eller boolske udtryk. Eksempelvis er x>y+k et prædikat. Sandhedsværdien afhænger af de aktuelle værdier af variablerne x, y og k. I tilstanden {x = 3, y = 2, k = 2} er udtrykket sandt. I tilstanden {x = 3, y = 1, k = 4} er udtrykket falsk.

INDHOLD 4 Vi vil arbejde med at formulere kontrakter i form af prædikater. Desuden vil vi anvende de formelle kontrakter på to måder. Vi vil anvende kontrakter som værktøj til at udvikle programmerne, og vi vil anvende kontrakter som grundlag for afprøvning (test) af programmerne. Vi har til hensigt at tilegne os og anvende en teknik, hvor man ud fra en specifikation (kontrakt) konstruerer et program eller et programmodul. Principielt er en specifikation i sig selv et program. Hvis man havde en virtuel maskine til rådighed, som kunne fortolke kontrakten direkte, så ville man slippe for arbejdet med at omforme kontrakten til et andet sprog. I en vis forstand er det netop, hvad man gør i et sprog som SQL. Her beskriver man ikke en beregningsproces. Man beskriver det ønske resultat. F. eks. beskriver select distinct nr from T where T.nr>7 at man ønsker en tabel (relation) med attributten nr. Værdierne i kolonnen nr skal alle være større en 7 og der må ikke forkomme to ens værdier. Værdierne i A skal hentes fra tabellen T. Man kalder også et sprog af denne type for et deklarativt sprog. Man kan med en vis ret sige, at SQL-sætningen er en udførbar specifikation. Hvis vi derimod skriver // T er en given relation create empty relation R foreach (Row r in T){ if (r.nr>7) R.addRow(r) } er der tale om at beskrive en fremgangsmåde til beregning af resultatet. Her er der tale om et imperativt program. Programmet består af en række kommandoer, som skal udføres i en bestemt rækkefølge. De programmer, som vi skal arbejde med, kaldes imperative programmer. Imperative programmer fører under udførelsen computeren fra en starttilstand til en sluttilstand. De fleste af de programmeringssprog, som benyttes i praksis, er imperative, hvor programmerne udføres gennem en række trin, der hver ændrer på computerens tilstand. Der findes dog mange programmeringssprog, der ikke er imperative. Vi har allerede nævnt SQL. Af andre sprogparadigmer kan nævnes funktionelle sprog (f. eks. Lisp og Haskell) og logiksprog (f.eks. Prolog). Se Wikipedia 2. En programs tilstand består af en mængde af benævnte værdier. Navnene kalder vi variabler, og værdierne tages fra de sædvanlige værdimængder: Hele tal, naturlige tal, brøker, tegn osv. 2 Java og C # er også imperative sprog. Der findes også objektorienterede funktionelle sprog.

INDHOLD 5 En tilstand er en afbildning (funktion) fra mængden af variabler til værdier, og vi kan beskrive en tilstand ved en tabel: Tilstand 0 : a 23 x 4.5 i 7 Tilstand 1 : a 23 x 5 i 7 Tilstand 0 og Tilstand 1 adskiller sig kun ved værdien af variablen x. Begge tilstande er præcist beskrevet, idet vi kender den præcise værdi af variablerne. Udførelsen af et program kaldes en proces. En program begynder udførelsen i en starttilstand, hvor alle variabler i programmet har givne værdier eller eventuelt ukendte værdier, og programmet slutter udførelsen i en sluttilstand, hvor variablerne har værdier, som er etableret gennem programmets udførelse. I en konkret udførelse kan man eventuelt aflæse disse værdier ved hjælp af en debugger. I nogle tilfælde kan det således ske, at et program må starte i en ukendt tilstand. Et sådant program har en startbetingelse, der er sand, dvs. programmet må udføres i enhver starttilstand. Som programmør og som udvikler er man normalt ikke interesseret i de konkrete tilstande, som et program gennemløber under udførelsen med et givet input. De konkrete tilstande er kun interessante for den, som vil følge udførelsen af programmet med et givet input. I stedet er det interessant at se på forholdet mellem input og output og i de mulige tilstande, som programmet kan være i under udførelsen. De gyldige inputtilstande bekriver vi i en præbetingelse i form af et prædikat, f.eks. x 0 n > 0. Dette prædikat er sandt i alle tilstande, hvor x er støre end eller lig med 0, dvs. alle ikke-negative værdier af x, og hvor n er positiv. Resultatet af et program beskrives i en postbetingelse igen i form af et prædikat, f. eks. x = b[i], dvs. variablen x har samme værdi som variablen b[i]. Prædikater er boolske funktioner dvs. funktioner, der kan antage en af værdierne true og f alse, afhængig af værdierne af de variabler, som ingår i prædikatet. Prædikatet x 0 n > 0 er således f alse i tilstanden {x = 1, n = 2} og true i tilstanden {x = 2, n = 3}. Antag, at b er arrayen int[] b = {2, 4, 2, 4, 1} og x = 2 og i = 2. Så er x = b[i] lig med true. Normalt består undervisningen i programmering i, at man simultant lærer et programmeringssprog og at skrive programmer i dette sprog. Man lærer at gætte, hvad programmerne skal indeholde på grundlag af nogle skabeloner og at afprøve programmerne. Hvis afprøvningen ikke giver det ønskede resultat, udfører man en rettelse (evt. ved et nyt gæt) og gentager afprøvningen. Dette fortsætter, indtil man tror, at programmet er korrekt. I denne bog lærer man at konstruere programmer ved at anvende en teknik, hvor programmers indhold (tekst) kan beregnes. Derved opnår man en større sikkerhed for, at programmerne er korrekte. Lad os se på et eksempel. Funktionen /*@ pre true @ post r er den midterste værdi af x, y og z @*/ func midt(int x, int y, int z)->int r {... }

INDHOLD 6 påstås ifølge specifikationen at returnere den midterste værdi af de tre tal: x, y og z. F. eks skal kaldet midt(7,3,12) returnere værdien 7. Vi har ikke vist kildekoden til funktionens krop. Antallet af forskellige mulige input til midt(x,y,z) er (2 32 ) 3 = 2 96. En afprøvning af alle mulige input er i praksis umuligt. Ved at vælge en teststrategi, kan vi afprøve udvalgte input. Det kan bruges til at øge tilliden til, at funktionen regner rigtigt. Men vi kan i princippet kun være sikker, hvis alle muligheder er afprøvet. Hvis et input giver en fejl, f. eks. hvis midt(-7,3,12)=-7, så er vi blevet oplyst. Vi ved, at der er en fejl, og vi kan rette i programmet, så fejlen forsvinder. Desværre kan rettelsen give anledning til nye fejl. Læren af dette er. Hvis funktionen regner rigtigt med et givet input, er vi ikke blevet meget klogere. De 2 96 1 andre input mangler at blive afprøvet. Gennem afprøvning af programmer kan man i bedste fald afsløre, om der er fejl. Det er generelt ikke muligt gennem afprøvning at afgøre, om et program er korrekt. Den eneste måde, hvorpå vi kan bevise, at funktionen regner rigtigt for alle gyldige input, er ved at studere, hvorledes funktionen er programmeret. Dette kræver, at vi studerer kildekoden. Skal man så ikke anvende test. Jo, test bør være en del af de værktøjer, som vi bruger til at øge sikkerheden for, at vore programmer regner rigtigt. Den teknik, som bogen benytter, er baseret på matematik og især på anvendelse af logik. Det er derfor nødvendigt, at den studerende bliver fortrolig med denne disciplin. Man skal være fortrolig med almindelig algebra (aritmetik), mængdelære, udsagnslogik og prædikatkalkyle for at kunne arbejde med udvikling af programmer efter bogens teknik. Besværet med at lære dette lønner sig, idet man som programmør opnår en større sikkerhed i at skrive korrekte programmere. I tilgift reducerer man den tid, man ellers skulle anvende til test. At udvikle programsystemer til computere er en vanskelig og udfordrende opgave. Hvis kravene til et program er upræcise og uklare, er opgaven også at finde ud af, hvilken opgave programmet skal løse. Upræcise beskrivelser af krav og ønsker til programmer er en kilde til mange fallerede projekter. De fleste har lært programmering baseret på uformelle, tekstlige og til tider upræcise beskrivelser af, hvad programmerne skal udføre. Samtidig har man udviklet programmerne baseret på intuition og gætteri kombineret med erfaring. De fejl, der opstår ved denne fremgangsmåde, kalder man lus (eng. bugs), og man investerer mange kræfter i at finde og rette fejl, kaldet aflusning (eng. debugging). Problemet er, at man ikke kan vide, om en funden fejl er den sidste, eller om rettelse af fejlen har introduceret flere fejl. Ved aflusning af store systemer såsom operativsystemer, store administrative systemere mv. vil man ofte introducere nye fejl. Allerede i 1960 erne blev det klart, at fejlbehæftede programmer var et stort problem. Dette gjaldt ikke mindst operativsystemer. Et operativsystem kunne indeholde omkring 1000 alvorlige fejl. F. eks. udsendte CDC hver uge rettelser til operativsystemet på deres CDV 6400. Rettelserne kom på hulkort og fyldte flere hundrede hulkort. Hver rettelsesrunde gav anledning til nye fejl; men antallet af fejl, der skulle rettes hver uge blev mindre og mindre. På et tidpunkt valgte man at udsende en ny version af operativsystemet. Men også applikationer kunne give anledning til alvorlige problemer, hvis programmerne havde fejl. Englænderen C. A. R. Hoare foreslog i artiklen An Axiomatic Basis for Computer Programming Hoare [1969] at indføre en formel matematisk metode til at hjælpe med at skrive

INDHOLD 7 korrekte programmer. Det er i stor udstrækning en videreudvikling af denne metode, som bliver præsenteret i denne bog. I bogen A Dicipline of Programming Dijkstra [1976]beskriver E. W. Dijkstra udførligt idéen bag de teknikker, vi skal arbejde med. Bertrand Meyer introducerede i programmeringssproget Eiffel begrebet Design by Contract, hvor man kan forsyne programmer med formelle specifikationer (se f. eks. Meyer [2009]), der fastlægger kravene til input (præbetingelser) og præcise beskrivelser af output (postbetingelser). Disse krav kan så blive kontrolleret under udførelsen af programmet. Kontrol af formelle specifikationer under udførelse af et program svarer til at udføre en test. Hvis udførelsen gennemføres uden fejlreaktioner, har man kun sikret sig, at programmet udføres korrekt med de givne inputdata og i de givne omgivelser. Det beviser ikke, at programmet er korrekt. Vi vil benytte de formelle specifikationer til at konstruere korrekte programmer. På samme måde, som ingeniører anvender matematik som værktøj til at konstruere bygninger, maskiner, broer mv, vil vi anvende matematik til at konstruere programmer. Dette kræver dels, at vi tilegner os de matematiske værktøjer, som skal anvendes til konstruktionen og dels, at vi lærer at skrive præcise formelle specifikationer. Den matematik, som vi benytter os af, kaldes diskret matematik, idet den i modsætning til den matematik, som ingeniører og fysikere benytter sig af, ikke behandler kontinuerte størrelser, men alene arbejder med størrelser, der kan antage diskrete (adskilte) værdier, såsom hele tal og boolske værdier (falsk og sand). Vi anvender diskret matematik, fordi den digitale computer kun kan arbejde med hele tal. Alt, hvad der lagres i en computer og alt, hvad der behandles i en computer, er hele tal. I computeren er tallene repræsenteret på binær form, dvs. hvor kun cifrene 0 og 1 anvendes. Al information i en computer er således kodet ved brug af hele tal. En omfattende præsentation af diskret matematik findes i David Gries og Fred B Schneiders A logical Approach to discrete Math Gries and Schneider [1993]. Den del af diskret matematik, som vi har speciel interesse i er: Mængder Relationer Funktioner Udsagnslogikken Prædikatkalkulen Til brug for programmering vil vi arbejde med: En simpel programnotation, som er en modificeret delmængde af sproget Java. Herved får vi adgang til at afprøve programmerne, hvis dette er ønskeligt. Programsemantik ved brug af prædikattransformeren wp (weakest precondition)

INDHOLD 8 Programsemantik er beskrivelsen af virkningen af udførelse af et program. Typisk beskriver man virkningen af de enkelte sætningstyper i sit programmeringssprog. I Java vil vi således beskrive virkningen af tilordningssætninger, if-sætninger og while-sætninger mv. Valget er faldet på wp, da det er et kraftfuldt værktøj, og da det umiddelbart er muligt at anvende wp til at konstruere programmer, der opfylder givne postbetingelser.

Del I Matematik 9

Kapitel 1 Matematisk argumentation Dette kapitel handler om at kunne forstå og gennemføre en matematisk argumentation for, at et udsagn eller en påstand er sand. En matematisk argumentation for en påstand kaldes et bevis. Det matematiske bevis er baseret på anvendelse af symboler og nogle faste slutningsregler og adskiller sig i præcision og entydighed fra den måde, hvorpå vi argumenterer for en påstand i dagligt sprog. Alligevel er der en klar sammenhæng mellem matematisk bevisførelse og dagligdagens argumentation. Lad os tage et eksempel fra Sherlock Holmes i historien»silver Blaze«Doyle. Sherlock Holmes siger: A dog was kept in the stalls, and yet, though someone had been in and fetched out a horse, the dog had not barked... Obviously the visitor was someone whom the dog knew well... Holmes argumentation indeholder to præmisser. Den første er»hunden gøede ikke ad den besøgende i stalden«. Den anden præmis er implicit, nemlig at»hunde gør ikke af folk, de kender«. De to præmisser medfører, at»hunden kendte den besøgende«. Dette er et eksempel på en type argumentation, som vi kender fra dagligdagen. I matematikken ville man opstille begge præmisser, så det var tydeligt, på hvilket grundlag man drog sin slutning. I matematikken ville man opstille argumenationen således: 1. Præmis. Hunden gøede ikke af den, der kom ind i stalden. 2. Præmis. Hunde gør ikke af folk, de kender. 3. Konklusion. Ergo, hunden kendte den besøgende. Læg mærke til det underforståede alle i præmissen Hunde gør ikke af folk, de kender. Der menes, at alle hunde opfører sig på den måde. Men der kan jo være hunde, som opfører sig anderledes. Nogle hunde ville gø af glæde ved at se en person, som de kender. Men vi udtaler os ikke om rigtigheden af præmisserne. Vi udtaler os kun om argumentationen, dvs. 10

KAPITEL 1. MATEMATISK ARGUMENTATION 11 hvis præmisserne er sande, så er slutningen også sand. Sherlock Holmes mener altså, at hans præmisser holder. Og det er netop akilleshælen i hans metode. Måske holder hans præmisser ikke. Selv om resultatet af et argument er forkert, kan selve argumentationen være rigtig. F. eks. Præmis. Alle rige mennesker bor nord for København Præmis. X er rig Konklusion. Altså bor X nord for København Argumentationen er korrekt, men mindst den ene præmis er forkert. Hvilken? Argumentationsformen er et eksempel på en syllogisme. En syllogisme er en logisk slutning, som består af to eller flere præmisser og en konklussion. Præmisserne og konklusionen skal være såkaldte katagoriske udsagn, dvs. udsagn om, at der består en given relation mellem to genstande eller begreber. I eksemplet ovenfor er der en relation mellem rige mennesker og København samt mellem X og rige mennesker. Begrebet rige mennesker er mellembegrebet, som knytter X til København. Se Weston [1992]for mere information om syllogismer. Man kan også hente information om syllogismer på Internet, f. eks. i Den store Danske. Se også Wikipedia. Linket til Wikipedia indeholder en oversigt over forskellige former for syllogismer. På Ludvig Holbergs tid var studiet af syllogismere en vigtig del af universitetsuddannelserne. Her følger et eksempel på en ukorrekt syllogisme hentet fra Ludvig Holbergs skuespil Erasmus Montanus. Rasmus Berg var på besøg i sit hjem, og han ville brillere med det, han havde lært på universitetet. Her er hans syllogisme. En sten kan ikke f lyve Morlille kan ikke f lyve Ergo er morlille en sten Der er ingen egenskab, der forbinder en sten med morlille. At de har samme egenskab, nemlig ikke at kunne flyve gør dem ikke ens. Der er intet mellembegreb som i argumentationen ovenfor på denne side. Her er rig mellembegrebet, der forbinder X med bor nord for København. 1.0.1 Deduktive argumentationsformer Vi skal se på nogle metoder, som kan anvendes ved argumentation for påstande. Metoderne baseres på det, vi kalder en implikation P Q. Hvis P er sand, så er Q også sand.