5. Reihungen (Arrays) 4. Verifikation 3. Anweisungen und Kontrollstrukturen 2. Einfache Datentypen 1. Erste Schritte II.1.4. Verifikation - 1 - Semantik der Programmiersprache II.1.4. Verifikation - 2 - z Terminierung: Hält Programm immer an? z Partielle Korrektheit: Falls Programm anhält, erfüllt es Spezifikation? z Totale Korrektheit: Terminierung & Partielle Korrektheit Verifikation: Mathematischer Beweis der Korrektheit keine 100% Sicherheit Testen: Überprüfung für endlich viele Eingaben z natürliche Sprache z grafische Sprachen (UML, ...) z logische Sprachen (Z, VDM, ...) Spezifikation: Angabe, was ein Programm tun soll 4. Verifikation } System.out.println("Die Fakultät ist " + res); } i = i - 1; res = res * i; while (i > 1) { res = 1; i = n; public static void main (String [] arguments) { int n = IO.eingabe(), i, res; Fakultät II.1.4. Verifikation - 3 - } i = i - 1; res = res * i; while (i > 1) { res = 1; i = n; hilft für Programmentwurf und Programmierstil II.1.4. Verifikation - 4 - Wie beweist man so etwas ? Verifikation nötig bei sicherheitskritischen Anwendungen Totale Korrektheit Nach Ausführung ist res = n! Partielle Korrektheit: Programm hält an, weil i in jedem Schleifendurchlauf kleiner wird Terminierung: Programm berechnet (in res) Fakultät von n Spezifikation: Programm P Verifikation < true > P < res = n! > II.1.4. Verifikation - 5 - Hoare-Kalkül: 7 syntaktische Regeln zur Herleitung von Korrektheitsaussagen Partielle Korrektheit ist semantische Aussage Bsp: dann gilt hinterher Nachbedingung ψ. und Ausführung von P terminiert, Wenn vor Ausführung von P Vorbedingung ϕ gilt <ϕ> P <ψ> Spezifikation (zur partiellen Korrektheit) Partielle Korrektheit: Hoare-Kalkül Bsp: <5 = 5> x = 5; <x = 5> x = 5; <5 = 5> <x = 5> II.1.4. Verifikation - 6 - x ist Variable, t ist Ausdruck (ohne Seiteneffekte), ϕ [x/t] ist ϕ mit allen x ersetzt durch t <ϕ [x/t]> x = t; < ϕ > Zuweisungsregel x = 5; <true> <5 = 5> x = 5; <x = 5> <true> x = 5; II.1.4. Verifikation - 7 - true ⇒ 5 = 5 α⇒ϕ <x = 5> <x = 5>, denn: <5 = 5> x = 5; <x = 5> Bsp: <true> <α> P <ψ> <ϕ> P <ψ> Konsequenzregel 1 (Stärkere Vorbedingung) x = 5; <true> <true> <5 = 5> x = 5; <x = 5> <x ≥ 5> x = 5; II.1.4. Verifikation - 8 - x = 5 ⇒ x ≥ 5 ψ⇒β <x ≥ 5> <x ≥ 5>, denn: <true> x = 5; <x = 5> Bsp: <true> <ϕ> P <β> <ϕ> P <ψ> Konsequenzregel 2 (Schwächere Nachbedg.) Bsp: <true> x = 5; res = x * x + 6; <res = 31> <res = 31> II.1.4. Verifikation - 9 - res = x * x + 6; <x = 5> <x * x + 6 = 31> x = 5; <true> <5 = 5> < ψ > Q <β> <ϕ> P Q <β> <ϕ> P <ψ> Sequenzregel <res = y ∧ ¬ x > y > ⇒ <res = max(x,y)> denn: <res = y ∧ x > y > <x = max(x,y)> res = x; <res = max(x,y)> Bsp: <true> res = y; if (x > y) res = x; <res = max(x,y)> und ϕ ∧ ¬B ⇒ ψ II.1.4. Verifikation - 10 - <res = max(x,y)> if (x > y) res = x; <res = y> res = y; <true> <y = y> <ϕ> if (B) {P} <ψ> <ϕ ∧ B> P <ψ> Bedingungsregel 1 <ϕ ∧ ¬ B> Q <ψ> Bsp: <true> if (x < 0) res = -x; else res = x; <res = |x|> und II.1.4. Verifikation - 11 - <res = |x|> res = x; < ¬ x < 0> <x = |x|> <res = |x|> res = -x; denn: <x < 0> <-x = |x|> <ϕ> if (B) {P} else {Q} <ψ> <ϕ ∧ B> P <ψ> Bedingungsregel 2 ¬ i > 1> <i! * res = n!> res = res * i; i = i - 1; denn: <i! * res = n! ∧ i > 1> <(i-1)! * (res * i) = n!> <i! * res = n! ∧ <res = n! > while (i > 1) {res = res * i; i = i - 1; } <i = n ∧ res = 1> <i! * res = n!> i = n; res = 1; <true> <ϕ> while (B) {P} < ϕ ∧ ¬ B > <ϕ ∧ B> P < ϕ > Schleifenregel II.1.4. Verifikation - 12 - invariante ϕ ist Schleifen- < ψ > Q <β> <ϕ> P <ψ> <ϕ> P Q <β> Sequenzregel ψ⇒β <ϕ> P <ψ> <ϕ> P <β> α⇒ϕ <ϕ> P <ψ> <α> P <ψ> Konsequenzregeln <ϕ [x/t]> x = t; < ϕ > Zuweisungsregel ϕ ∧ ¬B ⇒ ψ <ϕ ∧ ¬ B> Q <ψ> II.1.4. Verifikation - 13 - <ϕ> while (B) {P} < ϕ ∧ ¬ B > <ϕ ∧ B> P < ϕ > Schleifenregel <ϕ> if (B) {P} else {Q} <ψ> <ϕ ∧ B> P <ψ> <ϕ> if (B) {P} <ψ> <ϕ ∧ B> P <ψ> Bedingungsregeln Hoare-Kalkül und <V = m ∧ B > P <V < m> Variante ist i, ⇒i ≥ 0 <i = m-1> <i < m> II.1.4. Verifikation - 14 - res = res * i; i = i - 1; <i = m ∧ i > 1> <i-1 = m-1> denn: i > 1 while (i > 1) {res = res * i; i = i - 1; } B⇒V≥0 Für jede Schleife while (B) {P} finde einen int-Ausdruck V (Variante der Schleife), so dass: Terminierung Vorbedingung: a ≥ 0 }} Nachbedingung: res = a + b System.out.println (a + " + " + b + " = " + res); while (x > 0) { x = x - 1; res = res + 1; } //Invariante: x ≥ 0 ∧ x + res = a + b //Variante: x x = a; res = b; public static void main (String [] args) { System.out.print ("Gib 2 Zahlen ein: "); int a = IO.eingabe (), b = IO.eingabe (), x, res; public class Plus { Verifikation der Addition II.1.4. Verifikation - 15 - Vorbedingung: x ≥ y }} Nachbedingung: res = x - y System.out.println (x + " - " + y + " = " + res); while (x > z) { z = z + 1; res = res + 1; } //Invariante: x ≥ z ∧ res = z - y //Variante: x - z z = y; res = 0; public static void main (String [] args) { System.out.print ("Gib 2 Zahlen ein: "); int x = IO.eingabe (), y = IO.eingabe (), z, res; public class Subtract { Verifikation der Subtraktion II.1.4. Verifikation - 16 - }} System.out.println (n + " prim: " + istPrim); II.1.4. Verifikation - 17 - Nachbedingung: istPrim = true gdw. n ist Primzahl while (teiler <= wurzel) { if (n % teiler = = 0) istPrim = false; teiler = teiler + 1; } //Invariante: n ≥ 2 ∧ wurzel = sqrt(n) ∧ // istPrim = keine Zahl i mit 2 ≤ i < teiler teilt n //Variante: wurzel - teiler public class Prim { public static void main (String [] args) { System.out.print ("Gib Zahl ein: "); int n = IO.eingabe (); Vorbedingung: n ≥ 2 int wurzel = (int) Math.sqrt (n), teiler = 2; boolean istPrim = true; Verifikation eines Primzahl-Programms