3.3 Laufzeit von Programmen Die Laufzeit eines Programmes T(n) messen wir als die Zahl der Befehle, die für die Eingabe n abgearbeitet werden Betrachten wir unser Programm zur Berechnung von Zweierpotenzen, so beobachten wir, dass für n = 1 insgesamt 9 Befehle abgearbeitet werden für n = 2 insgesamt 13 Befehle abgearbeitet werden für n = 3 insgesamt 17 Befehle abgearbeitet werden für n = 4 insgesamt 21 Befehle abgearbeitet werden 53
Berechnen von Zweierpotenzen INPUT 0 OUTPUT 1 0: a <- 1 1: i1 <- s[0] 2: if i1 = 0 then jump 6 3: a <- a * 2 4: i1 <- i1-1 5: jump 2 6: s[1] <- a 7: HALT 54
Laufzeit von Programmen Allgemein gilt für unsere Berechnung von Zweierpotenzen für n werden insgesamt 4n + 5 Befehle abgearbeitet Dies lässt sich mittels vollständiger Induktion anhand von Tabellen beweisen Aussage: A n (d.h. für n werden 4n + 5 Befehle abgearbeitet) Induktionsanfang: Zeige für n = 1 mittels einer Tabelle, dass insgesamt 9 Befehle abgearbeitet werden Induktionsschritt: Zeige für n + 1, dass vier Befehle mehr als für n abgearbeitet werden (d.h. die Schleife bestehend aus den Befehlen 2 5 wird einmal mehr durchlaufen) 55
Schnelleres Berechnen von Zweierpotenzen Wir sehen nun, wie man Zweierpotenzen der Form schneller berechnen kann 2 (2 l ) Berechnen wir 2 16 mit unserem bisherigem Programm, so werden insgesamt 69 Befehle abgearbeitet 56
Schnelleres Berechnen von Zweierpotenzen Wir beobachten, dass für 2 16 gilt 2 16 = 2 2 2 2 2 Eine schnellere Berechnung ist also möglich, indem wir die Zahl 2 viermal quadrieren (d.h. mit sich selbst multiplizieren) Allgemein können wir 2 (2 l) schneller berechnen, indem wir die Zahl 2 l-mal quadrieren 57
Schnelleres Berechnen von Zweierpotenzen Die Eingabe l befindet sich in s[0] und die Ausgabe der Zweierpotenz 2 (2 l) erfolgt in s[1] INPUT 0 OUTPUT 1 0: a <- 2 1: i1 <- s[0] 2: if i1 = 0 then jump 7 3: s[2] <- a 4: a <- a * s[2] 5: i1 <- i1-1 6: jump 2 7: s[1] <- a 8: HALT 58
Schnelleres Berechnen von Zweierpotenzen Berechnen wir beispielsweise 2 128 = 2 (2 7) mit unserem ursprünglichen Verfahren, so werden 517 Befehle abgearbeitet, wohingegen mit dem schnelleren Verfahren nur 40 Befehle abgearbeitet werden 59
Schnelleres Berechnen von Zweierpotenzen Wir können das Verfahren für Potenzen der Form a n mit einer Basis a > 1 und einem Exponenten n 0 verallgemeinern Betrachte hierzu die Binärdarstellung des Exponenten n =(b k...b 0 ) 2 und stelle die Potenz a n dar als a n = a b k 2 k a b k 1 2 k 1... a b 0 2 0 60
Schnelleres Berechnen von Zweierpotenzen Wir können die Potenz a n also berechnen, indem wir k-mal quadrieren (um die Faktoren a 2i zu berechnen) k-mal multiplizieren (um die Faktoren zu multiplizieren) Insgesamt benötigen wir also 2k Multiplikationen Der Wert k ist die Zahl der (benötigten) Bits in der Binärdarstellung des Exponenten n und es gilt k = blog 2 (n)c 61
O-Notation In der Informatik sind wir meist nicht an der genauen Anzahl abgearbeiteter Befehle interessiert, sondern daran wie sich diese für wachsendes n entwickelt Die O-Notation (auch: Landau-Notation) erlaubt uns, Größenordnungen von Laufzeiten auszudrücken Intuitiv bedeutet 4n + 4 O(n), dass die Funktion f(n) = 4n + 4 höchstens so schnell wächst wie die Funktion g(n) = cn für eine positive Konstante c + 62
O-Notation Definition: Für zwei Funktionen f : + und g : + heißt f O(g(n)), wenn es positive Konstanten c + und n 0 gibt, so dass f(n) c g(n) für alle n n 0 gilt 63
O-Notation n Ø n 0 : c g(n) Ø f(n) c g(n) f(n) g(n) n 0 64
O-Notation Beispiel: Betrachten wir die beiden Funktionen f(n) = 4n + 5 und g(n) = n. Wir raten ein c + und bestimmen ein zugehöriges n n 0 4n +5Æ 5n 5 Æ n 65
O-Notation Beispiel: Betrachten wir die beiden Funktionen f(n) = 2n 2 + 3 und g(n) = n 2 und raten c = 3 2n 2 +3Æ 3n 2 3 Æ n 2 Ô 3 Æ n somit ist z.b. für n 0 = 2 unsere Definition erfüllt 66
O-Notation Beispiel: Betrachten wir die beiden Funktionen f(n) = 3n 3 + n 2 und g(n) = n 3 67
O-Notation Wie die Schreibweise f O(g(n)), suggeriert, handelt es sich bei einer Laufzeitklasse O(g(n)) um eine Menge von Funktionen Durch Angabe der Laufzeitklasse eines Programmes charakterisieren wir seine Zeitkomplexität Programme können für Eingaben gleicher Größe n unterschiedliche Laufzeit haben; wir betrachten immer den schlechtesten Fall (worst case), d.h. die maximale Laufzeit für eine Eingabe einer Größe 68
O-Notation Man versucht in der Regel, eine möglichst enge (d.h. kleine) Laufzeitklasse O(g(n)) zu einer gegebenen Funktion f(n) anzugeben Beispiel: Auch wenn log n O(n 317 ) gilt, bevorzugt man die Angabe der Laufzeitklasse O(log n) 69
Regeln zum Bestimmen von Laufzeitklassen Folgende Regeln können angewendet werden, um für eine Funktion f(n) eine möglichst enge Laufzeitklasse zu bestimmen additive Konstanten a 0 dürfen entfallen, d.h. f(n)+a œ O(f(n)) konstante Faktoren a 0 dürfen entfallen, d.h. c f(n) œ O(f(n)) 70
Regeln zum Bestimmen von Laufzeitklassen dominierte Terme dürfen entfallen d.h. können wir die Funktion f(n) umschreiben als f(n) =f 1 (n)+f 2 (n)+...+ f k (n) und gilt für zwei Terme f i (n) O(f j (n)), so kann der Term f i (n) entfallen 71
Wachstum von Funktionen 72
Wachstum von Funktionen f(n) 1 5 10 25 log n 0.00 1.61 2.30 3.22 n 1.00 5.00 10.00 25.00 n log n 0.00 8.05 23.03 80.47 n 2 1.00 25.00 100.00 625.00 n 3 1.00 125.00 1, 000.00 15, 625.00 e n 2.72 14.85 22, 026.47 7, 200, 489, 930.00 73
Wachstum von Funktionen Wie können wir allgemein feststellen, ob die Funktion f(n) schneller wächst als die Funktion g(n)? Betrachte, ob für den Grenzwert des Quotienten gilt lim næœ f(n) g(n) æ Œ Beispiel: Betrachte f(n) = n log n und g(n) = n lim næœ n log n n = lim næœ log n æ Œ 74
Beispiele zum Bestimmen von Laufzeitklassen Beispiel: Bestimme möglichst enge Laufzeitklasse für 3n 4 + 2n 3 + 2n 2 3n 2 + 12n + log n 75
Beispiele zum Bestimmen von Laufzeitklassen n log n + 12 n 13n + log n + 242 76
Beispiele zum Bestimmen von Laufzeitklassen log 17 n O(log n) Hinweis: Logarithmen zu unterschiedlicher Basen unterscheiden sich nur um einen konstanten Faktor 77
Platzkomplexität Analog zur Zeitkomplexität eines Programmes können wir Angaben zu seiner Platzkomplexität machen, d.h. wie viele Speicherstellen S(n) es in Abhängigkeit von der Eingabe n benötigt Die von uns bisher betrachteten RAM-Programme haben alle konstante Platzkomplexität in O(1), da die Zahl der benötigten Speicherstellen nicht von der Eingabe n abhängt 78
Wann ist ein RAM-Programm effizient? Ein RAM-Programm heißt effizient, wenn seine Laufzeit ein Polynom ist, d.h. T(n) O(n k ) für festes k gilt Unser Programm zur schnelleren Berechnung von Zweierpotenzen hat logarithmische Laufzeit in O(log n) Alle Belegungen von n verfügbaren Bits aufzuzählen, hat exponentielle Laufzeit in O(2 n ), da es 2 n mögliche Belegungen gibt 79
Zusammenfassung Schnellere Berechnung von Zweierpotenzen durch wiederholtes Quadrieren Laufzeiten von Programmen werden durch Angabe einer möglichst engen Laufzeitklasse gemäß der O-Notation charakterisiert Regeln zum Bestimmen enger Laufzeitklassen 80
Literatur [1] H.-P. Gumm und M. Sommer: Einführung in die Informatik, Oldenbourg Verlag, 2012 (Kapitel 4.1.5) [2] T. H. Cormen, C. E. Leiserson, R. Rivest und C. Stein: Algorithmen Eine Einführung, Oldenbourg Verlag, 2009 (Kapitel 3) 81