Kapitel 2 Algorithmen und Computerzahlen Für die Formulierung von Lösungsverfahren, die auf einem Computer realisiert werden sollen, bedient man sich mehr oder minder eines Werkzeugs, dass Algorithmus“ genannt wird. Hier ” skizzieren wir, worauf es bei Algorithmen ankommt, und geben erste Beispiele. Die zuletzt betrachtete Struktur Graphen“ ist beim Studium von Algorithmen von Bedeutung. Bei der ” Realisierung von Algorithmen auf dem Computer haben wir mit Computerzahlen“ zu rechnen. ” Sie genügen nicht immer den bekannten Rechenregeln, da sie diskret auf einem endlichen Teil des Zahlenstrahls verteilt sind. 2.1 Algorithmen Ein Computer ist ein Werkzeug zur Verarbeitung und Speicherung von Information. Um ihn zu nutzen, ist er mit Verarbeitungsvorschriften zu füttern“. Wir ” formulieren solche Vorschriften in der Regel unter dem Stichwort Algorithmus. Ein Algorithmus1 für eine vorgegebene bestimmte Art von Aufgaben ist eine endliche Abfolge von wohldefinierten, ausführbaren Vorschriften, die bei Abarbeitung, ausgehend von einem Eingangszustand (Input) nach einer endlichen Anzahl von Verarbeitungsschritten einen Ausgangszustand (Output) bestimmen, der als Lösung der durch den Eingangszustand charakterisierten Aufgabe angesehen werden kann. Abbildung 2.1: AL–Khwarizmi Algorithmen sind unabhängig von einer konkreten Programmiersprache und einem konkreten Computertyp, auf denen sie ausgeführt werden, zu formulieren. Algorithmen stehen im Zentrum der Informatik, der Numerischen und der Diskreten Mathematik. Ein Algorithmus, der einen gewissen Kultstatus“ beanspruchen kann, ist der euklidi” sche Algorithmus; wir werden ihn noch kennnenlernnen. Wir nutzen einen Algorithmus zur Bestimmung des PageRank einer Web–Seite, wenn wir die Suchmaschine google nutzen. Wir finden Algorithmen auch sonst im Alltag vor, wenn wir etwa einen Kuchen backen: Backrezepte sind, wenn sie gut aufgeschrieben sind, Algorithmen für den Prozess des Kuchenbackens. 1 Die Bezeichnung leitet sich aus dem Namen Al–Khwarizmi (Al–Khwarizmi,780? — 850?), einem der bedeutensten Mathematiker des anfangenden Mittelalters, ab. 13 Beispiel 2.1.1 Betrachte folgende Liste von Anweisungen: EIN: Natürliche Zahl n . step 1 k := 1, a := n . step 2 Ist a ( = 1, dann gehe zu AUS. 3a + 1 falls a ungerade step 3 a := a/2 falls a gerade step 4 k := k + 1, gehe zu step 2. AUS: Mit k die Länge der erzeugten Zahlenfolge. Die Rechenschritte erklären sich selbst: ausgehend von n wird eine Folge von natürlichen Zahlen erzeugt, eine so genannte Collatz/Uhlam/Warring-Folge. Ist dies ein Algorithmus? NEIN, denn es ist nicht sichergestellt, dass die Abfrage Ist a = 1, dann gehe zu AUS“ ” irgendwann zur Beendigung führt. ABER: Bisher hat man keine natürliche Zahl gefunden, bei der die obige Liste von Anweisungen nicht endet. Glaubt“ man dieser Beobachtung nicht, solte man eine Vorsichtsmaßnahme ” (Abbrechkriterium) einbauen, die sicherstellt, dass nur endlich oft der Schritt step 3“ ange” sprungen wird. Unterschiedliche Algorithmen können entworfen werden zur Lösung ein und derselben Aufgabe. Leistungsunterschiede lassen sich herausarbeiten, wenn man ihren Aufbau und ihre Wirkungsweise analysiert. Fragestellungen dafür sind: • Entwurf von Algorithmen: Wie soll ein Algorithmus zur Lösung einer bestimmten Aufgabe aussehen? • Komplexität: Wie läßt sich der Aufwand, der betrieben werden muss, um eine Problemklasse von Aufgaben zu lösen, bestimmen/abschätzen? • Berechenbarkeit: Gibt es Aufgaben, für die kein (schneller) Algorithmus existiert? • Korrektheit: Wie läßt sich nachweisen, ob ein vorliegender Algorithmus die Aufgabe korrekt löst? • Robustheit/Zuverlässigkeit: Wie groß ist die Problemklasse von Aufgaben, die der Algorithmus löst? • Genauigkeit: Was ist die Qualität der Lösung, wenn numerisches Rechnen nötig ist? Hauptziel der Analyse ist die Effizienzuntersuchung und die Entwicklung effizienter(er) Algorithmen. Diese Analyse sollte aber rechnerunabhängig durchgeführt werden. Dazu benötigt man ein geeignetes Rechnermodell. Solche Modelle stehen zur Verfügung! Wir wollen hier nicht darauf eingehen. Analyseuntersuchungen stützt man auf die Ermittlung des Rechenaufwands, ausgedrückt durch die Anzahl von elementaren Operationen. Hierbei kann man drei Ansätze unterscheiden: – Worst-case-Komplexität: Dies ist eine obere Schranke für den Aufwand in Abhängigkeit vom Input. – Mittlere Komplexität: Dies ist eine obere Schranke für den Aufwand in Abhängigkeit vom Input bei gewissen Annahmen über das Auftreten des Inputs in der Problemklasse. 14 – Untere Komplexität: Hierunter versteht man die Ermittlung unterer Schranken für den zu betreibenden Aufwand. Diese Ansätze können rechnerunabhängig und a-priori erfolgen, d.h. ohne den Algorithmus an einem Beispiel zu testen. Unter einer a-posteriori–Analyse versteht man das Testen des Algorithmus an Aufgaben mit (hinreichend) großem Input. 2.2 Programme und Programmiersprachen Die konkrete Ausführung eines Algorithmus nennt man einen Prozess, die Einheit, die den Prozess ausführt, ist ein Prozessor. Beim Kuchenbacken ist der Algorithmus das Rezept, der Prozess die Abarbeitung des Rezepts, der Prozessor der Koch. Hier denken wir natürlich an den Prozessor Computer“. Um eine Analyse des Ablaufs eines Algorithmus auf diesem Pro” zessor vornehmen zu können, ist ein geeignetes Modell für den Computer (Maschinenmodell) bereitzuhalten. Die Informatik studiert u.a. die Turing-Maschine und die Random-AccessMaschine (RAM), welche in gewissem Sinne sogar äquivalent sind. Die Analyse von Algorithmen auf einem abstrakten Niveau ist eine Disziplin der Informatik und/oder mathematischen Informatik. Die Hardware-Komponenten eines Computers sind • Zentraleinheit (CPU) • Speicher (Memory) • Ein- Ausgabegeräte (Input–, Output–Devices) Die Merkmale, die einen Computer bezüglich Hardware kennzeichnen sind Geschwindigkeit, Speichergröße, Zuverlässigkeit, Kosten, Vernetzbarkeit. Die Ausführung eines Algorithmus auf einem Prozessor setzt voraus, dass der Computer den Algorithmus interpretieren können muss, d.h. er muss • verstehen, was jeder Abarbeitungsschritt bedeutet, • die jeweilige Operation ausüben können. Dies leisten die Programmiersprachen. Die Algorithmen werden damit in Programmen aufgeschrieben; die einzelnen Schritte heißen nun (Programm–)Anweisung, Befehl. Bei einfachen Programmiersprachen (Maschinensprachen) kann jede Anweisung direkt vom Computer interpretiert werden. Da nur elementare Operationen damit erfasst werden, muss man sehr lange Programme schreiben. Zur Vereinfachung der Programmierung wurden höhere Programmiersprachen entwickelt. Programme in solchen Programmiersprachen können nicht direkt durch den Computer interpretiert werden, sie werden durch Übersetzungsprogramme in die Maschinensprache überführt. Der Übergang von Maschinensprachen zu höheren Programmiersprachen ist fließend. Es gibt eine ganze Hierarchie von Programmiersprachen: • Basic, Fortran • Algol • Pascal, C, C++, Java • Java, Python, . . . Auf Computern kann man Programme auf Vorrat“ für bestimmte Aufgaben ablegen. Diese ” Sammlung von Programmen nennt man Software. Man unterscheidet 15 • Anwendungssoftware (Textverarbeitungssoftware, Statistiksoftware, . . . ) • Systemsoftware (Betriebssystem, Editor, Compiler, . . . ) Besonderen Stellenwert nehmen Software-Pakete ein wie Maple, Mathematica, Derive, Matlab, R, Cinderella, die alle eine spezielle Ausrichtung haben: symbolisches Rechnen die ersten drei, numerisches Rechnen Matlab, statistisches Rechnen R, geometrisches Rechnen das letzte. 2.3 Sortieren Sei M eine endliche Menge mit n Elementen und versehen mit einer Ordnung ≤ . Sortieren heißt, die Elemente von M so anzuordnen, dass sie bzgl. der Ordnung ≤ eine aufsteigende Elementfolge bilden. Sortierverfahren werden benötigt etwa bei: Ordnung im Bücherregal, Einordnen von Schlüsseln im Werkzeugkasten, Ordnen der erhaltenen Karten beim Skatspiel, Sortieren von Dateien der Größe nach. Gesichtspunkte für die Leistungsfähigkeit eines Sortierverfahrens sind: Schnelligkeit. Wieviele Rechenoperationen (Vergleiche, Umstellen in einer Liste) in Abhängigkeit von n sind nötig? Dieser Aufwand wird Laufzeitkomplexität des Verfahrens genannt. Speicherplatz. Im allgemeinen kann man sich die Elemente der Menge abgelegt in Fächern vorstellen. Beim Sortieren kann es sinnvoll sein, Zusatzfächer zu benutzen. Der Bedarf an Fächern in Abhängigkeit von n ist die Speicherplatzkomplexität des Verfahrens. Sei nun eine Menge M = {a1 , . . . , an } vorgegeben. Wir denken uns die Elemente a1 , . . . , an jeweils einzeln in einer Liste (Feld von Fächern) abgelegt. Wir sortieren diese Liste, indem wir die Objekte in den Fächern irgendwie solange austauschen, bis sie angeordnet in den Fächern liegen. Sortieren durch Auswählen (Selection–sort). Hier geht man folgendermaßen vor: • Finde das kleinste Element und tausche es gegen das an der ersten Stelle befindliche Element (1. Schleife). • Fahre in dieser Weise jeweils auf dem Rest des Feldes, das noch nicht sortiert ist fort (i–te Schleife). Man stellt leicht fest, dass in der i–ten Schleife n − i Vergleiche und eventuell ein Austausch anfallen: Wegen n−1 X (n − i) = i=1 n−1 X j=1 1 1 j = ((1 + · · · + n − 1) + (n − 1 + · · · + 1)) = n(n − 1) 2 2 (2.1) gilt für die Komplexität: Es fallen etwa n2 /2 Vergleiche und etwa n Austausche an. Auf den Aufwand“ −n/2 bei den Vergleichen und −1 beim Austauschen kann man für große n verzich” ten; etwa“ bedeutet diese Vernachlässigung, wir schreiben dafür meist ∼. Hierzu ein Beispiel, ” wobei hier die Elemente die Buchstaben des Alphabets in ihrer alphabetischen Ordnung sind. Anwendung von Selection–sort auf unser Beispiel EXAMPLE ergibt die Sequenz (a). 16 EXAMPLE AXEMPLE AEXMPLE AEEMPLX AEELPMX AEELMPX EXAMPLE EXAMPLE AEXMPLE AEMXPLE AEMPXLE AELMPXE AEELMPX EXAMPLE EAXMPLE AEXMPLE AEMXPLE AEMPXLE AEMPLXE AEMLPXE AELMPXE AELMPEX AELMEPX AELEMPX AEELMPX EXAMPLE EEAMPLX EEALPMX EEALMPX EEAL EEA AEE A E E AEELMPX (a) Selection–sort (b) Insert–sort (c) Bubble–sort (d) Quick–sort M L L L PX M P X M P X M P X Sortieren durch Einfügen (Insert–sort). Betrachte die Listenelemente der Reihe nach und füge jedes an seinem richtigen Platz zwischen den bereits betrachteten ein, wobei diese sortiert bleiben. Das gerade bestimmte Element wird eingefügt, indem die größeren Elemente um eine Position nach rechts geschoben werden und das betrachtete Element auf dem frei gewordenen Platz eingefügt wird. Anwendung von Insert–sort auf unser Beispiel EXAMPLE ergibt die Sequenz (b). Man stellt fest, dass für die Laufzeitkomplexität gilt: ∼ n2 /2 Vergleiche , ∼ n2 /4 Austausche . Am besten macht man sich dies klar, wenn man ein Feld betrachtet, das gerade verkehrt herum sortiert ist.2 Sortieren durch Austausch (Bubble–sort). Durchlaufe immer wieder das Feld und vertausche jedesmal, wenn es notwendig ist, benachbarte Elemente; wenn beim Durchlauf kein Austausch mehr nötig ist, ist das Feld sortiert. Anwendung von Bubble–sort auf unser Beispiel EXAMPLE ergibt die Sequenz (c). Man stellt fest, dass für die Laufzeitkomplexität gilt: ∼ n2 /2 Vergleiche , ∼ n2 /2 Austausche . Sortieren nach Quick–sort. Dies ist der wohl am meisten angewendete Sortieralgorithmus. Seine Idee geht auf C.A.R. Hoare (1960) zurück. Es ist ein Vorgehen, das vom Typ Teile und Herrsche (divide et impera, divide and conquer) ist und auf einem Zerlegen des Feldes in zwei Teile und anschließendem Sortieren der Teile unabhängig voneinander beruht. Auf die Teile kann nun diese Idee wieder angewendet werden: Das Verfahren ist rekursiv, d.h. es ruft sich selbst (auf kleinerer Stufe) wieder auf. Wir kommmen im nächsten Kapitel auf das Prinzip Rekursivität“ zurück. ” Eine entscheidende Bedeutung kommt der Zerlegung eines Feldes zu. Es soll (zweckmäßigerweise) so erfolgen, dass gilt: Wird das Feld mit Hilfe des Elements ar zerlegt, so soll dies bedeuten: (1) ar befindet sich an seinem endgültigen Platz; (2) für alle j < r gilt aj ≤ ar ; (3) für alle j > r gilt aj ≥ ar . Bei jedem rekursiven Schritt wird eine solche Zerlegung benötigt. Wie findet man eine solche Zerlegung? Hier ist die Realisierung: 2 • Wähle irgendein ar . • Durchsuche das Feld von links, bis ein Element gefunden ist, das nicht kleiner als ar ist, und durchsuche das Feld von rechts, bis ein Element gefunden ist, das nicht größer als ar ist. Tausche die so gefundenen Elemente. Siehe http://www-i1.informatik.rwth-aachen.de/ algorithmus/algo2.php. 17 • Wiederhole den obigen Suchprozess solange, bis sich die Suche von links und rechts bei einem Element trifft. Nun ist das Element ar mit dem Element zu tauschen, bei dem sich die Suche von links und rechts getroffen hat. Ist das Feld nun zerlegt (Start), das Startfeld ist also nun a1 , . . . , ar , . . . , an , wird das Sortierverfahren auf die Teile a1 , . . . , ar−1 und ar+1 , . . . , an angewendet; als trennende Elemente können nun etwa die Elemente ar−1 und an verwendet werden. Anwendung von Quick–sort auf unser Beispiel EXAMPLE ergibt die Sequenz (d) (M ist beim Start das trennende Element). Das Beste, was bei Quick–sort passieren könnte, ist, dass durch jede Zerlegung das Feld genau halbiert wird. Dann würde die Anzahl Cn der von Quick–sort benötigten Vergleiche der rekurrenten Beziehung vom Typ Teile und Herrsche“ genügen (n gerade!): ” Cn = 2C n2 + n . (2.2) Dabei ist 2C n2 der Aufwand für das Sortieren der zwei halbierten Felder und n der Aufwand für die Zerlegung. Man kann zeigen, dass notwendigerweise Cn = n log2 n gilt. Die Vderifikation, dass diese Darstellung von Cn der Rekursion (2.2) genügt ist mit der Funktionalgleichung des Logarithmus einfach: n 2C n2 + n = n log2 ( ) + n = n(log2 n − 1) + n = n(log2 n = Cn . 2 In Kapitel ?? kommen wir auf die Logarithmusfunktion zurück. Für den allgemeinen Fall zeigt eine etwas aufwendigere Analyse Cn = 2n ln n . Eine wichtige Begriffsbildung ist die Laufzeitkomplexität im Mittel eines Verfahrens. Damit ist hier gemeint, wieviele Rechenschritte ein Sortierverfahren benötigt, wenn es auf ein zufällig“ vorsortiertes Feld angewendet wird. ” Wie wir oben gesehen haben, kann das Sortieren ganz schnell erledigt werden, wenn man nur den richtigen Algorithmus verwendet. Dies ist nun eine Feststellung, die sich im Kern auf alle Probleme anwenden lässt, die algorithmisiert werden können. Daher ist es so wichtig, den richtigen Algorithmus für ein Problem zu kennen und einzusetzen, da er möglicherweise ein Problem erst lösbar macht. 2.4 Computerzahlen In einer Grundvorlesung über Analysis beweist man folgenden Satz: Satz 2.4.1 Sei g eine Zahl in N mit g ≥ 2 . Für jedes x ∈ R, x 6= 0, gibt es genau eine Darstellung der Gestalt ∞ X x−k g−k (2.3) x = σgn k=1 mit σ ∈ {+, −}, n ∈ Z und x−k ∈ {0, 1, . . . , g−1}, wenn man von den Zahlen x−k noch zusätzlich fordert, dass x−1 6= 0 und dass zu jedem n ∈ N ein Index k ≥ n existiert mit x−k 6= g − 1 . Wichtige Spezialfälle von Satz (2.4.1) sind g = 10 (Dezimalsystem), g = 2 (Dualsystem), g = 8 (Oktalsystem) und g = 16 (Hexadezimalsystem). Beim Hexadezimalsystem benötigen wir zusätzlich Ziffern“, da man etwa 12 nicht als Ziffer verwenden will. Man wählt ” 0, 1, . . . , 9, A, B, C, D, E, F . In (2.3) ist also die Zahl x durch eine Reihe dargestellt, wobei der ganze Anteil“ gn mit ” Exponent n abgespaltet wurde, die Forderung x−1 6= 0“ macht diese Abspaltung eindeutig. ” 18 g heißt Basis der Darstellung, welche im Allgemeinen eine gerade Zahl ist. σ steht für das Vorzeichen der Zahl. Die Forderung x−k 6= g − 1“ für fast alle k schließt aus, dass eine ” Nichteindeutigkeit, wie wir sie vom Dezimalsystem in Form von 0.99999 · · · = 1.00000 . . . kennen, zugelassen ist. Die positionelle Schreibweise sieht so aus: (x)g := σ0.a−1 a−2 · · · gn . (2.4) Der Punkt zwischen 0 und a−1 wird Dezimalpunkt genannt, wenn g = 10, Binärpunkt, wenn g = 2. Eine Zahl x kann eine endliche Anzahl von Ziffern haben bezüglich einer Basis und eine unendliche Anzahl von Ziffern in einer anderen Basis. Zum Beispiel gilt für x = 1/3: (x)10 = +0.33333 · · · =: +0.3 , (x)3 = +0.1 . Für x := 103 3/4 haben wir (x)10 = +[103.75] , (x)2 = +[1100111.11] , (x)16 = +[67.C] . Um jede Ziffer in der Darstellung (2.4) im Dualsystem darstellen zu können, benötigen wir einen Code, d.h. eine Darstellung in einem anderen Alphabet; siehe Anhang 1.5. Für das Oktalsystem (g = 8) kann man etwa nutzen: Ziffer 0 1 2 3 4 5 6 7 Codewort 000 001 010 011 100 101 110 111 Für die Zahlen, die wir oben beschrieben haben, benötigen wir im Allgemeinen unendlich viele Speicherplätze. Daher müssen wir die Darstellung (2.4) für eine Computernutzung einschränken. Dies geschieht dadurch, dass die Reihe bei einem t ∈ N, der Mantissenlänge, abgebrochen wird und der Exponent n eingeschränkt wird. So gelangen wir zur Darstellung (x)g = σ0.x−1 . . . x−t ge wobei t ∈ N die Anzahl der erlaubten signifikanten Ziffern x−i ∈ {0, 1, . . . , g − 1} ist; e ∈ Z wird Exponent genannt, welcher in einem Bereich emin , emax variieren kann. Damit gelangen wir zur Menge der Computerzahlen/Fließkommazahlen x−1 , . . . x−t ∈ {0, 1, . . . , g − 1}, x−1 6= 0, e F := F(g, t, emin , emax ) := σ 0.x−1 . . . x−t g | . e ∈ Z, emin ≤ e ≤ emax , σ ∈ {+, −} Es ist einfach, diese Zahlen zu zählen: #F(g, t, emin , emax ) = 2(g − 1)gt−1 (emax − emin + 1) Natürlich ist in einem Computerzahlsystem auch die Null realisiert. Damit sind dann #F(g, t, emin , emax )+ 1 Zahlen verfügbar. In F(g, t, emin , emax ) sind größte und kleinste Zahl gegeben durch xmin := +[10 . . . 0] gemin −t = gemin −1 , xmax := +[δ . . . δ] gemax −t = gemax (1−g−t ) wobei δ = g−1 . Offenbar gilt für alle Computerzahlen x 6= 0 g−emin −1 ≤ |x| ≤ gemax . Hat man eine reelle Zahl x mit |x| < g−emin −1 , so wird im Allgemeinen x durch Null ersetzt. Zahlen x mit |x| > gemax können nicht verarbeitet werden. Treten diese Fälle auf, so spricht man von Exponentenüberlauf. In jedem Intervall [ge−1 , ge ], emin ≤ e ≤ emax , finden wir µ = gt − gt−1 + 1 gleichförmig verteilte Zahlen: F ∩ [ge−1 , ge ] = {ge−1 , ge−1 + ge−t , . . . , ge−1 + µge−t } . (2.5) Beachte, dass der Zuwachs ge−t anwächst, wenn e von emin auf emax anwächst. 19 Lemma 2.4.2 Betrachte das System F(g, t, emin , emax ) . Sei x eine reelle Zahl mit xmin ≤ |x| ≤ xmax . Dann gilt: |z − x| 1 min ≤ g−t+1 . (2.6) z∈F |x| 2 Beweis: Ohne Einschränkungen können wir annehmen: x ist positiv. Wir können annehmen, dass mit einem e mit emin ≤ e ≤ emax gilt: x ∈ [ge−1 , ge ] . Aus (2.5) erhalten wir, dass eine Zahl z ∈ [ge−1 , ge ] mit |z − x| ≤ 21 ge−t existiert. Wegen ge−1 ≤ x ist die Behauptung bewiesen. Die Zahl eps := 12 g−t+1 heißt Maschinengenauigkeit. Beachte, sie hängt nur von der Mantissenlänge t ab. Auf einem Computer sind üblicherweise zwei Formate von Fließkommazahlen verfügbar: einfache und doppelte Genauigkeit. Im IEEE-Standard mit einfacher Geneauigkeit haben wir eps = 2−23 ≈ 10−7 . Wegen des nötigen Übergangs von einer reellen Zahl x zu einer Computerzahl, muss x im Allgemeinen durch eine Approximation ersetzt werden. Dieser Prozess wird als Runden bezeichnet. Sei F das obige System der Computerzahlen. Es werden zwei Wege beschritten, eine gegebene reelle Zahl x durch eine Computerzahl f l(x) zu ersetzen: Runden und Abschneiden. Betrachte die positive reelle Zahl x dargestellt durch x = σ0.x−1 . . . d−t d−t−1 . . . ge . Abschneiden: ch(x) := σ0.x−1 . . . d−t ge . Rundung: ( σ0.x−1 . . . (1 + d−t ) ge rd(x) := σ0.x−1 . . . d−t ge , falls dt+1 ≥ g/2 . , sonst Der Fehler, der ensteht, wenn man x durch f l(x) ersetzt, wird Rundungsfehler genannt. Definition 2.4.3 Sei x eine reelle Zahl, x 6= 0 . Der absolute Fehler von x ist gegeben durch |x − f l(x)| und der relative Fehler durch |x − f l(x)|/|x| . Korollar 2.4.4 Sei das System F(g, t, emin , emax ) gegeben und sei x eine reelle Zahl mit xmax ≤ |x| ≤ xmin . Dann folgt für den relativen Rundungsfehler: |ch(x) − x| |rd(x) − x| ≤ eps , ≤ 2eps . |x| |x| (2.7) Die Grundoperationen der Arithmetik sind +, −, ·, / . Wie sind diese Operationen realisiert in einem Fließkommasystem F := F(g, t, emin , emax )? Sei ⋄ eine der Operationen +, −, ·, / . Wir bezeichnen die entsprechende Operation, realisiert in F mit ⋄∗ . Wir nehmen an, dass sie so realisiert sei: x ⋄∗ y := f l(x ⋄ y) für x, y ∈ F mit xmin ≤ |x ⋄∗ y| ≤ xmax . (2.8) Klar, im Fall ⋄ = / haben wir anzunehmen, dass y 6= 0 . Als Konsequenz haben wir: x ⋄∗ y = (x ⋄ y)(1 + τ ) mit |τ | ≤ κ eps . Hier ist κ eine Konstante, die nicht von x, y abhängt. Probleme der Computer-Arithmetik sind: 20 Überlauf Siehe oben. Unterlauf Siehe oben. Auslöschung Addition etwa gleich großer Zahlen mit entgegengesetztem Vorzeichen führt zu einer starken Verringerung der Zahl der gültigen Ziffern. Ungültigkeit von Rechenregeln Selbst in Fällen, wo weder Überlauf noch Unterlauf eintritt, gelten die Rechenregeln der reellen Zahlen im allgemeinen nicht mehr. 2.5 Anhang: Abbildungen Mit Abbildungen drücken wir den mathematischen Sachverhalt aus, dass es zwischen zwei Objekten eine klar definierte Abbhängigkeit gibt. Definition 2.5.1 Seien A, B, C, D Mengen. (a) Eine Abbildung f von A nach B ist eine Vorschrift, durch die jedem a ∈ A genau ein Bild f (a) ∈ B zugeordnet wird; A heißt Definitionsbereich, B heißt Wertebereich von f. Wir schreiben f : A −→ B . (b) Zwei Abbildungen f : A −→ B, g : C −→ D heißen gleich, wenn gilt: A = C, B = D, f (x) = g(x) für alle x ∈ A . Wir werden später auch von Funktionen sprechen. In unserem Verständnis ist eine Funktion ein Spezialfall einer Abbildung: wir sprechen dann von einer Funktion, wenn wir eine Abbildung zwischen Zahlbereichen haben, d.h. wenn Definitions– und Wertebereich der Abbildung Mengen von Zahlen sind.3 Beispiel 2.5.2 Sei A eine Menge. Dann nennt man die Abbildung idA : A ∋ x 7−→ x ∈ A die Identität auf A. (Manchmal lassen wir den Index A weg und schreiben einfach id, wenn klar ist, um welches A es sich handelt.) Beispiel 2.5.3 Seien A, B Mengen. Dann heißt die Abbildung π1 : A × B ∋ (a, b) 7−→ a ∈ A die Projektion auf den ersten Faktor.4 Es sollte klar sein, dass entsprechend auch die Projektionen auf beliebige Faktoren in einem kartesischen Produkt erklärt sind. Definition 2.5.4 Sei f : A −→ B eine Abbildung. Die Menge graph(f ) := {(a, b) ∈ A × B|a ∈ A, b = f (a)} heißt der Graph von f . 3 Der Abbildungsbegriff, wie wir ihn hier eingeführt haben, konnte erst nach G. Cantor in Mode“ kommen, ” da nun Mengen handhabare Objekte waren. 4 Die Wortwahl wird verständlich, wenn wir uns A × A als Koordinatensystem realisiert denken. Dann wird von einem Punkt durch Beleuchtung parallel zur zweiten Koordinatenachse auf der ersten Achse der projezierte Punkt sichtbar. 21 Definition 2.5.5 Sei f : X −→ Y eine Abbildung und seien A ⊂ X, B ⊂ Y . Dann heißt die Menge f (A) := {f (x)|x ∈ A} die Bildmenge von A oder das Bild von A, und die Menge −1 f (B) := {x ∈ X|f (x) ∈ B} heißt die Urbildmenge von B oder einfach das Urbild von B. Sei A eine Menge. Jede Abbildung N ∋ n 7−→ xn ∈ A nennt man eine Folge mit Folgengliedern aus A . Meist schreiben wir dafür kurz (xn )n∈N . Regel 2.5.6 Sei f : X −→ Y, A1 , A2 ⊂ X, B1 , B2 ⊂ Y . A1 ⊂ A2 =⇒ f (A1 ) ⊂ f (A2 ) (2.9) f (A1 ∪ A2 ) = f (A1 ) ∪ f (A2 ) (2.10) f (A1 ∩ A2 ) ⊂ f (A1 ) ∩ f (A2 ) (2.11) −1 B1 ⊂ B 2 =⇒ −1 f (B1 ) ⊂ f (B2 ) −1 −1 f (B1 ∪ B2 ) = (2.12) −1 f (B1 ) ∪ f (B2 ) (2.13) Beweisen wir etwa (2.13). Da eine Gleichheit von Mengen behauptet wird, sind zwei Inklusionen zu verifizieren. −1 −1 −1 Zu f (B1 ∪ B2 ) ⊂ f (B1 ) ∪ f (B2 ) . −1 −1 Sei x ∈ f (B1 ∪ B2 ) . Also gilt f (x) ∈ B1 ∪ B2 . Ist f (x) ∈ B1 , dann ist x ∈ f (B1 ) ⊂ −1 −1 −1 −1 −1 f (B1 ) ∪ f (B2 ) . Ist f (x) ∈ B2 , dann ist x ∈ f (B2 ) ⊂ f (B1 ) ∪ f (B2 ) . −1 −1 −1 Zu f (B1 ) ∪ f (B2 ) ⊂ f (B1 ∪ B2 ) . −1 −1 −1 −1 Sei x ∈ f (B1 ) ∪ f (B2 ) . Ist x ∈ f (B1 ), dann ist f (x) ∈ B1 ⊂ B1 ∪ B2 , d.h. x ∈ f (B1 ∪ B2 ) . −1 −1 Ist x ∈ f (B2 ), dann ist f (x) ∈ B2 ⊂ B1 ∪ B2 , d.h. x ∈ f (B1 ∪ B2 ) . Definition 2.5.7 Seien f : X −→ Y , g : Y −→ Z Abbildungen. Die Hintereinanderausführung oder Komposition g ◦ f der Abbildungen f, g ist erklärt durch g ◦ f : X ∋ x 7−→ g(f (x)) ∈ Z . Regel 2.5.8 Seien f : X −→ Y, g : Y −→ Z, h : Z −→ W Abbildungen. idY ◦ f = f ◦ idX h ◦ (g ◦ f ) = (h ◦ g) ◦ f (2.14) (2.15) Die Identität in (2.15) nennt man das Assoziativgesetz. Man beachte, dass für die Hintereinanderausführung von Abbildungen ein Kommutativgesetz ( f ◦ g = g ◦ f ) im allgemeinen nicht gilt. 22 Definition 2.5.9 Sei f : X −→ Y eine Abbildung. (i) f injektiv genau dann, wenn für alle x, x′ ∈ X x 6= x′ =⇒ f (x) 6= f (x′ ) gilt. (ii) f surjektiv genau dann, wenn für alle y ∈ Y ein x ∈ X existiert mit y = f (x) . (iii) f bijektiv : ⇐⇒ f injektiv und surjektiv Ohne Beweis halten wir fest: Satz 2.5.10 Sei f : X −→ Y eine Abbildung. Dann ist f bijektiv genau dann, wenn g : Y −→ X existiert mit g ◦ f = idX , f ◦ g = idY . Definition 2.5.11 Sei f : X −→ Y bijektiv. Die nach Satz 2.5.10 eindeutig bestimmte Abbildung5 g mit g ◦ f = f ◦ g = id heißt die (zu f ) inverse Abbildung. Wir schreiben dafür f −1 . 2.6 1.) Übungen S Sei A ein (endliches) Alphabet, sei A∗ := {()} ∪ n∈N An die Menge der Wörter (beliebiger Länge) über dem Alphabet A . Für zwei Worte u = (u1 , . . . , uk ) ∈ Ak , v = (v1 , . . . , vl ) ∈ Al setzen wir: uv := (u1 , . . . , uk , v1 , . . . , vl ) ∈ Ak+l . Wir definieren für u, v ∈ A∗ : u ≤ v : ⇐⇒ Es gibt z ∈ A∗ mit uz = v . (a) Zeige: ≤ ist eine Halbordnung in A∗ . (b) Ist ≤ stets eine Ordnung in A∗ ? (c) Gibt es in A∗ ein Wort w, so dass gilt: w ≤ u für alle u ∈ A∗ . 2.) Eine Permutation der Zahlen 1, 2, . . . , n ist eine Umstellung dieser Zahlen. (a) Ermittle die Anzahl der Permutationen von 1, 2, . . . , 8 . (b) Die Fehlstandszahl einer Permutation ist die Anzahl der Paare (i, j), die nach Umstellung mit dieser Permutation in falscher Reihenfolge stehen. Ermittle die Anzahl der Permutationen von 1, 2, . . . , 5 mit ungerader Fehlstandszahl. 3.) Finde ein Darstellung des periodischen Dezimalbruchs x = 123.456 im Dualsystem. 4.) Betrachte das Fließkommasystem F := F(2, 2, −2, 2). (a) Bestimme von den positiven Zahlen F+ in F die kleinste Zahl xmin und größte Zahl xmax . (b) Wie weit sind die nächsten Nachbarn in F+ von xmin bzw. xmax entfernt? 5.) Betrachte das Fließkommasystem F := F(2, 3, −1, 2) . (a) Bestimme alle positiven Zahlen in F . (b) x := 1/4, y := 7/8 liegen in F . Liegt auch x + y in F ? 5 In der Literatur spricht man bei bijektiven Abbildungen oft auch von umkehrbar eineindeutigen Abbildungen. In Satz 2.5.10 zusammen mit Definition 2.5.9 liegt die Berechtigung für eine solche Sprechweise. 23