Algorithmus und Programm - Technische Universität Braunschweig

Werbung
Algorithmus und Programm:
Vom Algorithmus zum Programm
1.1
1.2
1.3
1.4
Vom Algorithmus zum Programm
Programmiersprachen
Korrektheit, Komplexität und Entscheidbarkeit
Software-Grundlagen
1.1 Vom Algorithmus zum Programm
1-1
Algorithmusbegriff
Ein Algorithmus ist eine „Berechnungsvorschrift“. Die Aufgabe, die der Algorithmus
lösen soll, wird durch eine Spezifikation festgelegt.
• Die Berechnungsvorschrift wird durch einen endlichen Text kodiert.
• Sie beschreibt die auszuführenden Berechnungen „hinreichend präzise“.
• Die Berechnungen sind aus „elementaren“ Operationen aufgebaut und besitzen
Aus- und evtl. Eingabewerte.
Hierbei handelt es ich um eine sog. intuitive Definition. In der Informatik wird auch
eine formale Definition benötigt, zum Beispiel zum Nachweis, dass für ein bestimmtes
Problem kein Algorithmus existiert.
»Intuitiv heißt nicht erlernt.«
1.1 Vom Algorithmus zum Programm
(Bruce M. Hood)
1-2
Eigenschaften von Algorithmen
• Algorithmen sollen in der Regel terminieren, d. h. bei jeder Eingabe irgendwann zu
einem Ende führen. Es gibt Ausnahmen: z. B. Betriebssysteme oder sogenannte
„reaktive Systeme“.
• Die Terminierung wird in der Definition des Algorithmusbegriffs nicht verwendet.
Ein Grund hierfür ist zum Beispiel das Halteproblem (s. unten): Definitionen
müssen überprüfbar sein.
• Einen Algorithmus nennt man deterministisch, wenn er bei gleichen Eingabedaten
stets die gleiche Berechnung ausführt.
• Ein Algorithmus heißt determiniert, wenn er bei gleichen Eingabedaten stets die
gleichen Ausgabedaten liefert.
1.1 Vom Algorithmus zum Programm
1-3
Programm und Programmiersprache
Ein Programm ist die Formulierung eines Algorithmus mit seiner Datenbereiche in
einer Programmiersprache. Eine Programmiersprache erlaubt es, Algorithmen präzise
zu beschreiben. Insbesondere legt eine Programmiersprache
• die elementaren Operationen,
• die Möglichkeiten zu ihrer Kombination und
• die zulässigen Datenbereiche
eindeutig fest. Unter „programmieren“ versteht man den Vorgang des Erstellens eines
Programms.
1.1 Vom Algorithmus zum Programm
1-4
Grundlegende Aspekte der Algorithmenentwicklung
• Wie wird ein Algorithmus formuliert? Paradigma.
Beispiele für Paradigmen: imperativ, objektorientiert, funktional, logisch.
Es gibt weitere Paradigmen, diese vier sind aber die am häufigsten erwähnten.
Weitere Bezeichnungen für Paradigmen: hybrid, prozedural, deklarativ.
• Mit welchem Aufwand löst der Algorithmus das Problem? Komplexität.
Beispiele zur Komplexität: benötigte Rechenzeit oder verwendeter Speicherplatz.
• Erfüllt mein Algorithmus seine Spezifikation? Korrektheit.
Der Nachweis der Korrektheit wird Verifikation genannt.
• Wie werden Datentypen definiert? Abstrakte Datentypen.
ADT/Abstrakte Datentypen werden durch algebraische Methoden definiert.
1.1 Vom Algorithmus zum Programm
1-5
Grundlegende Aspekte der Algorithmenentwicklung
• Gibt es für das Problem einen Algorithmus? Berechenbarkeit/Entscheidbarkeit.
Zur Beantwortung dieser Frage wird eine formale Definition des
Algorithmenbegriffs benötigt. Beispiel: Turing-Maschine.
Alonzo Church stellte 1936 die folgende These auf, die bisher nicht widerlegt
wurde. Church’sche These:
Der intuitive Algorithmenbegriff wird durch
das Modell der Turing-Maschine adäquat definiert.
Die Church’sche These kann natürlich nicht bewiesen werden, da sie den intuitiven
Algorithmenbegriff verwendet. Über intuitive Dinge können keine formalen Beweise
geführt werden. Es wurde gezeigt, dass viele formale Algorithmusdefinitionen
äquivalent sind. Daher könnte in der Church’schen These die Turing-Maschine
durch etliche andere formale Definitionen des Algorithmus ersetzt werden.
1.1 Vom Algorithmus zum Programm
1-6
Grundlegende Aspekte der Algorithmenentwicklung
• Gibt es Vorgehensweisen für die Erstellung von Algorithmen?
Entwurf von Algorithmen.
Beispiele: Rekursion, Backtracking, Divide-and-Conquer, Greedy-Algorithmus, . . .
• Gibt es Algorithmen, die man häufig verwenden kann?
Standardalgorithmen.
Beispiele: Algorithmen zum Suchen und Sortieren, Algorithmen für konkrete
Datentypen (zum Beispiel: Graphen, Listen, Keller, Schlangen, . . . )
• Gibt es andere Definitionen des Algorithmenbegriffs?
Varianten des Algorithmenbegriffs.
Beispiele: nichtdeterministische, parallele, randomisierte Algorithmen.
1.1 Vom Algorithmus zum Programm
1-7
Paradigmen zur Formulierung von Algorithmen
In einem imperativen Algorithmus gibt es Variable, die verschiedene Werte annehmen
können. Die Menge aller Variablen und ihrer Werte sowie der Programmzähler
beschreiben den Zustand zu einem bestimmten Zeitpunkt. Ein Algorithmus bewirkt
eine Zustandstransformation.
Ein funktionaler Algorithmus formuliert die Berechnung durch Funktionen. Die
Funktionen können rekursiv sein; auch gibt es Funktionen höherer Ordnung.
In einem objektorientierten Algorithmus werden Datenstrukturen und
Methoden/Funktionen zu einer Klasse zusammengefasst. Von jeder Klasse können
Objekte gemäß der Datenstruktur erstellt und über die Methoden manipuliert werden.
Ein logischer (deduktiver) Algorithmus führt Berechnungen durch, indem er aus
Fakten und Regeln durch Ableitungen in einem logischem Kalkül Ziele beweist.
Unter einem hybriden Paradigma versteht man die Mischung von Paradigmen.
1.1 Vom Algorithmus zum Programm
1-8
Paradigmen zur Formulierung von Algorithmen
Aus einer übergeordneten Sichtweise werden die folgenden Kategorien unterschieden:
• Prozedurale Programmiersprachen: Es wird exakt angegeben, wie die Lösung eines
Problems ermittelt werden kann. Imperative Programmiersprachen fallen in diese
Kategorie.
• Deklarative Programmiersprachen: Im Gegensatz zum prozeduralen Paradigma
fragt man in der deklarativen Programmierung danach, was berechnet werden soll.
Es wird also nicht der Lösungsweg programmiert, sondern angegeben, welches
Ergebnis gewünscht ist. Deklarative Paradigmen beruhen auf mathematischen,
rechnerunabhängigen Theorien. Beispiele hierfür sind prädikative und – bis zu
einem gewissen Grade – auch funktionale Programmiersprachen.
1.1 Vom Algorithmus zum Programm
1-9
Beispiel: Algorithmus von Euklid
Der folgende, in einer imperativen Programmiersprache formulierte,
Algorithmus von Euklid (ca. 300 v. Chr.)
berechnet den größten gemeinsamen Teiler der Zahlen x , y ∈ N mit x > 0 und y ≥ 0:
a := x;
b := y;
while b
do r :=
a :=
b :=
od
# 0
a mod b;
b;
r
Anschließend gilt a = ggT(x , y ).
1.1 Vom Algorithmus zum Programm
1-10
Beispiel: Algorithmus von Euklid
Variable
r
a
b
z0
–
–
–
z1
–
36
–
z2
–
36
52
z5
36
52
36
z8
16
36
16
z11
4
16
4
z14
0
4
0
ggT(36, 52) = 4
Durchlaufene Zustände:
z0, z1, z2, ... , z14
Zustandstransformation:
z0 7−→ z14
1.1 Vom Algorithmus zum Programm
1-11
Datenstrukturen und Typsysteme
Programmiersprachen bieten die Möglichkeit, aus elementaren Datenbereichen mithilfe
von Konstruktoren komplexe Datenbereiche aufzubauen. Datenbereiche werden häufig
Datenstrukturen genannt. Die Aspekte, die die Datenbereiche betreffen, werden als
Typsystem bezeichnet. Nicht alle Programmiersprachen bieten alles hiervon an.
• Elementare Datenstrukturen:
◦ Wertebereiche, Operationen
◦ boolean, char, cardinal, integer, real, enumeration
• Konstruktoren:
◦ array (Feld), record (Satz), set (Menge), pointer (Zeiger)
◦ Zeiger ermöglichen rekursive Datenstrukturen wie Listen, Bäume und Graphen.
• Typäquivalenz, Typanpassung, Typkompabilität, . . .
1.1 Vom Algorithmus zum Programm
1-12
Natürliche und künstliche Sprachen
• Sprache ist ein sich stets weiterentwickelndes, komplexes System von Lauten und
Zeichen zum Zwecke der Kommunikation. Es werden natürliche und künstliche
Sprachen unterschieden.
• Natürliche Sprachen sind historisch gewachsen. Hierzu zählen z. B. Deutsch,
Englisch und Französisch. Sie sind Ausdruck menschlichen Denkens, Fühlens und
Wollens und weisen im Unterschied zu künstlichen Sprachen Mehrdeutigkeiten auf.
• Künstliche Sprachen sind Zeichensysteme, die der Verständigung in einem eng
begrenzten Fachgebiets dienen, zum Beispiel Programmiersprachen. Sprachen wie
Esperanto sind ebenfalls künstliche Sprachen, die sich durch leichtere Schreibung
und Grammatik gegenüber natürlichen Sprachen auszeichnen.
aus Basiswissen Deutsch, Dudenverlag
1.1 Vom Algorithmus zum Programm
1-13
Sprachklassen der Informatik
Die Sprachen der Informatik werden typischerweise in zwei Klassen aufgeteilt:
• General Purpose Language (GPL)
• Domain Specific Language (DSL)
Meistens zählt man die Programmiersprachen zu den GPLs und Sprachen für spezielle
Anwendungen zu den DSLs.
Die Klasseneinteilung ist nicht in allen Quellen genau identisch. Eine mögliche
Beispiel-Einteilung finden Sie in einem Material der Veranstaltung.
1.1 Vom Algorithmus zum Programm
1-14
Sprachen der Informatik
Um Objekte mit Rechensystemen zu behandeln, müssen sie in eindeutigen – also
künstlichen – Sprachen beschrieben werden. Einige Beispiele sollen dies verdeutlichen:
• Algorithmen: Programmiersprachen (Java)
• Dokumente: Markup-Sprachen (Html, XML), Seitenbeschreibungssprachen
(Postscript)
• Modelle, Systeme: Modellierungssprachen (UML)
• Spezifikationen: Spezifikationssprachen (Z, VDM-SL)
• Datenbanken: Anfragesprachen (SQL)
1.1 Vom Algorithmus zum Programm
1-15
Folgerung
• In der Informatik hat man es mit einer Vielzahl von künstlichen Sprachen zu tun.
• Sie alle beschreiben Sachverhalte in einem relativ kleinen Kontext,
• dafür aber (hoffentlich) präzise, widerspruchsfrei und vollständig.
In dieser Vorlesung betrachten wir die Programmiersprache Java.
In anderen Veranstaltungen (z. B. „Programmieren für Fortgeschrittene“,
„Logik in der Informatik“) lernen Sie weitere Sprach(klass)en kennen.
Die theoretische Grundlagen der Programmiersprachen lernen Sie
in der Veranstaltung „Semantik von Programmiersprachen“ kennen.
1.1 Vom Algorithmus zum Programm
1-16
Algorithmus und Programm:
Programmiersprachen
1.1
1.2
1.3
1.4
Vom Algorithmus zum Programm
Programmiersprachen
Korrektheit, Komplexität und Entscheidbarkeit
Software-Grundlagen
1.2 Programmiersprachen
1-17
Entwicklung der Programmiersprachen
Edsger W. Dijkstra (niederländischer Informatiker, 1930–2002):
„Jeder Programmierer weiß, dass es nur eine einzig wahre Programmiersprache
gibt. Jede Woche eine neue.“
A. Weinert: Java für Ingenieure, 2001, Seite 7:
„Die Zahl der Programmiersprachen, die die Informatik in den letzten fünfzig
Jahren hervorgebracht hat, ist Legion. Ernst zu nehmende Schätzungen
sprechen von mehr als 20 000.“
Wenn Weinerts Schätzung zutrifft, sind es 7,7 Programmiersprachen pro Woche!
Zitat: Lisp ist nach Fortran die zweitälteste Sprache, die noch verbreitet ist.
1.2 Programmiersprachen
1-18
Entwicklung der Programmiersprachen
.
.
2000
C#
1995
JAVA
SCHEME (standard)
1990
OCCAM
C++
1985
CSP
ADA
1980
SMALLTALK80
MODULA−2
1975 C
• Algol68
• Modula-2
SCHEME
PASCAL
ALGOL68
LOGO
• Java/Scheme
BASIC
COBOL
ALGOL
FORTRAN
• Modula-2/Scheme
SIMULA
1965 PL/I
1955
• Algol
PROLOG
1970
1960
Programmiersprachen in der
Informatikausbildung
LISP
• Java
.
1.2 Programmiersprachen
1-19
Definition von Programmiersprachen
Die Lexik einer Programmiersprache bestimmt die textuellen Grundbausteine der
Programme. Solche Bausteine sind z. B. Schlüsselwörter, Zeichen und Bezeichner.
Sie werden beispielsweise durch Aufzählung oder reguläre Ausdrücke angegeben.
Die Syntax einer Programmiersprache beschreibt, wie aus den Grundbausteinen
vollständige Programme gebildet werden können. In den meisten Fällen wird die
Syntax einer Programmiersprache durch eine kontextfreie Grammatik festgelegt.
Die Bedeutung der syntaktisch korrekten Programme ist durch die Semantik der
Sprache gegeben. Sie kann beispielsweise mithilfe von Zustandsfolgen (operationelle
Semantik) oder durch Funktionen, die den syntaktischen Einheiten zugeordnet sind
(denotationale Semantik), definiert werden. Es gibt auch weitere Möglichkeiten.
Beispiele: axiomatische Semantik, algebraische Semantik.
Die Pragmatik einer Programmiersprache untersucht ihre Anwendbarkeit und
Nützlichkeit. Sie gehört nicht zur Definition der Sprache.
1.2 Programmiersprachen
1-20
Definition von Programmiersprachen: Kleines Beispiel
Lexik:
Schlüsselwörter: while, do, od, . . .
Zeichen: +, ;, :=, (, ), {, }, . . .
Bezeichner = Buchstabe · { Buchstabe, Ziffer }∗
Syntax:
<Anweisungsfolge>
<Anweisung>
<Zuweisung>
<While-Anweisung>
::=
::=
::=
::=
<Anweisung> ; <Anweisungsfolge> | <Anweisung>
<Zuweisung> | <While-Anweisung> | . . .
<Bezeichner> := <arithmetischer Ausdruck>
while <logischer Ausdruck> do <Anweisungsfolge> od
(Operationelle) Semantik:
Eine (partielle) Funktion f, die Zustände auf Zustände abbildet.
Ein Beispiel: f(z0) = z14 (s. Abschnitt 1.1)
1.2 Programmiersprachen
1-21
Klassifikation der Programmiersprachen
Die Programmiersprachen lassen sich grob in drei Klassen einteilen:
• Maschinensprachen
Bits und Bytes, für den menschlichen Leser kaum verständlich
• Maschinenorientierte Sprachen (Assembler)
stellen die Befehle in einem Mnemo-Code dar
ADDIC 23, R0
STO R0, #12004
• Problemorientierte Sprachen
imperative, funktionale, objektorientierte, deduktive Sprachen, Spezialsprachen
Ein Computer versteht nur Maschinensprachen!
1.2 Programmiersprachen
1-22
Implementierung von Programmiersprachen
Compiler übersetzen Quellprogramme aus problemorientierten Sprachen in äquivalente
Zielprogramme in Maschinensprachen:
cc -o prog prog.c
prog input output
Interpreter lesen das Programm ein und führen es aus. Die Eingabe kann während der
Ausführung oder durch eine Datei erfolgen.
scm prog.scm input output
Mischverfahren übersetzen das Programm zunächst mit einem Compiler in eine
Zwischensprache. Das übersetzte Programm wird anschließend interpretiert:
javac prog.java
java prog
Die Eingabe kann zum Beispiel über die Tastatur oder Dateien erfolgen.
Die Ausgabe kann zum Beispiel auf dem Bildschirm oder in Dateien geschehen.
1.2 Programmiersprachen
1-23
Implementierung von Programmiersprachen
Interpreter müssen das Programm bei jedem Lauf erneut analysieren. Dies bedeutet
einen gewissen Effizienzverlust.
Typisch, aber nicht zwingend:
• Compiler: C
• Interpreter: Scheme
• Mischverfahren: Java
• Compiler und Interpreter: Haskell
Compiler1 6= Compiler2
1.2 Programmiersprachen
Interpreter1 6= Interpreter2
1-24
Verarbeitung von Java-Programmen
• Zuerst wird ein Quellprogramm vom
Compiler in Bytecode übersetzt.
Java−Quellprogramm
javac
Java−Bytecode
java
VM für Windows
1.2 Programmiersprachen
java
VM für Linux
• Im zweiten Schritt wird der Bytecode
vom Interpreter ausgeführt. Der
Bytecode kann als Maschinencode der
sogenannten virtuellen Java-Maschine
(JVM) angesehen werden. Bytecode ist
portabel.
• Der Compiler ist maschinenunabhängig,
der Interpreter muss für jede Plattform
neu entwickelt werden.
1-25
Verarbeitung von Java-Programmen
• Interpretierter Code ist langsamer in der Ausführung als kompilierter Code, selbst
wenn dieser als Bytecode vorliegt.
• Prinzipiell könnten Java-Programme auch in Maschinensprachen übersetzt werden.
Dann könnte die Portierbarkeit verloren gehen.
• Eine Alternativlösung bieten Just-in-Time-Compiler (JIT). Ein JIT ist ein
Programm, das den Bytecode einzelner Methoden während der Ausführung in
Maschinencode der jeweiligen Plattform übersetzt. So kann die Methode beim
nächsten Aufruf deutlich schneller ausgeführt werden. Vorteilhaft ist, dass der
Bytecode nicht verändert wird und damit das übersetzte Programm portabel bleibt.
1.2 Programmiersprachen
1-26
Implementierung von Programmen
Warum muss man wissen, wie Programme umgesetzt werden?
Beispiel:
Java-Programm:
public static void main(String[] args) {
int z = 256*256*256*128+2147483647;
System.out.println(z*z);
}
Ausgabe:
1
Der korrekte Wert ist 4294967295.
Warum ist die Ausgabe 1?
1.2 Programmiersprachen
Kann ein Computer nicht rechnen?
1-27
Paradigmen und Programmiersprachen
Einige Programmiersprachen:
imperativ:
funktional:
prädikativ:
objektorientiert:
hybrid:
Algol, Algol68, Pascal, Ada, C, . . .
Lisp, Scheme, ML, Haskell, . . .
Prolog
Smalltalk, Eiffel, . . .
Java, C++, C# (imperativ, oo),
Scala (imperativ, oo, funktional), . . .
In der Regel lassen sich die Sprachen nicht eindeutig einem bestimmten Paradigma
zuordnen. Zum Beispiel gibt es in Scheme Variable und Zuweisungen, d. h. imperative
Konzepte. Java ist als „imperativ-basierte objektorientierte Programmiersprache“
(hybrides Paradigma) zu bezeichnen. C++ hingegen besitzt einen vollständigen
imperativen Kern, während Smalltalk eine strikt objektorientierte Programmiersprache
ist.
1.2 Programmiersprachen
1-28
Skriptsprachen
• Bei Skriptsprachen handelt es sich um übergeordnete Sprachen, um vorhandene
Programme oder Prozeduren kontrolliert ablaufen zu lassen.
• Skriptsprachen haben ihren Ursprung in den Kommandosprachen (Job Control
Language, JCL) von Betriebssystemen.
• Einfache Skriptsprachen sind die Shell-Skripts von Unix. Mächtigere Skriptsprachen
sind beispielsweise Perl, PHP, Python oder JavaScript.
• Skriptsprachen werden in der Regel interpretiert, nicht kompiliert.
1.2 Programmiersprachen
1-29
Dieses sind Versionen von Java
1992–1995
Januar 1996
Anfang 1997
Dezember 1998
Januar 1999
Mai 2000
Februar 2002
Ende 2004
Dezember 2006
Juli 2011
März 2014
Juli 2017 ???
Java-Vorläufer, zuerst unter dem Namen „Oak“.
Oak: Object Application Kernel, Eiche.
Neu: Applets (little applications)
JDK 1.0 (Java Development Kit)
JDK 1.1
JDK 1.2, wurde
umbenannt in „Java 2 Plattform“
Java 2, JDK 1.3
Java 2, JDK 1.4
Java 2, JDK 5.0 (interne Versionsnummer: 1.5.0) „Tiger“
Java Standard Edition 6 „Mustang“
Java Standard Edition 7 „Dolphin“
Java Standard Edition 8
Java Standard Edition 9
Sprachen haben Versionen.
1.2 Programmiersprachen
1-30
Java-Versionen
Die installierte Version kann mit java -version ermittelt werden.
Bitte checken Sie Ihre Java-Version.
Achten Sie also darauf, dass Ihre Programme der Hausaufgaben auf Ihrem Computer
und auf dem von Ihnen benutzten TU-Computer ausgeführt werden können.
1.2 Programmiersprachen
1-31
Java-Beispiel
Dieses ist ein Beispiel für die Version Java 8.
Java 8 macht Schritte in die Richtung Funktionalität:
@FunctionalInterface
interface Funktion {
int rechnen (int x, int y);
}
Diese Prinzipien werden wir uns natürlich genauer anschauen.
1.2 Programmiersprachen
1-32
public class Test {
public static void main(String[] args) {
Funktion f = (a,b) -> a+b;
Funktion g = (a,b) -> a-b;
Funktion h = (a,b) -> a*b;
Funktion l = (a,b) -> a/b;
int a = 100;
int b = 25;
int w = f.rechnen(a,b);
int x = g.rechnen(a,b);
int y = h.rechnen(a,b);
int z = l.rechnen(a,b);
System.out.printf("%d + %d = %4d%n",a,b,w);
System.out.printf("%d - %d = %4d%n",a,b,x);
System.out.printf("%d * %d = %4d%n",a,b,y);
System.out.printf("%d / %d = %4d%n",a,b,z);
}
}
1.2 Programmiersprachen
1-33
Übersetzung, Ausführung und Ausgabe:
javac Test.java
java -ea Test
100
100
100
100
+
*
/
1.2 Programmiersprachen
25
25
25
25
= 125
=
75
= 2500
=
4
1-34
Algorithmus und Programm:
Korrektheit, Komplexität und Entscheidbarkeit
1.1
1.2
1.3
1.4
Vom Algorithmus zum Programm
Programmiersprachen
Korrektheit, Komplexität und Entscheidbarkeit
Software-Grundlagen
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-35
Spezifikation, Korrektheit und Verifikation
Die Spezifikation beschreibt die Anforderungen an ein Softwaresystem in einer
informellen, grafischen und/oder formalen Sprache. Eine Spezifikation sollte
vollständig und widerspruchsfrei sein.
Ein Softwaresystem, das eine Spezifikation erfüllt, heißt korrekt bezüglich dieser
Spezifikation. Man unterscheidet dabei zwischen partieller und totaler Korrektheit. Ein
Programm nennt man partiell korrekt, wenn die Spezifikation erfüllt, die Terminierung
von Programmläufen aber nicht notwendigerweise gewährleistet ist. Es heißt total
korrekt, wenn zusätzlich die Terminierung sichergestellt ist. Ein partiell korrektes
Programm liefert also keine falschen Ergebnisse.
Unter Verifikation versteht man den mathematischen Beweis der partiellen oder
totalen Korrektheit eines Programms.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-36
Korrektheit des Algorithmus von Euklid
Die Spezifikation besteht aus einer Vorbedingung und einer Nachbedingung:
Vorbedingung:
Nachbedingung:
x > 0 und y ≥ 0
a = ggT(x , y )
Der Algorithmus von Euklid ist für Eingaben x und y mit x > 0 und y ≥ 0 partiell
und total korrekt. Die Variable a enthält nach Programmende den Wert des größten
gemeinsamen Teilers von x und y .
Mit der Definition ggT(0, 0) = 0 ist der Algorithmus von Euklid für alle Werte x und
y mit x ≥ 0 und y ≥ 0 partiell und total korrekt.
Beweis unter Verwendung einer Schleifeninvarianten: Sehen wir uns jetzt an.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-37
Test und Validierung
Der Test eines Programms ist der probeweise Ablauf des Programms. Damit der Test
aussagekräftig ist, müssen die Eingabedaten sorgfältig ausgewählt werden. Ein Test
kann nur die Anwesenheit von Fehlern, niemals aber deren Abwesenheit zeigen.
Als Validierung bezeichnet man den Test eines Softwaresystems unter Bedingungen,
wie sie im späteren Einsatz herrschen werden. Auch wenn das zu erstellende
Programm verifiziert wurde, kann auf eine Validierung nicht verzichtet werden, da ein
mathematischer Nachweis der Korrektheit beispielsweise nichts über das
Laufzeitverhalten des Programms oder die Auslastung von Leitungen aussagt.
Verifikation:
Validierung:
verus – wahr, facere – machen
validus – gesund, stark
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-38
Komplexität und O-Notation
• Unter Komplexität versteht man den Aufwand, den ein Algorithmus/Programm zur
Lösung einer Aufgabe benötigt. Damit ist in den meisten Fällen der erforderliche
Speicherplatz oder die Anzahl der durchgeführten Rechenschritte gemeint.
• Mathematisch wird die Komplexität eines Algorithmus/Programms in der Regel
durch eine Funktion f : N −→ R beschrieben. Die Größenordnung einer solchen
Funktion f wird häufig durch die sogenannte O-Notation nach oben abgeschätzt:
O(g) = {f : N −→ R | ∃c > 0, n0 > 0 ∀n ≥ n0. 0 ≤ f (n) ≤ cg(n)}
für eine Funktion g : N −→ R.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-39
Komplexität des Algorithmus von Euklid
Theorem. [G. Lamé, 1845] Es seien x , y und n mit x ≥ 0, y ≥ 0 und
0 ≤ x , y < n gegeben. Dann gilt: Der Algorithmus von Euklid benötigt höchstens
√ m
l
f (n) := logφ
5n −2
Divisionsschritte, wobei φ =
1
2
√ 1 + 5 ist.
Beispiel: ggt(36,52), n=53, f (n) = d9, 92288...e − 2 = 10 − 2 = 8.
Unter Verwendung der O-Notation erhalten wir: f (n) ∈ O(log(n)).
Man schreibt es auch in der Form: f (n) = O(log(n)).
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-40
Symbole zur Größenordnung von Funktionen
Es sei eine Funktion g : N −→ R gegeben.
O(g) = {f : N −→ R | ∃c > 0, n0 > 0 ∀n ≥ n0. 0 ≤ f (n) ≤ cg(n)}
Ω(g) = {f : N −→ R | ∃c > 0, n0 > 0 ∀n ≥ n0. 0 ≤ cg(n) ≤ f (n)}
Θ(g) = {f : N −→ R |
∃c1 > 0, c2 > 0, n0 > 0 ∀n ≥ n0. 0 ≤ c1g(n) ≤ f (n) ≤ c2g(n)}
o(g) = {f : N −→ R | ∀c > 0 ∃n0 > 0 ∀n ≥ n0. 0 ≤ f (n) < cg(n)}
ω(g) = {f : N −→ R | ∀c > 0 ∃n0 > 0 ∀n ≥ n0. 0 ≤ cg(n) < f (n)}
Diese Zeichen werden Landau-Symbole genannt. Sie beschreiben das asymptotische
Verhalten von Funktionen. Eine Übersicht finden Sie auf der Web-Seite dieser
Vorlesung. Dieses Thema wird in den Veranstaltungen Algorithmen und
Datenstrukturen und Diskrete Mathematik behandelt.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-41
Symbole zur Größenordnung von Funktionen
• 3000n2 + 7n + 23 ∈ Θ(n2)
Man schreibt meistens: 3000n2 + 7n + 23 = Θ(n2)
• 3000n2 + 7n + 23 ∈ O(n2)
• 3000n2 + 7n + 23 ∈ Ω(n2)
• 23 ∈ Θ(1)
• an x n + ... + a1x + a0 ∈ Θ(x n )
• Θ(logk (n)) = Θ(logl (n))
• 6n log2(n) + 8n + 12 ∈ Θ(n log(n))
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-42
Entscheidbarkeit
• Entscheidbarkeit von Problemen: Gibt es zu jedem Problem einen Algorithmus,
der es löst?
• Immer wieder kommt es vor, dass ein Computerprogramm plötzlich keine Reaktion
mehr zeigt („abstürzt“ oder „sich aufhängt“). Dahinter verbirgt sich häufig ein
Algorithmus, der für eine spezielle Eingabe nicht terminiert. Für kommerzielle
Software kann das sehr teuer werden.
• Die Suche nach dem Grund der Nichtterminierung kann sich sehr schwierig
gestalten. Daher liegt der Wunsch nahe, einen Algorithmus zu entwickeln, der
beliebige Algorithmen auf Terminierung testet. Diese Aufgabenstellung heißt
Halteproblem.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-43
Halteproblem 1
Das Halteproblem ist unentscheidbar. Wir zeigen die Aussage indirekt:
• Annahme: Es gibt einen Algorithmus
HALT(algorithmus a, eingabe e),
der für einen Algorithmus a und eine Eingabe e genau dann das Ergebnis true
liefert, wenn a bei Eingabe von e terminiert.
• Der Algorithmus TEST(algorithmus a) sei definiert durch
TEST(algorithmus a): while HALT(a,a) { ... }.
Das heißt, TEST(a) terminiert genau dann nicht, falls a bei Eingabe von a
terminiert.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-44
Halteproblem 2
Zwei Fälle können eintreten:
• 1. Fall: Der Aufruf HALT(TEST, TEST) liefert true.
In diesem Fall terminiert nach Definition von HALT der Aufruf TEST(TEST).
Hieraus folgt aus der Definition von TEST, dass der Aufruf TEST(TEST) nicht
terminiert, ein Widerspruch.
• 2. Fall: Der Aufruf HALT(TEST, TEST) liefert false.
In diesem Fall terminiert nach Definition von HALT der Aufruf TEST(TEST) nicht.
Hieraus folgt aus der Definition von TEST, dass der Aufruf TEST(TEST)
terminiert, ein Widerspruch.
Da in beiden Fällen ein Widerspruch auftritt, kann der Algorithmus HALT nicht
existieren.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-45
Halteproblem 3
Die beiden vorherigen Seiten
• Halteproblem 1 und
• Halteproblem 2
wurden dem Schulbuch
Peter Hubwieser, Patrick Löffler et al.: Informatik 5 – Lehrwerk für Gymnasien.
Ernst Klett Verlag, Stuttgart, Leipzig, 2010.
entnommen.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-46
Berechenbarkeit 1
• Eine Funktion f : A → Y heißt berechenbar, wenn es einen Algorithmus Af gibt,
der diese Funktion „realisiert“.
• Die Quadratfunktion f : N → N ist berechenbar, denn es gibt einen Algorithmus,
der für jede gegebene natürliche Zahl n das Quadrat n2 berechnet.
Ist es wirklich möglich, ganz lange Zahlen mit dem Computer zu bearbeiten?
• Es gibt überabzählbar viele Funktionen f : N → N, aber nur abzählbar viele
Algorithmen. Das heißt, fast keine Funktion ist berechenbar.
Wir werden den Satz von Rice kennenlernen.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-47
Berechenbarkeit 2
• Mithilfe des Berechenbarkeitsbegriffs lässt sich die Entscheidbarkeit formal
definieren: Eine Menge M ⊂ X heißt entscheidbar relativ zu X , wenn die
charakteristische Funktion
(
1, x ∈ M,
χM (x ) =
0, x ∈ X \ M,
berechenbar ist.
• Formulieren Sie das Halteproblem als charakteristische Funktion einer geeigneten
Menge.
Fazit: Es gibt unentscheidbare Probleme und nicht berechenbare Funktionen.
Mehr zu diesem Thema lernen Sie in den Modulen Theoretische Informatik.
1.3 Korrektheit, Komplexität und Entscheidbarkeit
1-48
Algorithmus und Programm:
Software-Grundlagen
1.1
1.2
1.3
1.4
Vom Algorithmus zum Programm
Programmiersprachen
Korrektheit, Komplexität und Entscheidbarkeit
Software-Grundlagen
1.4 Software-Grundlagen
1-49
Hardware
Für unsere Zwecke reicht das folgende einfache Modell vom Aufbau eines Rechners.
Details lernen Sie in den Modulen Technische Informatik, „Rechnernetze, ... kennen:
Zentraleinheit
Prozessor
Eingabewerk
Eingabegeräte
1.4 Software-Grundlagen
Hauptspeicher
Massenspeicher
Ausgabewerk
Ausgabegeräte
1-50
Software
• Zur Systemsoftware zählen alle Programme, die für den korrekten Ablauf von
Rechnern oder Rechnernetzen erforderlich sind.
• Die Anwendungssoftware wird zur Lösung von Problemen, die nicht ursächlich mit
Rechnern zu tun haben, eingesetzt.
• Softwarewerkzeuge unterstützen die Erstellung von System- und
Anwendungsprogrammen.
1.4 Software-Grundlagen
1-51
Systemsoftware
Zur Systemsoftware zählen alle Programme, die für den korrekten Ablauf von
Rechnern oder Rechnernetzen erforderlich sind:
• Betriebssysteme und ihre Komponenten
• Compiler, Interpreter
• Binder, Lader bzw. Bindelader
• Programme zur Verwaltung von Geräten
• Netzsoftware
• ...
1.4 Software-Grundlagen
1-52
Anwendungssoftware
Die Anwendungssoftware wird zur Lösung von Problemen, die nicht ursächlich mit
Rechnern zu tun haben, eingesetzt:
• Datenbankprogramme
• Conputeralgebrasysteme
• Office-Software: Textverarbeitung, Tabellenkalkulation, Präsentation, . . .
• E-Mail-Programme
• Internetsoftware: Browser, . . .
• Mediensoftware: Grafik-, Photo-, Audio-, Videoprogramme, . . .
• ...
1.4 Software-Grundlagen
1-53
Softwarewerkzeuge
Softwarewerkzeuge unterstützen die Erstellung von System- und
Anwendungsprogrammen:
• Modellbildung
• Programmierwerkzeuge
• Versionskontrolle
• Integrierte Entwicklungsumgebungen
• ...
1.4 Software-Grundlagen
1-54
Betriebssysteme
• Der Begriff Betriebssystem ist eine zusammenfassende Bezeichnung für alle
Programme, die die Ausführung der Benutzerprogramme, die Verteilung der
Betriebsmittel auf die einzelnen Benutzerprogramme und die Aufrechterhaltung der
Betriebsart (z. B. Stapelbetrieb, Dialogbetrieb) steuern und überwachen.
• Das Betriebssystem bietet seine Dienste dem Benutzer in einer textuellen oder
grafischen Oberfläche an.
1.4 Software-Grundlagen
1-55
Betriebssysteme
• Das Betriebssystem kann als eine Erweiterung der Maschine gesehen werden. Der
durchschnittliche Programmierer möchte in der Regel beispielsweise nicht die
Verwaltung einer Floppy-Disk programmieren, sondern deren Funktionalität als
Abstraktion auf hohem Niveau nutzen. In diesem Zusammenhang spricht man auch
von einer virtuellen Maschine.
• Das Betriebssystem arbeitet auch als Ressourcenmanager. Moderne Rechensysteme
bestehen aus Prozessoren, Speichern, Uhren, Platten, Terminals, Druckern,
Netzwerkschnittstellen und vielen weiteren Komponenten. Das Betriebssystem teilt
diese Ressourcen untern den verschiedenen Prozessen auf. Dieser Vorgang kann als
„Multiplexen in Zeit und Raum“ beschrieben werden.
1.4 Software-Grundlagen
1-56
Wichtige Betriebssysteme
• UNIX-Derivate
◦ BSD-Unix (Berkeley Software Distribution)
◦ AT&T, System V
◦ Linux (Linus Torvalds)
Distributionen für Linux: RedHat, Suse, Debian, Ubuntu, Knoppix, . . .
• Betriebssysteme der Fa. Microsoft
◦
◦
◦
◦
MS-DOS
Windows 3.x/95/98/Me
Windows NT, Windows 2000, Windows XP
Windows Vista, Windows 7, 8, 10
1.4 Software-Grundlagen
1-57
Oberflächen von Betriebssystemen
• Ein heutiges Betriebssystem stellt dem Benutzer die Fähigkeiten des Rechners über
eine textuelle Oberfläche (Shell) und/oder über eine grafische Oberfläche (GUI,
Graphical User Interface) zur Verfügung.
• Beispielsweise gibt es für Unix üblicherweise die Shells sh, bash, csh, tcsh, ksh und
einige weitere. Für Linux wurden die grafischen Oberflächen KDE und Gnome
entwickelt. Die Wahl der jeweiligen Oberfläche bleibt dem Benutzer überlassen.
1.4 Software-Grundlagen
1-58
Dateiverwaltung
Dateiverwaltungssystem
Komponente eines Betriebssystems, die den gesamten Platz auf externen Speichern
verwaltet. Zu den Aufgaben gehören die Lokalisierung von Dateien, die Zuweisung von
Speicherplatz und die Buchführung über die Verwendung des Speichers.
Editor
Komponente eines Dateiverwaltungssystems zum Bearbeiten von Texten oder Daten.
Verbreitete Editoren unter Unix sind vi, emacs, nedit und gedit. Notepad und
Wordpad sind solche für Windows.
1.4 Software-Grundlagen
1-59
Programmierwerkzeuge
• Änderungsverwaltung: diff, patch
• Versionsverwaltungsprogramme: rcs, cvs, svn
• Eingabeanalyse: lex, yacc
• Eingabeverarbeitung: awk
• Programmgenerierung: make
• ...
1.4 Software-Grundlagen
1-60
Programmierumgebungen
Programmierumgebungen sind Software-Systeme zur Unterstützung der
Programmentwicklung. Typische Bestandteile einer Programmierumgebung sind
• ein sprachspezifischer Editor (Texteditor),
• Compiler und/oder Interpreter,
• Binder, Lader bzw. Bindelader,
• Test- und Debughilfen,
• Quelltextformatierungstools,
• Archivierungswerkzeuge sowie
• Dokumentationsgeneratoren.
1.4 Software-Grundlagen
1-61
Integrierte Entwicklungsumgebungen
Eine Programmierumgebung wird auch integrierte Entwicklungsumgebung (IDE)
(integrated development environment) genannt. Integrierte Entwicklungsumgebungen
für Java sind beispielsweise
• NetBeans,
• Eclipse,
• IntelliJ IDEA,
• Borland JBuilder und
• Oracle JDeveloper.
Integrierte Entwicklungsumgebungen können ggf. auch für die Arbeit mit mehreren
Programmiersprachen geeignet sein.
1.4 Software-Grundlagen
1-62
Herunterladen