Powerpoint-Präsentation

Werbung
Eigenschaften von Algorithmen
Klaus Becker
2008
Algorithmen
2



Zielsetzung:

klassische Algorithmen erkunden und dabei

zentrale Eigenschaften von Algorithmen klären
3
Teil 1
Algorithmusbegriff
Ä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
5
Aufgabe
Finden Sie heraus, wie das Verfahren der Ägypter funktioniert.
Berechnen Sie mit dem Verfahren die folgenden Produkte:
15 * 14 =
9 * 120 =
16 * 7 =
Überprüfen Sie auch, ob die Ergebnisse stimmen.
Für Experten: Warum berechnet dieses merkwürdige Verdopplungs- und
Halbierungsverfahren das Produkt von zwei vorgegebenen Zahlen? Versuchen Sie sich dies
klar zu machen.
6
Aufgabe
Schreiben Sie eine möglichst präzise Anleitung, nach der jemand, der das Verfahren der
Ägypter nicht kennt, zwei Zahlen multiplizieren soll.
13 
12
6
24
3 
48
1 
96
156
13 ∙ 12
=
156
7
Verfahrensbeschreibung
 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.
umgangssprachliche Beschreibung
13 
12
6
24
3 
48
1 
96
156
13 ∙ 12
=
156
Verfahrensbeschreibung
8
Struktogramm
Trace / Ablaufprotokoll
Bedingung
Anweisung
z1
z2
13
12
p := 0
z1 > 0
z1 ungerade
13 
12
6
24
3 
48
1 
96
156
13 ∙ 12
=
156
24
3
48
60
1
96
(w)
(w)
p := p + z2
z1 := z1 / 2
z2 := z2 * 2
z1 > 0
6
(w)
(w)
p := p + z2
z1 := z1 / 2
z2 := z2 * 2
z1 > 0
z1 ungerade
12
(w)
(f)
z1 := z1 / 2
z2 := z2 * 2
z1 > 0
z1 ungerade
0
(w)
(w)
p := p + z2
z1 := z1 / 2
z2 := z2 * 2
z1 > 0
z1 ungerade
p
(f)
156
0
192
Algorithmus
9
Ein Algorithmus ist eine Verarbeitungsvorschrift, die so präzise formuliert ist, dass sie auch
von einer Maschine abgearbeitet werden kann.
 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
10
Kriterien für Algorithmen
Ein Algorithmus ist eine Verarbeitungsvorschrift, die folgende Kriterien erfüllt:
 Eindeutigkeit, d. h. die einzelnen Schritte und ihre Abfolge sind unmissverständlich
beschrieben
 Ausführbarkeit, d. h. der Prozessor muss die Einzelschritte abarbeiten können
 Allgemeinheit, d. h. es wird nicht nur ein Problem, sondern eine ganze Klasse von
Problemen gelöst
 Endlichkeit, d. h. seine Beschreibung besteht aus einem Text endlicher Länge
Prozessor: Maschine, Person oder auch gedachte Einheit
verstanden, die den Algorithmus ausführen soll
11
Algorithmen im Alltag
ZUTATEN für 5 Portionen:
650g Erdbeeren
150g Zucker
2 Pk Vanillezucker
5 EL Weinbrand
400 ml Sahne (gut gekühlt)
Rezept
ZUBEREITUNG
Erdbeeren kalt abbrausen, abtropfen lassen und trocken
tupfen. Blütenansatz entfernen. 150 Gramm der Früchte
zugedeckt beiseite stellen.
Restliche Erdbeeren in Stücke schneiden. Zucker,
Vanillezucker und Weinbrand darunterheben und alles 30
Minuten zugedeckt ziehen lassen. Dann mit dem Mixstab
fein pürieren. Die Hälfte der Sahne steif schlagen und
unter das Püree ziehen. Die Creme im Gefrierfach oder in
der Tiefkühltruhe gefrieren lassen.
Restliche Sahne halbsteif schlagen. Mit einem Esslöffel
Nocken von der Mousse abstechen und auf Dessertteller
verteilen. Die halbsteife Sahne angießen und das Dessert
mit den ganzen Erdbeeren garnieren.
Bedienungsanleitung
Quelle: www.daskochrezept.de
Auch im Alltag gibt es Verfahrensbeschreibungen, die algorithmische Züge aufweisen. Die
Anforderungen an den "Prozessor" sind aber in der Regel nicht so hoch wie bei Algorithmen in
der Informatik.
12
Al-Khwarizmi
Die Bezeichnung „Algorithmus“ leitet sich aus
dem Namen „Al-Khwarizmi“ – einem arabischen
Mathematiker – ab.
Abu Abd Allah Mohammed Ibn Musa Al-Khwarizmi lebte etwa von 780 bis 850 n. Chr. Er
stammte aus Choresm (arab. Khwarizmi), eine Gegend südlich des Aralsees, die heute Teil
von Usbekistan und Turkmenistan ist. Für seinen Namen sind mehrere Schreibweisen
gebräuchlich, z.B. Alhwarizmi, Al-Hwarizmi, al-Khowarizmi oder auch Mohammed ben Musa.
Al-Khwarizmi beschäftigte sich u. a. mit Verfahren zur Lösung von Gleichungen. Er verfasste
Bücher, die sich mit Algebra, Astronomie und Geographie beschäftigten, sowie Werke über
indische Ziffern und den Jüdischen Kalender.
Bausteine von Algorithmen
13
Kontrollstrukturen dienen dazu, den Ablauf der
Ausführungsschritte festzulegen. Wesentliche
Kontrollstrukturen sind die Fallunterscheidung, die
Wiederholung sowie die Sequenzbildung
(Hintereinanderreihung).
S
E
Eingabe: zahl1
E
Eingabe: zahl2
E
produkt = 0
Eine Elementaranweisung beschreibt eine Basisaktion des
betrachteten Prozessors.
W
S
F
S
E
produkt = produkt + zahl2
S
E
E
zahl1 = zahl1 / 2
E
zahl2 = zahl2 * 2
Ausgabe: produkt
14
Darstellung von Algorithmen
Algorithmen lassen sich auf unterschiedliche Weise darstellen:
 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.
umgangssprachlich
# Eingabe
zahl1 = input("Zahl 1: ")
zahl2 = input("Zahl 2: ")
# Verarbeitung
produkt = 0
while zahl1 > 0:
if zahl1 % 2 == 1:
produkt = produkt + zahl2
zahl1 = zahl1 / 2
zahl2 = zahl2 * 2
# Ausgabe
print "Produkt: ", produkt
Programm
Struktogramm
15
Implementierung in Python
Es gibt verschiedene Möglichkeiten, einen Algorithmus in Python zu implementieren.
# Eingabe
zahl1 = input("Zahl 1: ")
zahl2 = input("Zahl 2: ")
# Verarbeitung
produkt = 0
while zahl1 > 0:
if zahl1 % 2 == 1:
produkt = produkt + zahl2
zahl1 = zahl1 / 2
zahl2 = zahl2 * 2
# Ausgabe
print "Produkt: ", produkt
def multiplikation(zahl1, zahl2):
produkt = 0
while zahl1 > 0:
if zahl1 % 2 == 1:
produkt = produkt + zahl2
zahl1 = zahl1 / 2
zahl2 = zahl2 * 2
return produkt
>>>
Zahl 1: 12
Zahl 2: 13
Produkt: 156
>>> multiplikation(12, 13)
156
Folge von
Anweisungen
Funktionsdeklaration
16
Implementierung in Scratch
17
siehe www.inf-schule.de
Aufgaben
Exkurs: Mathematischer Hintergrund
18
Bedingung
13 = 6*2+1
Anweisung
z1
z2
13
12
= (3*2+0)*2+1
p := 0
= ((1*2+1)*2+0)*2+1
z1 > 0
z1 ungerade
= (((0*2+1)*2+1)*2+0)*2+1
p := p + z2
z1 := z1 / 2
z2 := z2 * 2
13 * 12 =
8*12 + 4*12 + 0 + 1*12 =
z1 > 0
z1 ungerade
96 + 48 + 12 =
156
13 
6
12
z1 > 0
z1 ungerade
3

48
1

96
156
6
24
3
48
(w)
(w)
p := p + z2
z1 := z1 / 2
z2 := z2 * 2
1
60
p := p + z2
z1 := z1 / 2
z2 := z2 * 2
0
96
(w)
(w)
24
z1 > 0
12
(w)
(f)
z1 := z1 / 2
z2 := z2 * 2
z1 > 0
z1 ungerade
0
(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 =
p
156
(f)
Der erste Faktor wird implizit in Binärdarstellung
umgewandelt. Hierdurch wird die Multiplikation auf
Verdoppeln und Halbieren reduziert.
192
19
Teil 2
Korrektheit von Algorithmen
20
Wechselwegnahme
Auf dem Tisch liegen zwei Reihen von Streichhölzern. Von der jeweils längeren Reihe sollen
so viele weggenommen werden, wie in der kürzeren vorkommen. Aufgehört wird, wenn
beide Streichholzreihen gleich lang sind.
Aufgaben:
Führe den Algorithmus mit
verschiedenen Ausgangszahlen /
Streichholzreihen durch und notiere die
jeweiligen Ausgaben.
 x = 15 ; y = 7
 x = 10; y = 21
 x = 3; y = 20
Was leistet der Algorithmus? Wie hängen
die Ausgaben von den Eingaben ab?
Ändert sich etwas am Verfahren, wenn
man es wie unten beschreibt?
21
Spezifikation
Das Verhalten eines Algorithmus lässt sich mit einer Spezifikation präzise beschreiben. Die
Spezifikation besteht aus einer Vorbedingung, die den Ausgangszustand beschreibt, sowie
einer Nachbedingung, die den Endzustand beschreibt.
Vorbedingung
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
nachher:
{ x = y = ggT(a, b) }
Nachbedingung
22
Korrektheit
Ein Algorithmus heißt terminierend bzgl. einer Spezifikation, wenn er bei jedem
Ausgangszustand, der die Vorbedingung erfüllt, nach endlich vielen Verarbeitungsschritten zu
einem Ende kommt.
Ein Algorithmus heißt (total) korrekt bzgl. einer Spezifikation, wenn er terminierend ist und
jeden Ausgangszustand, der die Vorbedingung erfüllt, in einen Endzustand überführt, der die
Nachbedingung erfüllt.
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
korrekt
nicht
terminierend
nachher:
{ x = y = ggT(a, b) }
nachher:
{ x = y = ggT(a, b) }
23
Korrektheitsnachweis über Testen
Beim Testen eines Algorithmus wird der Algorithmus bei bestimmten vorgegebenen Testdaten
ausgeführt und dabei überprüft, ob er in diesen Fällen das gewünschte Verhalten zeigt. Mit
dieser Methode kann man das Vorhandensein von Fehlern entdecken. Man kann aber in der
Regel nicht nachweisen, dass der Algorithmus korrekt bzgl. der gegebenen Spezifikation ist.
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
x = 8; y = 8:
nicht terminierend
x = 15; y = 7: ok
x = 8; y = 8:
ok
...
nachher:
{ x = y = ggT(a, b) }
nachher:
{ x = y = ggT(a, b) }
24
Teststrategien
Testdaten sollten immer sorgfältig ausgewählt werden. Man sollte sowohl typische als auch
untypische Eingabewerte betrachten. 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.). Oft ist es
auch günstig, zufällig erzeugte Testdaten zu verwenden.
Bei der Durchführung von Tests sollte man vorher notieren, welche Ausgabe das Programm
laut Spezifikation liefern soll. Danach überprüft man, ob der Algorithmus tatsächlich dieses
Verhalten zeigt. In einem Exkurs zur Testausführung mit Python zeigen wir, wie solche
Testfälle in lauffähige Implementierungen von Algorithmen integriert werden können.
25
Testen mit Python
Es gibt verschiedene Möglichkeiten, einen Algorithmus in Python zu testen.
# Implementierung des Algorithmus
Wechselwegnahme
def ggt(x, y):
while x <> y:
if x > y:
x=x-y
else:
y=y-x
return x
>>>
ggt(44, 12) = 4
ggt(7, 13) = 1
ggt(4, 4) = 4
ggt(1, 6) = 1
ggt(6, 18) = 6
Testergebnisse
# Test
if __name__ == "__main__":
print "ggt(44, 12) = ", ggt(44, 12)
print "ggt(7, 13) = ", ggt(7, 13)
print "ggt(4, 4) = ", ggt(4, 4)
print "ggt(1, 6) = ", ggt(1, 6)
print "ggt(6, 18) = ", ggt(6, 18)
Testfälle
Testen mit Python
26
Es gibt verschiedene Möglichkeiten, einen Algorithmus in Python zu testen.
def ggt(x, y):
""" groesster gemeinsamer Teiler
>>> ggt(44, 12)
4
>>> ggt(7, 13)
1
>>> ggt(4, 4)
4
"""
while x <> y:
if x > y:
x=x-y
else:
y=y-x
return x
vorher festgelegte
Testfälle mit erwarteten
Ergebnissen
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
>>>
Trying:
ggt(44, 12)
Expecting:
4
ok
Trying:
ggt(7, 13)
Expecting:
von Python
1
erzeugtes
ok
Testprotokoll
Trying:
ggt(4, 4)
...
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.
27
Exkurs: Verifikation von Algorithmen
Behauptung:
Der Wechselwegnahme-Algorithmus ist korrekt bzgl. der
angegebenen Spezifikation.
Beweis:
Wir zeigen zunächst, dass die Bedingung {ggT(x, y) = ggT(a, b)}
vor dem ersten und nach jedem Schleifendurchlauf erfüllt ist.
Vor dem ersten Schleifendurchlauf gilt selbstverständlich diese
Bedingung, da hier x = a und y = b gilt.
Für m > n gilt:
Als nächstes zeigen wir, dass die genannte Bedingung nach einem
Schleifendurchlauf noch gilt, sofern sie vorher bereits erfüllt war.
Wenn a | m und a | n,
dann a | (m-n).
Wir nehmen also an, dass die Bedingung ggT(x, y) = ggT(a, b)
vor der Ausführung der Anweisungen der Schleife gilt. Die Werte
der Variablen x und y nach der Ausführung der Schleife
bezeichnen wir mit x' und y'. Es gilt x' = x - y und y' = y oder x' =
x und y' = y - x. Jetzt nutzen wir eine allgemeine Eigenschaft des
ggT aus: Für beliebige natürliche Zahlen m und n mit m > n gilt:
ggT(m, n) = ggT(m-n, n). Diese Eigenschaft kann man leicht
mathematisch beweisen. Aus ihr folgt, dass in jedem Fall ggT(x',
y') = ggT(x, y) gelten muss. Da ggT(x, y) = ggT(a, b)
vorausgesetzt war, folgt, dass ggT(x', y') = ggT(a, b) gilt.
Wenn a | (m-n) und
a | n, dann a | m.
Hieraus folgt:
ggT(m, n) =
ggT(m-n, n).
28
Exkurs: Verifikation von Algorithmen
Fortsetzung des Beweises:
Kommt es zum Verlassen der Schleife, so gilt einerseits
ggT(x, y) = ggT(a, b), da diese Bedingung vor dem ersten
Schleifendurchlauf gilt und wie gezeigt nach jedem weiteren
Durchlauf. Andererseits gilt auch x = y, da nur bei dieser
Bedingung die Schleife verlassen wird. Da der ggT bei zwei
gleichen Zahlen mit dieser Zahl übereinstimmt, muss also
ggT(a, b) = ggT(x, y) = x = y gelten.
Hiermit ist gezeigt, dass die Nachbedingung erfüllt ist, sofern die
Vorbedingung gilt und der Algorithmus bei den gegebenen Daten
terminiert. Zuletzt muss jetzt nur noch gezeigt werden, dass der
Algorithmus bei sämtlichen möglichen Eingabedaten tatsächlich
terminiert.
Dies kann man sich aber schnell klar machen. Man beginnt mit
zwei natürlichen Zahlen x = a und y = b. In jedem
Schleifendurchlauf wird eine der beiden Zahlen verkleinert. Man
kann nicht unendlich oft eine der beiden Zahlen verkleinern, so
dass beide größer als Null und auch verschieden bleiben.
29
Teil 3
Effizienz von Algorithmen
30
ggT-Berechnung
Der ggT von x = 3642431875 und y = 15 soll berechnet werden.
Aufgaben:
Würde man hier wirklich den
Wechselwegnahme-Algorithmus
ausführen? Was spricht dagegen?
Wie könnte man effizienter vorgehen?
Bedenken Sie, mit welcher
Rechenoperation man wiederholte
Subtraktionen schneller ausführen kann.
Entwickeln Sie einen geeigneten
Algorithmus.
31
Effizienz
Der ggT von x = 3642431875 und y = 15 soll berechnet werden.
x = 3642431875; y = 15
x = 3642431875; y = 15
x = 3642431860; y = 15
x = 15; y = 5
x = 3642431845; y = 15
x = 5; y = 0
...
x = 5; y = 5
äquivalent
effizienter
32
Effizienz
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 Ressourcen (d. h. Rechenzeit oder Speicherplatz) auskommt.
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
vorher:
{ x = a (nat. Zahl) und y = b (nat. Zahl) }
äquivalent
effizienter
nachher:
{ x = y = ggT(a, b) }
nachher:
{ x = y = ggT(a, b) }
33
Laufzeitmessung mit Python
Es gibt verschiedene Möglichkeiten, den Aufwand eines Algorithmus in Python zu messen.
# Deklaration
def ggt(x, y):
while x <> y:
if x > y:
x=x-y
else:
y=y-x
return x
# Test mit Laufzeitmessung
from time import *
t1 = clock()
z = ggt(3642431875, 15)
t2 = clock()
t = t2 - t1
print "ggt(3642431875, 15) = ", z
print "Rechenzeit: ", t
>>>
ggt(3642431875, 15) = 5
Rechenzeit: 160.503182108
"interne Uhr"
34
Aktionen zählen mit Python
Es gibt verschiedene Möglichkeiten, den Aufwand eines Algorithmus in Python zu messen.
def ggt(x, y):
z=0
while x <> y:
z=z+1
if x > y:
x=x-y
else:
y=y-x
return x, z
Zähler für
Schleifendurchläufe
if __name__ == "__main__":
zahl1 = 3642431875
zahl2 = 15
(ergebnis, anzahl) = ggt(zahl1, zahl2)
print "Zahl 1: ", zahl1, "Zahl 2: ", zahl2, "ggt: ", ergebnis
print "Schleifendurchlaeufe: ", anzahl
>>>
Zahl 1: 3642431875 Zahl 2: 15 ggt: 5
Schleifendurchlaeufe: 242828793
Ausgabe der Ergebnisse
35
siehe www.inf-schule.de
Aufgaben
Herunterladen