Grundlagen der Programmierung 1 Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Teil 2 - Softwaretechnik Übersicht 1. Einführung 2. Entwurf von Algorithmen 3. Verifikation, Testen und Debugging 4. Vorgehensmodelle Prof. Dr. O. Drobnik Professur Architektur und Betrieb verteilter Systeme Institut für Informatik Fachbereich Informatik und Mathematik WS 2008/09 Überblick der Vorlesung Grundlagen der Programmierung 1 Programmentwicklung als Vorgang Korrektheit Testen Debugging Einführung Kap. 3 Kapitel 1 - Einführung Kap. 1 Softwaretechnik (Systematisierung der Sw-Entwicklung) Entwicklungsphasen und Vorgehensmodelle Kap. 4 Beispiele 1. Systematische Entwicklung von Programmen: Beispiel: größter gemeinsamer Teiler (ggT) Entwurfsmethoden 2. Algorithmenentwurf Beispiel: Suchen • Naiver Ansatz Kap. 2 Entwurf von Algorithmen • Alternativer Ansatz Konkrete Problemlösungen Grundlagen der Programmierung 1 Softwaretechnik © J.W.G-Universität Frankfurt a.M. Folie 3 1. Systematische Entwicklung von Programmen: Beispiel: größter gemeinsamer Teiler (ggT) Lernziele Problem: ggT(b,c) Programmentwicklung als Vorgang Problem: ggT(b,c) Entwurf von Algorithmen Problem: Suchen in Listen 2 alternative Lösungsansätze Einführung in die Softwaretechnik Systematisches Testen Begriffe Spezifikation Korrektheit Ermittlung des größten gemeinsamen Teilers (ggT) zweier natürlicher Zahlen b,c > 0 Definition von ggT(b,c): ggT(b,c) = max{ k : k | b ⋀ k | c ⋀ k ε Nat ⋀ k > 0 } Es bedeutet: k | b : k teilt b ohne Rest ⋀ : logisches Und (Konjunktion), Aussagenlogik Beispiel: ggT(24,9)=3 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 5 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Begriff Spezifikation Entwurf einer konkreten Lösung Spezifikation: Entwurf eines Algorithmus: Beschreibung der Funktionalität eines Programms, d.h. welches Problem ist zu lösen, ohne einen konkreten Lösungsweg oder Lösungsschritte vorzuschreiben. Folie 6 Entscheidung: Algorithmus von Euklid (ca. 300 v. Ch. , Algorithmus ist wahrscheinlich 200 Jahre älter). Für b>0, c>0 gilt: 1) ggT(b,b) = b Funktionaler Zusammenhang zwischen Ein- und Ausgabe des Programms: 2) ggtT(b,c) = ggT(b-c,c) für b > c 3) ggT(b,c) =ggT(c,b) Gegeben: Zwei natürliche Zahlen b,c > 0 → Eingabe: b,c Gesucht: ggT(b,c) → Ausgabe: x = ggT(b,c) Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 7 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 8 Beispiel ggT(24,9) Ansatz für Algorithmus ggT(24,9) = ggT(24-9,9) 2) ggT(15,9) = ggT(15-9,9) 2) ggT(6,9) = ggT(9,6) 3) ggT(9,6) = ggT(9-6,6) 2) ggT(3,6) = ggT(6,3) 3) ggT(6,3) = ggT(6-3,3) 2) ggT(3,3) = 3 1) Für b>0, c>0 gilt: 1) ggT(b,b) = b 2) ggtT(b,c) = ggT(b-c,c) für b > c 3) ggT(b,c) =ggT(c,b) Ansatz für Algorithmus: Solange 2) und 3) anwenden, bis 1) gilt. © J.W.G-Universität Frankfurt a.M. Grundlagen der Programmierung 1 Folie 9 Algorithmus: Flußdiagramm © J.W.G-Universität Frankfurt a.M. Grundlagen der Programmierung 1 Folie 10 Python-Programm def ggT(b,c): Eingabe: b, c Zuweisung: x=b; y=c if (b <= 0 or c <= 0): # Prüfen der Bedingung raise „Fehler in ggT: b, c > 0 nicht erfüllt!“ x == y? nein x > y? nein x, y = b, c while x != y: ja ja 1) if x > y: 2) 3) u. 2) x=x–y # Regel 2) y=y–x # Regel 2) und 3) else: Ausgabe: x Grundlagen der Programmierung 1 return x © J.W.G-Universität Frankfurt a.M. Folie 11 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 12 Ablaufprotokoll für ggT(24,9) Python-Programm Aufzeichnung der Werte aller Variablen vor und nach jedem Verarbeitungsschritt. def ggT(b,c): if (b <= 0 or c <= 0): # Prüfen der Vorbedingung Überprüfung eines Programms mit Papier und Bleistift. z.B. Darstellung mittels Tabelle: erste Spalte: Nummer der Programmzeile weitere Spalten: Werte von Variablen raise „Fehler in ggt: b, c > 0 nicht erfüllt!“ x, y = b, c # Zeile 1 while x != y: # Zeile 2 if x > y: x=x–y # Zeile 3 y=y–x # Zeile 4 else: return x Folie 13 © J.W.G-Universität Frankfurt a.M. Grundlagen der Programmierung 1 Ablaufprotokoll x 24 15 6 6 3 3 return 3 y 9 9 9 3 3 3 Folie 14 Korrektheit: Algorithmus bzw. Programm erfüllt Spezifikation Vergleich x, y x=x-y 24 > 9 15 > 9 6<9 6>3 3 == 3 15 6 Naheliegender Ansatz: Testen Festlegen eines Testfalls: Vorgeben einer spezifischen Eingabe und der für diese Eingabe gemäß Spezifikation zu erwartenden Ausgabe Ausführung des Programms mit dieser Eingabe Vergleich des Ergebnisses der Programmausführung mit der zu erwartenden Ausgabe y=y-x 3 3 Daraus folgt: unser Programm liefert das für den Testfall ggT(24,9) zu erwartende Ergebnis, mehr nicht! Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Diskussion der Korrektheit Ablaufprotokoll für ggT(24,9): Zeile 1 2,3 2,3 2,4 2,3 2 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 15 Problem: Erschöpfendes Testen i. a. nicht möglich → Systematisches Testen Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 16 Orientierung an Bedingungen Systematisches Testen Systematische Festlegung von repräsentativen Testfällen Bedingungen: 1) b ≤ 0 ⋁ c ≤ 0 a) b ≤ 0 ⋀ c ≤ 0 b) b > 0 ⋀ c > 0 Orientierung: Durchlaufen aller Anweisungen Durchlaufen aller Verzweigungen Durchlaufen aller Pfade im Programm … Mögliche Testfälle: 1) b ≤ 0 ⋁ c ≤ 0 b = 0 c = -2 b = -3 c = 0 b=0 c=0 b=4 c=0 b=0 c=5 Erster Ansatz: Orientierung an Verzweigungen (Bedingungen) 1. Bedingung 2. b≤0 ⋁ c≤0 b>0 ⋀ c> 0 2.Bedingung Bedingung x≠y (b≠c) x=y (b=c) © J.W.G-Universität Frankfurt a.M. Grundlagen der Programmierung 1 Folie 17 Problem 2) b > 0 ⋀ c > 0 b = c : b = c = 100 b > c : b = 24, c = 9 b < c : b = 16, c =25 © J.W.G-Universität Frankfurt a.M. Folie 18 2. Algorithmenentwurf Beispiel: Suchen Systematische Entwicklung von Programmen Phasen: Aktivitäten Analysieren Grundlagen der Programmierung 1 2) x ≠ y : x = y (b = c) x > y (b > c) x < y (b < c) Dokumente: Niederschriften Problembeschreibung Was soll Programm lösen? Spezifikation Algorithmus Entwurf der Lösung: Wie? Konzept des Programms Algorithmus Algorithmus als Programm in einer konkreten Sprache Programm Problem: Suchen Ist ein vorgegebenes Element T in einer aufsteigend sortierten Liste X von Elementen aus der Menge D enthalten? Entwerfen Implementieren Beispiel: X = [10, 20, 30, 40] a) T = 45 : T ∉ X b) T = 30 : T ∈ X Ausgabe: None Ausgabe: 2, da T==X[2] Testen Testat: Warum? Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Testfälle und Ergebnisse Folie 19 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 20 Problembeschreibung Algorithmusentwurf: Naiver Ansatz Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 21 Python Programm Vergleiche T mit jedem Element von X T == X[0] : ja : M = 0, fertig nein : weiter T == X[1] : ja : M = 1, fertig nein : weiter … Spezifikation: Gegeben: Menge D, z.B. natürliche Zahlen. Sortierte Liste X[0 · · · N −1] von Elementen des Typs D X[0] ≤ X[1] ≤ X[2] ≤ . . . ≤ X[N − 1]. T Є D. Eingabe: X, T Gesucht: Ist T Element von X? Ausgabe: Falls Ja: Position M mit T == X[M] Falls Nein: None T == X[N-1] : ja : M = N - 1, fertig nein : Ausgabe None, fertig Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 22 Laufzeit des Algorithmus Der Algorithmus bricht ab, sobald T in X gefunden wird. def search_naive(X,T): N = len(X) for i in range (0,N-1): if T == X[i]: return i return None Ist T nicht in X enthalten, so muß die gesamte Liste X untersucht werden. Enthält die Eingabe N Elemente, so benötigt der Algorithmus maximal N Schritte. Naiver Ansatz berücksichtigt nicht die Information, daß die Liste sortiert ist. Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 23 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 24 Entwurf Algorithmusentwurf: Alternativer Ansatz Binäre Suche Schrittweise Reduktion des Suchbereichs auf Basis der Spezifikation durch systematische Reduktion des Suchbereichs: Grenzen L (Low), U (Upper) ausgehend vom Bereich 0 · · ·N − 1, derart, dass falls T Є X[0 · · ·N − 1] gilt, muss T Є X[L· · ·U] mit 0 ≤ L ≤ U ≤ N − 1 gelten. Schlüsselidee Ausnutzung der Sortierung Reduktion des Suchbereichs durch Vergleich seines mittleren Elements mit T und Verwerfen des irrelevanten halben Bereichs usw. solange, bis T gefunden wird: T Є X, oder ein leerer Bereich erhalten wird. Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 25 Schlüsselidee Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 26 Verfeinerung des Entwurfs Ausgehend vom Bereich 0 · · ·N − 1 sicherstellen, dass falls T Є X[0 · · ·N − 1] gilt, Formalisierung: Prädikat P 2. Initialisierung des Bereichs L = 0, U = len(X) − 1. T Є X[0…N−1] → (T Є X[L· · ·U] Λ 0 ≤ L ≤ U ≤ N−1) „→“ : logische Implikation 3. Prüfe auf leeren Bereich Der Bereich [L…U] ist leer, falls L > U. Wir terminieren die Schleife mit return None Invariante: Prädikat, das „immer“ gültig ist. 4. Mitte des Bereichs (Divide) M = (L + U)/2 Schlüsselidee hat den Charakter einer „Invarianten“. © J.W.G-Universität Frankfurt a.M. Wir stellen sicher, dass alle Aktionen das Prädikat P respektieren. 1. Darstellung von “Bereich” Indizes L (Low) und U (Upper) für obere und untere Grenze des Bereichs T Є X[L· · ·U] mit 0 ≤ L ≤ U ≤ N − 1 gelten muss. Grundlagen der Programmierung 1 Initialisiere Bereich Schleife: { Schlüsselidee } if Bereich == leer: return None Berechne Position M als Ausgangspunkt für die Bereichsreduktion Wird T während des Reduktionsprozesses in X gefunden: return Position von T in X : M Folie 27 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 28 Python Programm Verfeinerung des Entwurfs 5. Vergleiche T mit X[M] und führe entsprechende Aktion zur Bewahrung von P aus (Conquer). (a) X[M] < T: Wir wissen: X[0] ≤ X[1] ≤ · · · ≤ X[M] < T • T ist nicht außerhalb von X[L· · ·U] d.h. T muß in X[M+1 · · ·U] sein. • Bereichsreduktion:L = M + 1 • Invariante P gilt nach wie vor! (b) X[M] == T: def binary_search(X,T): L, U = 0, len(X)-1 while True: if L > U: return None M = (L+U) / 2 if X[M] < T: L = M+1 elif X[M] == T: return M else: U = M-1 T Є X, M Position, Schleife beenden. (c) X[M] > T: Symmetrisch zu (a) mit Bereichsreduktion U = M − 1. Folie 29 © J.W.G-Universität Frankfurt a.M. Grundlagen der Programmierung 1 Laufzeit des Algorithmus Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 30 Literatur [CLRS07] T. Cormen, C. Leiserson, R. Rivest, C. Stein; Algorithmen – Eine Einführung, 2007, Oldenbourg, ISBN 978-3-486-58262-8 Für N=7: Maximal 3 Schritte [LL06] J. Ludewig, H. Lichter, Software Engineering, 2006, Dpunkt Verlag, ISBN 978-3-898-64268-2 [OW02] T. Ottmann, P. Widmayer Algorithmen und Datenstrukturen, 2002, Spektrum Akademischer Verlag, ISBN 3-827-41029-0. X X X X X X X Abschätzung für Anzahl der Schritte: s = ⎡log 2 ( N + 1)⎤ ≈ log 2 ( N ) da in jedem Schritt der Suchraum halbiert wird. [SE02] R. Sedgewick. Algorithms, 2002, Pearson Studium, ISBN 3-8273-7032-9. Zum Vergleich: Naiver Ansatz benötigt s = N Schritte. Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 31 Grundlagen der Programmierung 1 © J.W.G-Universität Frankfurt a.M. Folie 32