Namen und Bezeichner Ein Programm (also Klasse) braucht einen Namen 3. Java - Sprachkonstrukte I Namen und Bezeichner, Variablen, Zuweisungen, Konstanten, Datentypen, Operationen, Auswerten von Ausdrücken, Typkonversionen public class SudokuSolver {... Konvention für Klassennamen: CamelCase benützen Wörter sind zusammengeschrieben mit jeweils einem Grossbuchstaben Erlaubte Namen für Entitäten im Programm: Namen beginnen mit einem Buchstaben oder _ oder $ Danach Folge von Buchstaben, Zahlen oder _ oder $ 62 63 Namen - was ist erlaubt Schlüsselwörter Folgende Wörter werden von der Sprache bereits benützt und können deshalb nicht als Namen benützt werden: _myname AN$WE4_1S_42 $bling$ TheCure me@home strictfp 49ers?! side-swipe Ph.D s abstract continue for new switch assert default goto package synchronized boolean do if private this break double implements protected throw byte else import public throws case enum instanceof return transient catch extends int short try char final interface static void class finally long strictfp volatile const float native super while 64 65
Variablen und Konstanten Konstanten Variablen sind Behälter für einen Wert Haben einen Datentyp und einen Namen Der Datentyp bestimmt, welche Art von Werten in der Variable erlaubt sind int x 23 int y 42 float f 0.0f char c a Deklaration in Java: int x = 23, y = 42; float f; char c = a ; Initialisierung Schlüsselwort final Der Wert der Variable kann genau einmal gesetzt werden final int maxsize = 100; Tip: Benützen Sie final immer, es sei denn der Wert muss tatsächlich veränderlich sein. 66 67 Standardtypen Typen und Speicherbelegung Datentyp Definition Wertebereich Initialwert byte 8-bit Ganzzahl 128,..., 127 0 short 16-bit Ganzzahl 32 768,..., 32 767 0 int 32-bit Ganzzahl 2 31,..., 2 31 1 0 long 64-bit Ganzzahl 2 63,..., 2 63 1 0L float 32-bit Fliesskommazahl ±1.4E 45,..., ±3.4E +38 0.0f double 64-bit Fliesskommazahl ±4.9E 324,..., ±1.7E +308 0.0d Zur Erinnerung: Speicherzellen enthalten 1 Byte = 8 bit boolean byte short, char boolean Wahrheitswert true, false false char Unicode-16 Zeichen \u0000,..., a, b,..., \uffff \u0000 String Zeichenkette null int, float long, double 68 69
Literale: Ganzzahlen Literale: Fliesskommazahlen Typ int (oder short, byte) unterscheiden sich von Ganzzahlliteralen durch Angabe von 12 : Wert 12-3 : Wert 3 Dezimalkomma 1.0 : Typ double, Wert 1 1.23e-7f Typ long 25_872_224L : Wert 25 872 224 1.27f : Typ float, Wert 1.27 und / oder Exponent. 1e3 : Typ double, Wert 1000 ganzzahliger Teil fraktionaler Teil Exponent Tip: Unterstriche zwischen Zahlen sind erlaubt! 1.23e-7 : Typ double, Wert 1.23 10 7 70 1.23e-7f : Typ float, Wert 1.23 10 7 71 Literale: Zeichen und Zeichenketten Zeichen: In ASCII Tabelle Einzelne Zeichen: a : Typ char, Wert 97 Zeichenketten: "Hello There!" : Typ String "a" : Typ String Achtung: Zeichen und Zeichenketten sind zwei unterschiedliche Dinge! 72 73
Wertzuweisungen Kopiert einen Wert in die Variable x In Pseudocode: x Wert In Java: x = Wert x Wert (Kopie) = ist der Zuweisungsoperator und nicht ein Vergleich! int y = 42 ist also Deklaration + Wertzuweisung in einem. Wert Wertzuweisungen e int a = 3; double b; b = 3.141; int c = a = 0; String name = "Inf"; Eine verschachtelte Zuweisung: Der Ausdruck a = 0 speichert den Wert 0 in Variable a. und gibt den Wert danach zurück 74 75 Arithmetische Binäre Operatoren Arithmetische Binäre Operatoren Infix Notation: x op y mit folgenden Operatoren op: + / % Modulo Präzedenz: Punkt (und Modulo) vor Strich Assoziativität: Auswertung von Links nach Rechts Division x / y: Ganzzahldivision falls x und y Ganzzahlen sind. Division x / y: Fliesskommadivision falls x oder y eine Fliesskommazahl ist. e Ganzzahldivision und Modulo 5 / 3 ergibt 1 5 / 3 ergibt 1 5 % 3 ergibt 2 5 % 3 ergibt 2 76 77
Arithmetische Zuweisung Arithmetische Unäre Operatoren x = x + y x += y Analog für,, /, % e: x = 3; // x = x 3 name += "x" // name = name + "x" num = 2; // num = num 2 Prefix Notation: + x oder x Präzedenz: Unäre Operatoren binden stärker als binäre. e Angenommen x ist 3 2 x ergibt 6 x +1 ergibt 4 78 79 Inkrement/Dekrement Operatoren Inkrement Operatoren ++x und x++ haben den gleichen Effekt: x x + 1.Aber unterschiedliche Rückgabewerte: Präfixoperator ++x gibt neuen Wert zurück: a = ++x; x = x + 1; a = x; Postfixoperator x++ gibt den alten Wert zurück: a = x++; temp = x; x = x + 1; a= temp; Präzedenz: Inkrement und Dekrement binden stärker als unäre Operatoren. Analog für x und x. Inkrement/Dekrement Operatoren e Angenommen x ist initial 2 y = ++x 3 ergibt: x ist 3 und y ist 9 y = x++ 3 ergibt: x ist 3 und y ist 6 80 81
Ausdrücke (Expressions) Ausdrücke (Expressions) repräsentieren Berechnungen sind entweder primär oder zusammengesetzt...... aus anderen Ausdrücken, mit Hilfe von Operatoren sind statisch typisiert e primär: 4.1d oder x oder "Hi" zusammengesetzt: x + y oder f 2.1f Der Typ von 12 2.1f ist float Analogie: Baukasten 82 83 Celsius zu Fahrenheit Celsius zu Fahrenheit - Analye public class Main { } public static void main(string[] args) { Out.print("Celsius: "); int celsius = In.readInt(); float fahrenheit = 9 * celsius / 5 + 32; Out.println("Fahrenheit: " + fahrenheit); } : 15 Celsius sind 59 Fahrenheit 9 * celsius / 5 + 32 Arithmetischer Ausdruck, enthält drei Literale, eine Variable, drei Operatorsymbole Wie ist der Ausdruck geklammert? 84 85
Regel 1: Präzedenz Regel 2: Assoziativität Multiplikative Operatoren (*, /, %) haben höhere Präzedenz ("binden stärker") als additive Operatoren (+, -). Arithmetische Operatoren (*, /, %, +, -) sind linksassoziativ: bei gleicher Präzedenz erfolgt Auswertung von links nach rechts. Beipsiel 9 * celsius / 5 + 32 bedeutet (9 * celsius / 5) + 32 9 * celsius / 5 + 32 bedeutet ((9 * celsius) / 5) + 32 86 87 Regel 3: Stelligkeit Klammerung Unäre Operatoren +, - vor binären +, -. 9 * celsius / + 5 + 32 bedeutet 9 * celsius / (+5) + 32 Jeder Ausdruck kann mit Hilfe der Assoziativitäten Präzedenzen Stelligkeiten (Anzahl Operanden) der beteiligten Operatoren eindeutig geklammert werden. 88 89
Ausdrucksbäume Klammerung ergibt Ausdrucksbaum (((9 * celsius) / 5) + 32) 9 celsius 5 32 * / + Auswertungsreihenfolge "Von den Blättern zur Wurzel" im Ausdrucksbaum 9 * celsius / 5 + 32 9 celsius 5 32 * / + 90 91 Ausdrucksbäume Notation Üblichere Notation: Wurzel oben 9 * celsius / 5 + 32 + Typsystem Java hat ein statisches Typsystem: Alle Typen müssen deklariert werden Wenn möglich wird die Typisierung vom Compiler geprüft...... ansonsten zur Laufzeit / 32 Vorteil eines statischen Typsystems * 9 celsius 5 Fail-fast Fehler im Programm werden oft schon vom Compiler gefunden Verständlicher Code 92 93
Typfehler int pi_ish; float pi = 3.14f; pi_ish = pi; Explizite Typkonvertierung int pi_ish; float pi = 3.14f; pi_ish = (int) pi; Compiler Fehler:./Root/Main.java:12: error: incompatible types: possible lossy conversion from float to int pi_ish = pi; ^ Explizite Typkonvertierung mit Typecasting: (typ) Statisch typkorrekt, Compiler happy Laufzeitverhalten: Je nach Situation Hier: Genauigkeitsverlust: 3.14 3 94 Kann das Programm zur Laufzeit zum Absturz bringen! 95 Typ Konvertierung - Anschaulich für Ganzzahlen Gemischte Ausdrücke, Konversion Expliziter Cast byte short int long Implizite Konversion Fliesskommazahlen sind allgemeiner als ganzzahlige Typen. In gemischten Ausdrücken werden ganze Zahlen zu Fliesskommazahlen konvertiert. 9 * celsius / 5 + 32 Potentieller Informationsverlust bei explizitem Cast, da weniger Speicher zur Verfügung. 96 97
Typkonversion bei binären Operationen Bei einer binären Operation mit numerischen Operanden werden die Operanden nach folgenden Regeln konvertiert: Haben beide Operanden denselben Typ, findet keine Konversion statt Ist einer der Operanden double, so wird der andere nach double konvertiert Ist einer der Operanden float, so wird der andere nach float konvertiert Ist einer der Operanden long, so wird der andere nach long konvertiert Ansonsten: Beide Operanden werden nach int konvertiert 4. Effizienz von Algorithmen Effizienz von Algorithmen, Random Access Machine Modell, Funktionenwachstum, Asymptotik [Cormen et al, Kap. 2.2,3,4.2-4.4 Ottman/Widmayer, Kap. 1.1] 98 99 Effizienz von Algorithmen Technologiemodell Random Access Machine (RAM) Ziele Laufzeitverhalten eines Algorithmus maschinenunabhängig quantifizieren. Effizienz von Algorithmen vergleichen. Abhängigkeit von der Eingabegrösse verstehen. Ausführungsmodell: Instruktionen werden der Reihe nach (auf einem Prozessorkern) ausgeführt. Speichermodell: Konstante Zugriffszeit. Elementare Operationen: Rechenoperation (+,,,...), Vergleichsoperationen, Zuweisung / Kopieroperation, Flusskontrolle (Sprünge) Einheitskostenmodell: elementare Operation hat Kosten 1. Datentypen: Fundamentaltypen wie grössenbeschränkte Ganzzahl oder Fliesskommazahl. 100 101
Grösse der Eingabedaten Asymptotisches Verhalten Genaue Laufzeit lässt sich selbst für kleine Eingabedaten kaum voraussagen. Typisch: Anzahl Eingabeobjekte (von fundamentalem Typ). Oftmals: Anzahl Bits für eine vernünftige / kostengünstige Repräsentation der Daten. Betrachten das asymptotische Verhalten eines Algorithmus. Ignorieren alle konstanten Faktoren. Eine Operation mit Kosten 20 ist genauso gut wie eine mit Kosten 1. Lineares Wachstum mit Steigung 5 ist genauso gut wie lineares Wachstum mit Steigung 1. 102 103 Oberflächlich 4.2 Funktionenwachstum O, Θ, Ω [Cormen et al, Kap. 3; Ottman/Widmayer, Kap. 1.1] Verwende die asymptotische Notation zur Kennzeichnung der Laufzeit von Algorithmen Wir schreiben Θ(n 2 ) und meinen, dass der Algorithmus sich für grosse n wie n 2 verhält: verdoppelt sich die Problemgrösse, so vervierfacht sich die Laufzeit. 104 105
Genauer: Asymptotische obere Schranke Anschauung Gegeben: Funktion g : N R. Definition: O(g) = {f : N R c > 0, n 0 N : 0 f(n) c g(n) n n 0 } g(n) = n 2 f O(g) Schreibweise: O(g(n)) := O(g( )) = O(g). h O(g) 106 n 0 107 e Eigenschaft O(g) = {f : N R c > 0, n 0 N : 0 f(n) c g(n) n n 0 } f(n) f O(?) 3n + 4 O(n) c = 4, n 0 = 4 2n O(n) c = 2, n 0 = 0 n 2 + 100n O(n 2 ) c = 2, n 0 = 100 n + n O(n) c = 2, n 0 = 1 f 1 O(g), f 2 O(g) f 1 + f 2 O(g) 108 109
Umkehrung: Asymptotische untere Schranke Gegeben: Funktion g : N R. Definition: Ω(g) = {f : N R c > 0, n 0 N : 0 c g(n) f(n) n n 0 } h Ω(g) f Ω(g) g(n) = n n 0 110 111 Asymptotisch scharfe Schranke Gegeben Funktion g : N R. Definition: Θ(g) := Ω(g) O(g). Einfache, geschlossene Form: Übung. g(n) = n 2 f Θ(n 2 ) h(n) = 0.5 n 2 112 113
Wachstumsbezeichnungen Kleine n O(1) beschränkt Array-Zugriff O(log log n) doppelt logarithmisch Binäre sortierte Suche interpoliert O(log n) logarithmisch Binäre sortierte Suche O( n) wie die Wurzelfunktion Primzahltest (naiv) O(n) linear Unsortierte naive Suche O(n log n) superlinear / loglinear Gute Sortieralgorithmen O(n 2 ) quadratisch Einfache Sortieralgorithmen O(n c ) polynomial Matrixmultiplikation O(2 n ) exponentiell Travelling Salesman Dynamic Programming O(n!) faktoriell Travelling Salesman naiv 60 40 20 n 4 2 n n 2 n ln n 2 3 4 5 6 114 115 Grössere n Grosse n 1 0.8 10 6 2 n 0.8 1 1020 2 n 0.6 0.6 0.4 n 4 0.4 0.2 5 10 15 20 n 2 log n 0.2 n 4 n 2 20 40 60 80 100log n 116 117
Logarithmen! 1,000 800 600 400 200 n 2 n 3/2 n log n n log n 10 20 30 40 50 Zeitbedarf Annahme: 1 Operation = 1µs. Problemgrösse 1 100 10000 10 6 10 9 log 2 n 1µs 7µs 13µs 20µs 30µs n 1µs 100µs 1/100s 1s 17 Minuten n log 2 n 1µs 700µs 13/100µs 20s 8.5 Stunden n 2 1µs 1/100s 1.7 Minuten 11.5 Tage 317 Jahrhund. 2 n 1µs 10 14 Jahrh. 118 119 Eine gute Strategie?... dann kaufe ich mir eben eine neue Maschine! Wenn ich heute ein Problem der Grösse n lösen kann, dann kann ich mit einer 10 oder 100 mal so schnellen Maschine... Komplexität (speed 10) (speed 100) log 2 n n n 10 n n 100 n n 10 n n 100 n n 2 n 3.16 n n 10 n 2 n n n + 3.32 n n + 6.64 e n O(n 2 ) korrekt, aber ungenau: n O(n) und sogar n Θ(n). 3n 2 O(2n 2 ) korrekt, aber unüblich: Konstanten weglasssen: 3n 2 O(n 2 ). 2n 2 O(n) ist falsch: 2n2 cn = 2 c n n! O(n) O(n 2 ) ist korrekt Θ(n) Θ(n 2 ) ist falsch: n Ω(n 2 ) Θ(n 2 ) 120 121
Nützliches Theorem Seien f, g : N R + zwei Funktionen. Dann gilt: f(n) 1 lim n g(n) f(n) 2 lim n g(n) 3 f(n) g(n) = 0 f O(g), O(f) O(g). = C > 0 (C konstant) f Θ(g). n g O(f), O(g) O(f). Zur Notation Übliche Schreibweise f = O(g) ist zu verstehen als f O(g). Es gilt nämlich f 1 = O(g), f 2 = O(g) f 1 = f 2! n = O(n 2 ), n 2 = O(n 2 ) aber natürlich n n 2. 122 123 Algorithmen, Programme und Laufzeit Programm: Konkrete Implementation eines Algorithmus. Laufzeit des Programmes: messbarer Wert auf einer konkreten Maschine. Kann sowohl nach oben, wie auch nach unten abgeschätzt werden. Rechner mit 3 GHz. Maximale Anzahl Operationen pro Taktzyklus (z.b. 8). untere Schranke. Einzelne Operation dauert mit Sicherheit nie länger als ein Tag obere Schranke. Asymptotisch gesehen stimmen die Schranken überein. Komplexität Komplexität eines Problems P : minimale (asymptotische) Kosten über alle Algorithmen A, die P lösen. Komplexität der Elementarmultiplikation zweier Zahlen der Länge n ist Ω(n) und O(n log 3 2 ) (Karatsuba Ofman). Exemplarisch: Problem Komplexität O(n) O(n) O(n 2 ) Algorithmus Kosten 2 3n 4 O(n) Θ(n 2 ) Programm Laufzeit Θ(n) O(n) Θ(n 2 ) 124 2 Anzahl Elementaroperationen 125