Powerpoint-Präsentation

Werbung
Eigenschaften von Algorithmen
Klaus Becker
2007
Algorithmen
2



Zielsetzung:

klassische Algorithmen erkunden und dabei

zentrale Eigenschaften von Algorithmen klären
3
Teil 1
Fallstudie: Ägyptische Multiplikation
Ägyptische Multiplikation
4
Algorithmen werden seit den
Anfängen der Mathematik beim
Rechnen benutzt.
Im "Papyrus Rhind" wird
beschrieben, wie in Ägypten Zahlen
multipliziert wurden.
Im Jahre 1858 kaufte der englische Archäologe A.H. Rhind
in Luxor ein aus zwei Stücken bestehendes Papyrus. Erst
einige Jahrzehnte später stellte sich heraus, dass das dritte,
fehlende Mittelstück sich in einem New Yorker Museum
befand. Zusammen hat das Dokument eine Länge von 5,25
m und eine Breite von 33 cm. Es wurde rund 1700 Jahre vor
Christi Geburt geschrieben und enthält viele
Mathematikaufgaben. Heute heißt dieses Schriftstück
Papyrus Rhind.
13 ∙ 12



= 156
siehe:
http://buergernetz.muenster.de/mauritz//matheserver/teller
/aegypten/zahl2.html
Ägyptische Multiplikation
5
Verfahren:
•
Man schreibt die beiden zu multiplizierenden Zahlen nebeneinander.
•
Auf der linken Seite werden die Zahlen jeweils halbiert (Reste abgerundet) und die
Ergebnisse untereinander geschrieben, bis man zur 1 gelangt.
•
Auf der rechten Seite werden die Zahlen verdoppelt und untereinander geschrieben.
•
Die rechts stehenden (verdoppelten) Zahlen werden gestrichen, wenn die links stehende
Zahl gerade ist.
•
Die Summe der nicht gestrichenen rechts stehenden Zahlen ergibt das gesuchte
Produkt.
13 
12
6
24

3 
48

1 
96

156
13 ∙ 12
= 156
6
Aufgabe
Berechnen Sie mit dem beschriebenen Verfahren folgende Produkte:
16*7 =
15*14 =
9*120 =
Überprüfen Sie auch, ob die ermittelten Ergebnisse stimmen.
Aufgabe
7
Entwickeln Sie eine algorithmische Beschreibung des Verdopplungs- und
Halbierungsverfahren in Struktogrammform.
13 
12
6
24
3 
48
1 
96
156
Aufgabe
8
Warum berechnet dieses merkwürdige Verdopplungs- und
Halbierungsverfahren das Produkt von zwei vorgegebenen Zahlen?
Versuchen Sie, sich dies klar zu machen.
13 
12
6
24
3 
48
1 
96
156
9
Algorithmus "Ägyptische Multiplikation"
Die ägyptische Multiplikation würde man heute als Algorithmus so
beschreiben:
Ägyptische Multiplikation
Eingabe: x, y
p := 0
SOLANGE x > 0
x ungerade ?
nein
ja
p := p + y
x := x div 2
y := y * 2
Ausgabe: p
Ein Algorithmus ist eine Verarbeitungsvorschrift, die so präzise formuliert
ist, dass sie auch von einer Maschine abgearbeitet werden kann.
Ablaufprotokoll
10
Mit Hilfe e. Ablaufprotokolls ("Trace-Tabelle")
kann man sich einen ersten Überblick über die
Arbeitsweise des Algorithmus verschaffen.
Ägyptische Multiplikation
Eingabe: x, y
p := 0
SOLANGE x > 0
Bedingung
Anweisung
x
y
13
12
p
x ungerade ?
ja
nein
p := p + y
x > 0
x ungerade
x := x div 2
y := y * 2
Ausgabe: p
x > 0
x ungerade
13 
12
6
24
3

48
1

96
156
x > 0
x ungerade
p := 0
0
p := p + y
x := x div 2
y := y * 2
12
(w)
(w)
(w)
(f)
x := x div 2
y := y * 2
3
48
60
1
96
(w)
(w)
p := p + y
x := x div 2
y := y * 2
x > 0
24
(w)
(w)
p := p + y
x := x div 2
y := y * 2
x > 0
x ungerade
6
(f)
156
0
192
Mathematischer Hintergrund
11
13 = 6*2+1
Bedingung
Anweisung
= (3*2+0)*2+1
= ((1*2+1)*2+0)*2+1
x > 0
x ungerade
= (((0*2+1)*2+1)*2+0)*2+1
13 * 12 =
8*12 + 4*12 + 0 + 1*12 =
96 + 48 + 12 =
x > 0
x ungerade
x > 0
x ungerade
156
13 
12
6
24
3

48
1

96
156
12
0
p := p + y
x := x div 2
y := y * 2
12
(w)
(f)
x := x div 2
y := y * 2
6
24
3
48
(w)
(w)
60
1
96
(w)
(w)
p := p + y
x := x div 2
y := y * 2
x > 0
13
p
p := 0
p := p + y
x := x div 2
y := y * 2
x > 0
x ungerade
y
(w)
(w)
= 0*2*2*2*2 + 1*2*2*2 + 1*2*2 + 0*2 + 1
(1*2^3 + 1*2^2 + 0*2^1 + 1*2^0) * 12 =
x
156
0
192
(f)
Der erste Faktor wird implizit in Binärdarstellung
umgewandelt. Hierdurch wird die Multiplikation
auf Verdoppeln und Halbieren reduziert.
12
Implementierung des Algorithmus
Der Algorithmus "Ägyptische Multiplikation" soll zu Demonstrationszwecken
implementiert werden.
Ägyptische Multiplikation
Eingabe: x, y
p := 0
SOLANGE x > 0
x ungerade ?
ja
nein
p := p + y
x := x div 2
y := y * 2
Ausgabe: p
13
Implementierung in PASCAL
Wir implementieren den
Algorithmus als DelphiKonsolenprogramm:
...
var
x, y, p: integer;
Schritte:
Neuen Ordner anlegen
<Datei><Neu..><KonsolenAnwendung>
Projekt speichern
Programm eingeben
begin
// Eingabe
write('x: '); readln(x);
write('y: '); readln(y);
// Verarbeitung
p := 0;
while x > 0 do
begin
if x mod 2 = 1 then
p := p + y;
x := x div 2;
y := y * 2
end;
// Ausgabe
write('x * y: '); writeln(p);
readln;
end.
14
Implementierung in PYTHON
Wir implementieren den Algorithmus als Python-Programm:
Starten Sie die Python-Shell.
Öffnen Sie ein neues Fenster zur Eingabe des Programms: <File> <New
Window>.
Geben Sie das Programm (hier als Funktionsdefinition) ein und speichern
Sie es unter einem geeigneten Dateinamen ab (z. B. mult_aegypt.py).
Rufen Sie vom Programmfenster aus die Python-Shell auf: <Run><Run
Module>.
Lassen Sie Python geeinete Funktionsaufrufe auswerten.
>>> mult(13, 12)
156
Python-Shell mit Programmaufruf
mult1.py
def mult(x, y):
p = 0
while x > 0:
if x % 2 == 1:
p = p + y
x = x / 2
y = y * 2
return p
15
Aufgabe
Implementieren Sie den Algorithmus in einer der beiden Sprachen.
Ergänzen Sie auch Ausgaben, mit denen man die jeweiligen Zwischenwerte
verfolgen kann. In Python geht das ganz einfach (s. u.).
Notieren Sie die Testfälle, die Sie betrachtet haben.
>>> mult(13, 12)
13 12 0
6 24 12
3 48 12
1 96 60
156
def mult(x, y):
p = 0
while x > 0:
print x, y, p
if x % 2 == 1:
p = p + y
x = x / 2
y = y * 2
return p
mult2.py
16
Aufgabe
Entwickeln Sie ein analoges Verfahren / einen analogen Algorithmus zum
Potenzieren.
Tipp:
"Der Exponent wird schrittweise halbiert (das Ergebnis wird abgerundet) und die Basis
schrittweise quadriert. Man streicht die Zeilen mit geradem Exponenten. Das Produkt der
nichtgestrichenen rechten Zahlen ist die gesuchte Potenz."
(siehe Wikipedia, Stichwort "schnelles Potenzieren")
17
Teil 2
Korrektheit von Algorithmen
Korrektheit
18
Der Algorithmus "Ägyptische Multiplikation" scheint immer das gewünschte
Multiplikationsergebnis zu liefern. Stimmt das auch? Was heißt hier immer?
>>>
156
>>>
24
>>>
0
>>>
0
mult(13, 12)
mult(4, 6)
mult(0, 5)
mult(5, 0)
def mult(x, y):
p = 0
while x > 0:
if x % 2 == 1:
p = p + y
x = x / 2
y = y * 2
return p
Spezifikation
19
Das gewünschte Verhalten des Algorithmus lässt sich wie folgt beschreiben:
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
Vorbedingung
Algorithmus
nachher:
{ p = a*b }
Nachbedingung
Eine Spezifikation ist eine vollständige und eindeutige Beschreibung des
Ausgangszustands („Zustand vorher“) und des Zielzustands („Zustand
nachher“) mit Hilfe einer Vor- und Nachbedingung.
20
Korrektheit eines Algorithmus
Korrektheit bezieht sich immer auf vorher festgelegte Anforderungen.
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
Vorbedingung
Algorithmus
nachher:
{ p = a*b }
Nachbedingung
Eine Algorithmus heißt (total) korrekt bzgl. einer Spezifikation, wenn er
jeden Ausgangszustand, der die Vorbedingung erfüllt, in einen Zielzustand
überführt, der die Nachbedingung erfüllt (und dann anhält).
Informelle Korrektheitsüberlegungen
21
13 * 12 =
Bedingung
Anweisung
(6*2+1) * 12 = 6*(2*12) + 12 =
6 * 24 + 12 =
(3*2) * 24 + 12 = 3*(2*24) + 12 =
x > 0
x ungerade
(1*2+1) * 48 + 12 = 1*(2*48) + (48+12) =
(0*2+1) * 96 + 60 = 0*(2*96) + (96+60) =
0 * 192 + 156
allg.: x * y + p = 13 * 12
x > 0
x ungerade
x > 0
x ungerade
(w)
(f)
12
0
p := p + y
x := x div 2
y := y * 2
12
x := x div 2
y := y * 2
6
24
3
48
(w)
(w)
Schleifeninvariante
60
1
96
(w)
(w)
p := p + y
x := x div 2
y := y * 2
x > 0
13
p
p := 0
p := p + y
x := x div 2
y := y * 2
x > 0
x ungerade
y
(w)
(w)
3 * 48 + 12 =
1 * 96 + 60 =
x
156
0
192
(f)
Die gezeigten Berechnungsschritte spiegeln sich im Ablaufprotokoll wider. Es
fällt auf, dass die Werte der Variablen x, y und p in einem ganz bestimmten
Zusammenhang stehen.
Verifikation der Korrektheit
22
Die Korrektheit des
Algorithmus lässt sich auch
formal zeigen:
(siehe auch: http://www.hsgkl.de/faecher/inf/algorithmus/korrekt/verifik
ation/index.php)
Vor dem ersten Schleifendurchlauf gilt:
x*y+p = a*b
(klar, da p = 0)
Wir zeigen, dass der Ausdruck x*y+p nach jedem
Schleifendurchlauf seinen Wert nicht verändert. Die
Werte der Variablen x, y und p nach einem
Schleifendurchlauf nennen wir x', y' und p'. Es gilt:
x ungerade:
p' = p+y
2x'+1 = x bzw. x' = (x-1)/2
y' = 2y
Ägyptische Multiplikation
x'*y' + p' = (x-1)/2*(2y) + (p+y)
= x*y - y + p + y
= x*y + p
Eingabe: x, y
p := 0
SOLANGE x > 0
x gerade:
x ungerade ?
ja
nein
p := p + y
x := x div 2
y := y * 2
Ausgabe: p
p' = p
x' = x/2
y' = 2y
x'*y' + p' = (x/2)*(2y) + p
= x*y + p
Nach dem letzten Schleifendurchlauf gilt dann:
x*y+p = a*b
Da zudem x=0 gilt, folgt:
p = a*b
Aufgabe
23
13 * 12 =
(6*2+1) * 12 = 6*(2*12) + 12 =
6 * 24 + 12 =
(3*2) * 24 + 12 = 3*(2*24) + 12 =
Testen Sie mit Hilfe geeigneter
Ausgabeanweisungen die
Schleifeninvariante.
3 * 48 + 12 =
(1*2+1) * 48 + 12 = 1*(2*48) + (48+12) =
1 * 96 + 60 =
(0*2+1) * 96 + 60 = 0*(2*96) + (96+60) =
0 * 192 + 156
allg.: x * y + p = 13 * 12
def mult(x, y):
p = 0
Schleifeninvariante
while x > 0:
print x*y+p
if x % 2 == 1:
p = p + y
x = x / 2
y = y * 2
return p
mult3.py
24
Aufgabe
Testen Sie das unten abgebildete Programm. Was klappt hier nicht?
def mult(x, y):
p = 0
while x >= 0:
if x % 2 == 1:
p = p + y
x = x / 2
y = y * 2
print p
return p
mult4.py
25
Termination
Achtung: Der Algorithmus berechnet zwar die beabsichtigten Ergebnisse,
hält aber nicht, um sie zurückzugeben.
>>> mult(7,8)
8
24
56
56
56
56
...
def mult(x, y):
p = 0
while x >= 0:
if x % 2 == 1:
p = p + y
x = x / 2
y = y * 2
print p
return p
Eine Algorithmus heißt terminierend, wenn er bei jedem möglichen
Ausgangszustand in endlich vielen Verarbeitungsschritten zum Ende
kommt (und Ausgabedaten als Ergebnisse liefert).
Terminationsnachweis
26
Zum Nachweis der (totalen) Korrektheit eines Algorithmus gehört auch der
Nachweis der Termination:
Der Algorithmus terminiert bei natürlichen Zahlen
sicher, da x als Eingabewert eine natürliche Zahl
erhält und dieser Wert innerhalb der Schleife stets
ganzzahlig halbiert wird. Mit jedem
Schleifendurchlauf wird der Wert von x demnach
kleiner. Nach endlich vielen Schritten muss also der
Wert 0 erreicht werden.
Ägyptische Multiplikation
Eingabe: x, y
p := 0
SOLANGE x > 0
x ungerade ?
ja
nein
p := p + y
x := x div 2
y := y * 2
Ausgabe: p
Aufgabe
27
Versuchen Sie, die Korrektheit mit e. geeigneten Invariante zu zeigen bzw.
sich die Korrektheit anhand e. typischen Ablaufprotokolls klar zu machen.
vorher:
x = b (positive rationale Zahl) und
y = n (nat. Zahl)
Schnelles Potenzieren
Eingabe: x, y
p := 1
SOLANGE y > 0
y ungerade ?
ja
nein
p := p * x
y := y div 2
x := x * x
Ausgabe: p
nachher:
p = bn
28
Teil 3
Fallstudie: Euklidischer Algorithmus
29
Der größte gemeinsame Teiler
Algorithmen werden seit den
Anfängen der Mathematik beim
Rechnen benutzt. Euklid beschreibt
ein Verfahren, mit dem man den
größten gemeinsamen Teiler von
zwei natürlichen Zahlen bestimmen
kann.
ggt(44, 12) =
ggt(32, 12) =
ggt(20, 12) =
ggt(8, 12) =
ggt(8, 4) =
ggt(4, 4) =
ggt(4, 0) =
4
"Wenn CD aber AB nicht misst, und man nimmt bei AB, CD
abwechselnd immer das kleinere vom größeren weg, dann
muss (schließlich) eine Zahl übrig bleiben, die die
vorangehende misst."
aus: Euklid, Die Elemente, Herausgegeben von Clemens
Thaer, Wissenschaftliche Buchgesellschaft Darmstadt, VII
Buch, §2
siehe auch:
http://de.wikipedia.org/wiki/Euklidischer_Algorithmus
Wechselwegnahme-Algorithmus
30
Das Wechselwegnahme-Verfahren lässt sich wie folgt algorithmisch
beschreiben.
GGT - Version 1
{x = a; y = b; a,b natürliche Zahlen größer 0}
SOLANGE y > 0
x >y
ja
nein
x := x - y
{x = ggT(a,b)}
y := y - x
Aufgabe
31
Überprüfen Sie, ob der gezeigte Algorithmus korrekt ist.
- Fertigen Sie geeignete Ablaufprotokolle per Hand an.
- Implementieren Sie den Algorithmus und testen Sie den Algorithmus.
- Zeigen Sie die Korrektheit des Algorithmus. Benutzen Sie die folgende
Schleifeninvariante: ggt(x, y) = ggt(a, b)
GGT - Version 1
{x = a; y = b; a,b natürliche Zahlen größer 0}
SOLANGE y > 0
x >y
ja
nein
x := x - y
{x = ggT(a,b)}
y := y - x
Aufgabe
32
Der größte gemeinsame Teiler lässt sich eventuell aber auch mit anderen
Algorithmen berechnen. Überprüfen Sie die folgenden Algorithmen:
GGT - Version 2
{x = a; y = b; a,b natürliche Zahlen größer 0}
GGT - Version 3
x >y
ja
nein
x := x - y
{x = a; y = b; a,b natürliche Zahlen größer 0}
y := y - x
x <= y
ja
WIEDERHOLE BIS x = y
nein
min := x
{x = ggT(a,b)}
min := y
SOLANGE nicht ((x mod min = 0) oder (y mod min = 0))
min := min - 1
GGT - Version 4
{x = a; y = b; a,b natürliche Zahlen größer 0}
SOLANGE y > 0
h := x mod y
x := y
y := h
{x = ggT(a,b)}
{min = ggT(a,b)}
33
Aufgabe
Welche Unterschiede lassen sich im Verhalten der vorgeschlagenen
Algorithmen beobachten?
34
Teil 4
Testen und Laufzeitmessungen
35
Testen
Die Überprüfung eines Algorithmus bzw. Programms hinsichtlich
Korrektheit kann auf zwei grundsätzlich verschiedene Weisen erfolgen:
- Formale Methode (Verifikation): Mittels logischer Herleitungen wird
die Einhaltung der Bedingungen an die Zwischen- und Endergebnisse des
Algorithmus bzw. Programms nachgewiesen.
- Empirische Methode (Testen): Mit bestimmten ausgesuchten Daten,
für die das Ergebnis bekannt ist, wird der Algorithmus bzw. das
Programm erprobt. Dabei kann lediglich das Vorhandensein von Fehlern
entdeckt, nicht jedoch die Fehlerfreiheit nachgewiesen werden.
"Der Methode der Programmverifikation stellen sich in der Praxis große Hindernisse entgegen.
Bei umfangreichen Programmen ist ein formaler Korrektheitsbeweis der geschilderten Art i. d.
R. nicht möglich. Unsere Beispiele betrafen vergleichsweise wenig umfangreiche
mathematische Algorithmen, deren Spezifikation seit Jahrhunderten bekannt ist. In der Praxis
besteht das eigentliche Problem jedoch im Entwickeln eines geeigneten Modells (...), und es ist
zu prüfen, ob das Modell "auf die Wirklichkeit passt". Erst wenn dies gesichert ist, kann die
Verifikation beginnen. In der Praxis ändern sich Spezifikationen laufend, das Modell wird
abgewandelt. Daher ist man dort auf die - zugegebenermaßen unvollkommene - Methode des
empirischen Testens angewiesen." (aus: R. Baumann: Informatik für die Sekundarstufe II,
Band 1. S. 185 ff.)
36
Testdaten
Testdaten müssen sorgfältig gewählt werden. Es reicht in der Regel nicht,
nur einige wenige Testfälle durchzuführen.
Testfälle:
x = 44; y = 12  4 (ok)
GGT - Version 2
{x = a; y = b; a,b natürliche Zahlen größer 0}
x >y
ja
x = 13; y = 5  1 (ok)
x = 24; y = 6  6 (ok)
nein
x := x - y
y := y - x
WIEDERHOLE BIS x = y
{x = ggT(a,b)}
Die gewählten Testdaten decken hier nicht auf, dass der Algorithmus bei
der Eingabe zweier gleicher Zahlen nicht terminiert.
37
Teststrategien
Regeln zur Wahl von Testdaten:
Man wähle sowohl typische als auch untypische Eingabewerte. Besondere
Aufmerksamkeit ist auf Sonderfälle und Grenzwerte zu richten. Unter
letzteren versteht man Werte, die gerade noch als Eingabewerte zugelassen
sind (z. B. größter und kleinster Wert, leerer Text, leere Eingabe usw.).
Man sollte auch zufällige Testdaten verwenden, selbst wenn diese nicht
sinnvoll erscheinen mögen, denn mit ihnen lassen sich Testlücken aufgrund
scheinbarer Selbstverständlichkeiten vermeiden.
Regeln zur Testdurchführung:
Man notiere vor der Durchführung des Testlaufs, welche Ausgabe das
Programm laut Spezifikation liefern soll. Man prüfe nicht nur, ob das
Programm tut, was es soll, sondern auch, ob es etwas tut, was es nicht soll
(z. B.: hat eine Prozedur unerwünschte Nebenwirkungen?)
38
Testen mir Python
# ggt1Test1.py
>>>
44 12 4
7 13 1
4 4 4
1 9 1
def ggt(x, y):
while y > 0:
if x > y:
x = x - y
else:
y = y - x
return x
Testergebnisse
if __name__ == "__main__":
print 44, 12, ggt(44, 12)
print 7, 13, ggt(7, 13)
print 4, 4, ggt(4, 4)
print 1, 9, ggt(1,9)
vorher festgelegte
Testfälle
Testen mir Python
39
# ggt1Test2.py
def ggt(x, y):
""" groesster gemeinsamer Teiler
>>> ggt(44, 12)
4
>>> ggt(7, 13)
1
>>> ggt(4, 4)
4
vorher festgelegte
Testfälle mit den
erwarteten Ergebnissen
automatisch erzeugtes
Testprotokoll
"""
while y > 0:
if x > y:
x = x - y
else:
y = y - x
return x
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
>>>
Trying:
ggt(44, 12)
Expecting:
4
ok
Trying:
ggt(7, 13)
Expecting:
1
ok
Trying:
ggt(4, 4)
Expecting:
4
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.ggt
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
40
Systematisches Testen
Anweisungsüberdeckung:
Konstruiere die Testfälle so, dass
jede Anweisung mindestens
einmal ausgeführt wird.
Zweigüberdeckung:
Konstruiere die Testfälle so, dass
jeder einzelne Zweig im
Flussdiagramm mindestens einmal
ausgeführt wird.
Pfadüberdeckung:
Konstruiere die Testfälle so, dass
alle Pfade im Flussdiagramm
mindestens einmal ausgeführt
werden. Die Anzahl der
Scheifendurchläufe wird dabei auf
max. 2 begrenzt.
Eingabe: x, y
y > 0?
wahr
falsch
wahr
x > y?
x := x - y
falsch
y := y - x
Ausgabe: x
41
Systematisches Testen
Testfälle für eine
Pfadüberdeckung:
Eingabe: x, y
kein Schleifendurchlauf:
x = 3; y = 0  3
ein Schleifendurchlauf:
x = 4; y = 4  4
zwei Schleifendurchläufe:
x = 6; y = 3 (w, f)  3
x = 3; y = 6 (f, f)  3
y > 0?
wahr
falsch
wahr
x > y?
x := x - y
falsch
y := y - x
Ausgabe: x
42
Aufgabe
Überlegen Sie sich geeignete
Testfälle, um den Algorithmus
"GGT Version 4" zu testen.
Führen Sie die Tests mit einer
geeigneten Testumgebung durch.
Protokollieren Sie (ggf. in der
Testumgebung integriert) die
Ergebnisse.
GGT - Version 4
{x = a; y = b; a,b natürliche Zahlen größer 0}
SOLANGE y > 0
h := x mod y
x := y
y := h
{x = ggT(a,b)}
43
Aufgabe
Überlegen Sie sich geeignete
Testfälle, um den Algorithmus
"Ägyptische Multiplikation" zu
testen.
Führen Sie die Tests mit einer
geeigneten Testumgebung durch.
Protokollieren Sie (ggf. in der
Testumgebung integriert) die
Ergebnisse.
p := 0
x > 0?
wahr
falsch
wahr
x ungerade?
p := p + x
x := x div 2
y := y * 2
falsch
Äquivalenz von Algorithmen
44
Verschiedene Algorithmen, die das gleiches Ein-/Ausgabe-Verhalten zeigen,
können sich deutlich im Laufzeitverhalten unterscheiden.
GGT - Version 1
GGT - Version 4
{x = a; y = b; a,b natürliche Zahlen größer 0}
{x = a; y = b; a,b natürliche Zahlen größer 0}
SOLANGE y > 0
SOLANGE y > 0
x >y
h := x mod y
ja
nein
x := y
x := x - y
y := y - x
y := h
{x = ggT(a,b)}
{x = ggT(a,b)}
Zwei Algorithmen heißen äquivalent, wenn sie bei gleichen
Ausgangszuständen jeweils gleiche Endzustände erzeugen. Von zwei
äquivalenten Algorithmen heißt der effizienter, der mit weniger Zeit
(bzw. mit weniger Speicherplatz) auskommt.
45
Laufzeitmessung mit Python
# ggt1Laufzeit.py
def ggt(x, y):
while y > 0:
if x > y:
x = x - y
else:
y = y - x
return x
if __name__ == "__main__":
import profile
profile.run("ggt(768964310867, 34256)")
>>>
4 function calls in 11.452 CPU seconds
...
Performanzanalyse mit
dem Profiler
Auszug aus dem ProfilerProtokoll
46
Unterschiedliche Laufzeiten
# ggt1Laufzeit.py
# ggt4Laufzeit.py
def ggt(x, y):
while y > 0:
if x > y:
x = x - y
else:
y = y - x
return x
def ggt(x, y):
while y > 0:
h = x % y
x = y
y = h
return x
if __name__ == "__main__":
import profile
profile.run
("ggt(768964310867, 34256)")
if __name__ == "__main__":
import profile
profile.run
("ggt(768964310867, 34256)")
>>>
>>>
4 function calls in
11.452 CPU seconds
4 function calls in
0.001 CPU seconds
...
...
47
Schleifendurchläufe zählen
# ggt1Schleifendurchlaeufe.py
def ggt(x, y):
z = 0
while y > 0:
z = z + 1
if x > y:
x = x - y
else:
y = y - x
return x, z
zusätzlicher Zähler
if __name__ == "__main__":
zahl1 = 768964310867
zahl2 = 34256
(ergebnis, anzahl) = ggt(zahl1, zahl2)
print "Zahl 1: ", zahl1, "Zahl 2: ", zahl2, "ggt: ", ergebnis,
"Schleifendurchlaeufe: ", anzahl
>>>
Zahl 1: 768964310867 Zahl 2:
22447622
34256 ggt:
1 Schleifendurchlaeufe:
48
Unterschiedlicher Berechnungsaufwand
# ggt1Schleifendurchlaeufe.py
# ggt4Schleifendurchlaeufe.py
def ggt(x, y):
z = 0
while y > 0:
z = z + 1
if x > y:
x = x - y
else:
y = y - x
return x, z
def ggt(x, y):
z = 0
while y > 0:
z = z + 1
h = x % y
x = y
y = h
return x, z
if __name__ == "__main__":
zahl1 = 768964310867
zahl2 = 34256
...
if __name__ == "__main__":
zahl1 = 768964310867
zahl2 = 34256
...
>>>
Zahl 1: 768964310867 Zahl 2:
34256 ggt: 1
Schleifendurchlaeufe: 22447622
>>>
Zahl 1: 768964310867 Zahl 2:
34256 ggt: 1
Schleifendurchlaeufe: 9
49
Aufgabe
Untersuchen Sie auch das Verhalten des Algorithmus "ggt - Version 3".
Vergleichen Sie diesen Algorithmus mit den beiden anderen ggtAlgorithmen.
50
Aufgabe
Vergleichen Sie die beiden folgenden Algorithmen zum Potenzieren
hinsichtlich Laufzeit und Berechnungsaufwand.
def pot(x, n):
p = 1
for i in range(0, n):
p = p * x
return p
def pot(x, y):
p = 1
while y > 0:
if y % 2 == 1:
p = p * x
x = x * x
y = y / 2
return p
51
Aufgabe
Der folgende Algorithmus überprüft, ob eine natürliche Zahl eine Primzahl
ist. Testen Sie diesen Algorithmus. Versuchen Sie auch, effizientere
Algorithmen zu entwickeln.
Interessant ist auch das Problem, eine Zahl in ihre Primfaktoren zu
zerlegen. Wie könnte ein (effizientes) Verfahren aussehen?
def primzahl(n):
prim = True
if n == 1:
prim = False
else:
i = 2
while i <= n-1:
if n % i == 0:
prim = False
i = i+1
return prim
52
Aufgabe
Laufzeitmessungen sind auch mit Delphi möglich. Informieren Sie sich
hierüber in den folgenden Materialien:
G. Noll: Programmieren mit Delphi. Präsentation (Folie 44).
http://informatik.bildung-rp.de/fileadmin/user_upload/informatik.bildung-rp.de/Fortbildung/pps/D-070516Noll-ProgrammierenMitDelphi.pps
Herunterladen