%%===================================================================================== %% FILE: programmierung-uebungen.tex %% AUTHOR: Dr.-Ing. Fritz Mehner %% EMAIL: mehner@fh-swf.de %% VERSION: 1.1 %% REVISION: 02.12.2002 %% CREATED: 01.08.2002 %%===================================================================================== %%%%%%%%%%%%%%%%%%%%%% LATEX-Vorspann %%%%%%%%%%%%%%%%%%%%%% \documentclass[oneside,10pt,a4paper]{book} \newcommand{\Seitenformat}{1} %%\documentclass[doubleside,10pt,a4paper]{book} %%\newcommand{\Seitenformat}{2} \usepackage{gastex} \usepackage{german} \usepackage[T1]{fontenc} \usepackage[latin1]{inputenc} \usepackage{makeidx} \makeindex \usepackage{geometry} \geometry{verbose,a4paper,tmargin=20mm,bmargin=15mm,lmargin=20mm,rmargin=20mm} \setlength\parskip{\medskipamount} \setlength\parindent{0pt} \usepackage{listings} \usepackage{graphicx} \usepackage{floatflt} \usepackage{amsmath} \usepackage[hang]{subfigure} \usepackage{setspace} \usepackage{ifthen} \usepackage[usenames]{color} \usepackage{fancyhdr} \usepackage{pstricks} %\usepackage[ps2pdf]{hyperref} \newcommand{\DokumentAusgabestand}{02.12.2002} %%%%%%%%%%%%%%%%%%%%%% LATEX-Dokument %%%%%%%%%%%%%%%%%%%%%% \begin{document} %%---------------------------------------------------------------------- %% Abschnittsüberschriften umbenennen %%---------------------------------------------------------------------- \renewcommand{\chaptername}{Übung} \renewcommand{\indexname}{Stichwortverzeichnis} %%---------------------------------------------------------------------- %% Einstellungen für fancyhdr %%---------------------------------------------------------------------- \pagestyle{fancyplain} %% fancyplain erzeugt Kopf- und Fußeinträge %% auf auf den Seiten mit Kapitelanfängen \fancyhf{} \fancyfoot[c]{\thepage} \ifthenelse{\Seitenformat = 1 } { %% ----- einseitig ------------------------------------- \fancyhead[RE,RO]{\leftmark} \fancyfoot[RO,RE]{\scriptsize Praktikum Programmierung} \fancyfoot[LE,LO]{\scriptsize Stand \DokumentAusgabestand} } { %% ----- doppelseitig ------------------------------------- %%\fancyhead[RE,LO]{\leftmark} \fancyhead[LO]{\rightmark} \fancyhead[RE]{\leftmark} \fancyfoot[RO,LE]{\scriptsize Praktikum Programmierung} \fancyfoot[RE,LO]{\scriptsize Stand \DokumentAusgabestand} } %%---------------------------------------------------------------------- %% Einstellungen für das Paket listings %%---------------------------------------------------------------------- \lstset{basicstyle={\ttfamily,\footnotesize},tabsize=2,frame=single} \lstset{extendedchars=true,numbers=left,stepnumber=5,numberstyle=\tiny} \lstset{framesep=2mm} \lstset{linewidth=166mm} \lstset{xleftmargin=6mm} \lstset{identifierstyle=\ttfamily,keywordstyle=\bfseries} \lstset{commentstyle=\normalfont} \lstset{showstringspaces=false} \lstdefinestyle{ANSI}{language=C} \lstdefinestyle{C++}{alsolanguage=C++} \renewcommand\lstlistlistingname{Programmlisten} \renewcommand\lstlistingname{Liste} %%---------------------------------------------------------------------- %% Titelblatt - Vorderseite %%---------------------------------------------------------------------- %\title{\textbf{\textsc{\Huge Praktikum Programmierung}}} \title{ \begin{onehalfspace} \textbf{\textsc{ \Huge{Praktikum}\\ \large{zu den Veranstaltungen}\\ \Huge{Programmierung I}\\ \Huge{Programmierung II}\\ }} \end{onehalfspace} } \author{\textbf{\textsc{Prof. Dr.-Ing. Fritz Mehner }}\\ \\ Fachhochschule Südwestfalen\\ Fachbereich Informatik und Naturwissenschaften} \date{Stand \DokumentAusgabestand} \maketitle %%---------------------------------------------------------------------- %% Titelblatt - Rückseite %%---------------------------------------------------------------------- \newpage \begin{quote} \textbf{\textsc{Prof. Dr.-Ing. Fritz Mehner}}\\ Fachhochschule Südwestfalen\\ Fachbereich Informatik und Naturwissenschaften\\ Frauenstuhlweg 31\\ 58644 Iserlohn\\ \\ Tel. 02371-566-201\\ Email: mehner@fh-swf.de\\ Raum: Z-127\\ \end{quote} %%---------------------------------------------------------------------- %% Buchvorspann %%---------------------------------------------------------------------- \frontmatter %%---------------------------------------------------------------------- %% Einführung %%---------------------------------------------------------------------- \chapter*{Einführung} \addcontentsline{toc}{chapter}{Einführung} Das vorliegende Dokument enthält die Übungen zu den Veranstaltungen \textbf{Programmierung 1} und \textbf{Programmierung 2} für die folgenden Studiengänge: \begin{doublespace} \begin{center} %%~~~~~ TABULAR : begin ~~~~~~~~~~ \begin{tabular}[]{|l|l|l|} \hline \textbf{Studiengang} & \textbf{Fachbereich} & \textbf{Semester} \\ \hline \hline Angewandte Informatik & Informatik und Naturwissenschaften & 1. und 2. Sem. \\ [0.0ex] \hline Physikalische Technik & Informatik und Naturwissenschaften & 1. und 2. Sem. \\ \hline Mechatronik & Maschinenbau & 3. und 4. Sem. \\ \hline \end{tabular} \\ [0.0ex] %%~~~~~ TABULAR : end ~~~~~~~~~~ \end{center} \end{doublespace} \vspace{ 10mm} Die Durchführung der Aufgaben gibt Gelegenheit, das in der Vorlesung Gehörte anzuwenden und zu vertiefen. Die Teilnahme am Praktikum und die Durchführung der Übungen sind Pflicht. Die selbständige und erfolgreiche Lösung der Aufgaben wird im Praktikum bescheinigt und ist eine Voraussetzung für die Teilnahme an der Klausur. Programmieren kann man nur lernen indem man programmiert. Wenn keine Vorkenntnisse vorhanden sind, können die Anfänge durchaus mühevoll sein. Die alleinige Teilnahme am Praktikum, d.h. Programmieren am Rechner im Umfang von 2 Semesterwochenstunden, reicht \textit{keinesfall} zum Erwerb gefestigter Grundkenntnisse aus. \begin{quote} Es ist zwingend erforderlich auch außerhalb der Lehrveranstaltungen das in der Vorlesung erworbene Wissen praktisch nachzuvollziehen, anzuwenden und zu vertiefen. \end{quote} Dazu sollte auf dem eigenen Rechner eine entsprechende Entwicklungsumgebung zur Verfügung stehen . Grundsätzlich ist jeder Compiler oder jede Entwicklungsumgebung geeignet, sofern die ANSI-C-Verträglichkeit gegeben ist. Aus Kostengründen bietet sich freie Software an (LINUX oder FreeBSD). Selbstverständlich können auch die Einrichtungen der Fachhochschule benutzt werden. %%---------------------------------------------------------------------- %% Zur Darstellung %%---------------------------------------------------------------------- \section*{Zur Darstellung} Programmcode, Programmausgaben, Programm- und Dateinamen, Schlüsselwörter von Programmiersprachen und Menüeinträge erscheinen in \texttt{Schreibmaschinenschrift mit fester Zeichenbreite}. In den gerahmten C-/C++-Listen werden für Code und Kommentar zur Verbesserung der Lesbarkeit unterschiedliche Schriftarten verwendet. Der Nachkommaanteil reeller Zahlen wird, entsprechend der Darstellung in den meisten Programmiersprachen, durch einen \textit{Dezimalpunkt} abgetrennt, also z.B. PI = 3.1415 . Dieses Dokument wurde mit \LaTeX\ erzeugt. %%---------------------------------------------------------------------- %% Inhaltsverzeichnis / weitere Verzeichnisse %%---------------------------------------------------------------------- \cleardoublepage \setcounter{tocdepth}{1} \addcontentsline{toc}{chapter}{Inhaltsverzeichnis} \tableofcontents{} %%\cleardoublepage %%\addcontentsline{toc}{chapter}{Abbildungsverzeichnis} %%\listoffigures %% %%\cleardoublepage %%\addcontentsline{toc}{chapter}{Tabellenverzeichnis} %%\listoftables %% %%\cleardoublepage %%\addcontentsline{toc}{chapter}{Programmlisten} %%\lstlistoflistings %%---------------------------------------------------------------------- %% Buchhauptteil %%---------------------------------------------------------------------- \mainmatter %%---------------------------------------------------------------------- %% ÜBUNG : Summation unendlicher Reihen %%---------------------------------------------------------------------- \chapter{Summation unendlicher Reihen} \index{Summation} \index{Reihe! unendliche} %%---------------------------------------------------------------------- %% Bildung endlicher Reihensummen %%---------------------------------------------------------------------- \section{Bildung endlicher Reihensummen} \index{Reihe! harmonische} \index{Reihe! harmonische!alternierend} \index{Reihe! leibnizsche} \index{Reihe! geometrische} \begin{align} H & =\; \; \sum _{i=1}^{\infty }\frac{1}{i} &&=\; \; \frac{1}{1}+\frac{1}{2}+\frac{1}{3}+\frac{1}{4}+\ldots \label{eq:HReihe} &&&\\ A & =\; \; \sum _{i=1}^{\infty }\frac{\left(-1\right)^{i+1}}{i} &&=\; \; \frac{1}{1}-\frac{1}{2}+\frac{1}{3}-\frac{1}{4}+\ldots \label{eq:AReihe} &&&\\ L & =\; \; \sum _{i=1}^{\infty }\frac{\left(-1\right)^{i+1}}{2i-1} &&=\; \; \frac{1}{1}-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+\ldots \label{eq:LReihe} &&&\\ G & =\; \; \sum _{i=0}^{\infty }\frac{1}{2^{i}} && =\; \; \frac{1}{1}+\frac{1}{2}+\frac{1}{4}+\frac{1}{8}+\ldots \label{eq:GReihe} &&& \end{align} \begin{table}[h] \begin{onehalfspace} \begin{center} \begin{tabular}{|c|c|c|} \hline \textbf{Gleichung}& \textbf{Name}& \textbf{Summe}\\ \hline \hline \ref{eq:HReihe}& harmonische Reihe& $\infty $\\ \hline \ref{eq:AReihe}& alternierende harmonische Reihe& $ln$ 2\\ \hline \ref{eq:LReihe}& Leibnizsche Reihe& $\pi $/4\\ \hline \ref{eq:GReihe}& Geometrische Reihe& 2\\ \hline \end{tabular} \end{center} \end{onehalfspace} \caption{\label{cap:Unendliche-Reihen}Unendliche Reihen} \end{table} Die Bildung einer Summe S aus n Summanden wird mit Hilfe einer Schleife durchgeführt. Bei jedem Schleifendurchlauf wird ein Summand $s_{i}$ zu der sich aufbauende Summe S addiert: \begin{eqnarray*} S & = & s_{1}+s_{2}+s_{3}+\ldots +s_{n}\\ & & \\ S & = & 0\\ S & = & S+s_{1}\\ S & = & S+s_{2}\\ & \ldots & \\ S & = & S+s_{n} \end{eqnarray*} Schreiben Sie ein C-Programm, in welchem für jede dieser Reihen die Summe der ersten 1000 Summanden gebildet und ausgegeben wird. %%---------------------------------------------------------------------- %% Wechselnde Vorzeichen %%---------------------------------------------------------------------- \subsection{Wechselnde Vorzeichen} \index{Vorzeichen!wechselndes} Wechselnde Vorzeichen (Reihe \ref{eq:AReihe} und \ref{eq:LReihe}) werden dadurch gebildet, daß man einer Hilfsvariablen v vor der Schleife den Wert +1 zuweist. Die Summanden werden in der Schleife mit der Vorzeichenvariablen v multipliziert. Danach wird mit der Zuweisung v = -v die Umkehr des Vorzeichens für den nächsten Durchlauf erzwungen. %%---------------------------------------------------------------------- %% Nichtlinear wachsende oder fallende Summanden %%---------------------------------------------------------------------- \subsection{Nichtlinear wachsende oder fallende Summanden} Die Summanden der Geometrischen Reihe können ohne Potenzierung berechnet werden. Der jeweils nächste Summand ergibt sich durch Multiplikation mit dem Faktor $1/2$ aus dem vorhergehenden. Wenn die Variable \texttt{summand} den Wert des Summanden aus dem letzten Schleifendurchlauf besitzt, dann kann durch \begin{verbatim} summand = 0.5*summand; \end{verbatim} der Wert für den aktuellen Schleifendurchlauf bestimmt werden. %%---------------------------------------------------------------------- %% Bildung ,,unendlicher'' Reihensummen %%---------------------------------------------------------------------- \section{Bildung ,,unendlicher'' Reihensummen} Die Bildung unendlicher Summen ist auf einem Digitalrechner natürlich nicht möglich. Wegen der begrenzten Genauigkeit der Zahlendarstellung und der Tatsache, daß die Summanden einer konvergierenden Reihe immer kleinere Beträge annehmen, verändert die Addition weiterer Summanden eine bereits berechnete Summe ab einem gewissen i nicht mehr ! Wenn die Summe aus dem letzten Rechenschritt als Vergleichswert zur Verfügung steht, kann dieser Umstand festgestellt und die Berechnung abgebrochen werden. Die bis dahin ermittelte Summe stellt die Näherungslösung dar. Erstellen Sie eine neue Version des Programmes aus dem ersten Teil, in welchem Sie dann alle Reihen solange aufsummieren, bis sich die jeweilige Summe nicht mehr ändert. Geben Sie die errechneten Summen aus und vergleichen Sie diese mit den theoretischen Grenzwerten aus Tabelle \ref{cap:Unendliche-Reihen}. %%---------------------------------------------------------------------- %% ÜBUNG : Verwendung von Schleifen %%---------------------------------------------------------------------- \chapter{Verwendung von Schleifen} \index{Schleifen} %%---------------------------------------------------------------------- %% ASCII-Tabelle %%---------------------------------------------------------------------- \section{ASCII-Tabelle} \index{ASCII-Tabelle} Schreiben Sie ein C-Programm, welches in 32 Zeilen eine 8-spaltige ASCII-Tabelle ausgibt, die jeweils den Zahlenwert eines Zeichens (3-stellig mit führenden Nullen) und das zugehörige abdruckbare Zeichen enthält. Für die nicht darstellbaren Steuerzeichen (0-31) sollen 3 Punkte ausgegeben werden. \lstset{language=C} \lstinputlisting[caption={Programmausgabe: ASCII-Tabelle},label=ascii-tabelle]{ ./programme/ascii.txt } %%---------------------------------------------------------------------- %% Teilsumme der harmonischen Reihe bei aufsteigender und absteigender Summation %%---------------------------------------------------------------------- \section{Teilsumme der harmonischen Reihe bei aufsteigender \\und absteigender Summation} \index{Reihe! harmonische} \index{Summation} Schreiben Sie ein Programm, in welchem die Glieder der harmonischen Reihe (Gleichung \ref{eq:HReihe}) beginnend mit 1/1 so lange aufsummiert werden, bis sich die Reihensumme nicht mehr ändert und geben Sie die Summe aus. Anschließend ist eine Schleife zu programmieren, die beginnend vom letzten Wert des Index der vorhergehenden Schleife die Reihensumme bildet und beim Summanden 1/1 endet. Diese Summe ist ebenfalls auszugeben. Geben Sie nun die Differenz der beiden Summen aus (Exponentenformat). Verwenden Sie den Datentyp \texttt{float} bei der Bildung der Summen. \begin{itemize} \item Wie oft werden die beiden Schleifen durchlaufen ? \item Was stellen Sie beim Vergleich der beiden Summen fest ? \end{itemize} %%---------------------------------------------------------------------- %% Rundungsfehler durch fortgesetzte Multiplikation und Division %%---------------------------------------------------------------------- \section{Rundungsfehler durch fortgesetzte Multiplikation und Division} \index{Rundungsfehler} Schreiben Sie ein Programm, in welchem die \texttt{float}-Zahl x = 1000000 in einer ersten Schleife 10-mal mit dem \texttt{float}-Faktor k = 0.1693 multipliziert wird. Das Ergebnis wird danach in einer zweiten Schleife 10-mal durch den selben Faktor k dividiert. Theoretisch müßte danach x wieder den Ausgangswert enthalten. Geben Sie den Ausgangswert und den Endwert von x mit jeweils 10 Nachkommastellen aus und vergleichen Sie die Werte. \begin{itemize} \item Was stellen Sie beim Vergleich der beiden Werte fest ? \end{itemize} %%---------------------------------------------------------------------- %% Steuerung einer for-Scheife %%---------------------------------------------------------------------- \section{Steuerung einer \texttt{for}-Scheife} %%----- FIGURE : begin ---------- \begin{figure}[htb] \begin{center} \includegraphics[scale=.5]{./bilder/parabel.eps} \caption{ \label{ABB:Parabel} Punktweise Berechnung einer Parabel } \vspace{ 5mm} \end{center} \end{figure} %%----- FIGURE : end ---------- Die Funktion $f(x)=x^{2}$ ist im Bereich von $x = 0\ldots30$ auszuwerten. Dazu wird das x-Intervall {[}0,30{]} in 250 Teilintervalle der Länge $\Delta x = 30/250 = 0.12$ eingeteilt und die Funktion an den 251 Teilungspunkten ausgewertet (Abb. \ref{ABB:Parabel}). Die Teilungspunkte $x_{i}$ und die dazugehörigen Funktionswerte $f(x_{i})$ sollen in einer \texttt{for}-Schleife berechnet werden. Dabei sollen 3 verschiedene Steuerungsmethoden ausprobiert werden: \begin{enumerate} \item Ganzzahliger Schleifenzähler \texttt{i} . Das laufende $x_{i}$ wird durch Multiplikation des Schleifenzählers mit der Intervalllänge ermittelt: $x_{i}=i*\Delta x$ .\\ Anmerkung: Der aktuelle Wert von $x_{i}$ hängt nur von einer Multiplikation ab. \item Ganzzahliger Schleifenzähler \texttt{i} . Das laufende $x_{i}$ wird durch fortlaufende Addition der Intervalllänge ermittelt: $x_{i}=x_{i-1}+\Delta x$ .\\ Anmerkung: Der aktuelle Wert von $x_{i}$ hängt von allen vorhergegangenen Additionen ab. \item Reeller Schleifenzähler \texttt{x} . Das laufende $x$ wird durch Hochzählen des Schleifenzählers \texttt{x} um die Intervalllängeermittelt: $x=x+\Delta x$ .\\ Anmerkung: Der aktuelle Wert von $x_{i}$ hängt von allen vorhergegangenen Additionen und von der Darstellungsgenauigkeit von $\Delta x$ ab. \end{enumerate} Schreiben Sie ein Programm, in welchem die 3 Schleifen durchlaufen werden. Der letzte in der Schleife berechnete x-Wert und der dazugehörige Funktionswert soll jeweils ausgegeben werden (15 Nachkommastellen; Datentyp \texttt{double}). \begin{itemize} \item Was stellen Sie beim Vergleich der Ausgabewerte fest ? \end{itemize} %%---------------------------------------------------------------------- %% ÜBUNG : Verwendung von Feldern %%---------------------------------------------------------------------- \chapter{Verwendung von Feldern} \index{Felder} %%---------------------------------------------------------------------- %% Feld mit Quadratzahlen belegen und ausgeben %%---------------------------------------------------------------------- \section{Feld mit Quadratzahlen belegen und ausgeben} Geben Sie das Beispielprogramm aus der Vorlesung ein, in welchem ein \texttt{int}-Feld (100 Elemente) mit den Quadratzahlen $0^{2},1^{2},2^{2},...,99^{2}$ belegt und der Feldinhalt anschließend ausgegeben wird. Verwenden Sie in der Ausgabeschleife (Schleifenzähler: i ) die Anweisung \begin{verbatim} if( i%10==0 ) printf("\n"); \end{verbatim} um nach jeweils 10 Werten einen Zeilenvorschub zu erzwingen. %%---------------------------------------------------------------------- %% Feld mit Zufallszahlen zwischen 0 und 50 belegen %%---------------------------------------------------------------------- \section[Feld mit Zufallszahlen zwischen 0 und 50 belegen]{Feld mit Zufallszahlen zwischen 0 und 50 belegen und Mittelwert, Minimalwert und Maximalwert aller Feldelemente ermitteln} \index{Mittelwert} \index{Minimalwert} \index{Maximalwert} Schreiben Sie ein Programm, in welchem ein \texttt{double}-Feld a (100 Elemente) mit Zufallszahlen zwischen 0 und 50 (jeweils einschließlich) belegt wird. Die Funktion \texttt{random()} , \texttt{include}-Datei \texttt{stdlib.h}, liefert Zufallszahlen im Bereich von 0 bis $2^{31}-1$. Durch die Bildung des Divisionsrestes mit 51 (Operator \% , modulo-Operator) können daraus Werte zwischen 0 und 50 erzeugt werden: \begin{verbatim} a[i] = random() % 51; \end{verbatim} \begin{itemize} \item Geben Sie das so belegte Feld mit 10 Werten pro Zeile aus. \item Bilden Sie das arithmetische Mittel aller Feldelemente und geben Sie diesen Wert aus. \item Ermitteln Sie den kleinsten Wert und den größten Wert der Feldelemente und geben Sie diese beiden Werte aus. \end{itemize} %%---------------------------------------------------------------------- %% Korrespondierende Felder %%---------------------------------------------------------------------- \section{Korrespondierende Felder} \index{Felder!korrespondierende} Schreiben Sie ein Programm, in welchem die \texttt{double}-Felder \texttt{x}, \texttt{y1} und \texttt{y2} mit jeweils 1000 Elementen angelegt werden. Die Funktionen $y_{1}(x)=\sin(x)$ und $y_{2}(x)=\cos(x)$ sind im Bereich von $x = 0 \ldots 6.4$ auszuwerten (\texttt{include}-Datei \texttt{math.h} ). Dazu wird das Intervall $\lbrack 0,6.4\rbrack$ in 100 Teilintervalle der Länge $\Delta x=6.4/100$ eingeteilt und die beiden Funktionen an den 101 Teilungspunkten ausgewertet (s.Aufgabe 2.4). Die $x$-Werte werden fortlaufen im Feld \texttt{x}, die Funktionswerte entsprechend in den Feldern \texttt{y1} und \texttt{y2} abgelegt. Nachdem die Felder belegt sind, sollen die Werte zeilenweise in der Form \begin{quote} \begin{verbatim} +0.000000 +0.000000 +1.000000 +0.064000 +0.127651 +0.981625 +0.128000 +0.253213 +0.927174 . . . \end{verbatim} \end{quote} ausgegeben werden. Von der Kommandozeile des Betriebssystems aus kann die Ausgabe des Programmes \texttt{kfeld.e} in die Datei \texttt{kfeld.dat} umgeleitet werden: \begin{quote} \begin{verbatim} student@rechner5:/home/student> kfeld.e > kfeld.dat \end{verbatim} \end{quote} %%---------------------------------------------------------------------- %% Erzeugung einer Graphik mit Hilfe des Programmes gnuplot %%---------------------------------------------------------------------- \section{Erzeugung einer Graphik mit Hilfe des Programmes \texttt{gnuplot}} \index{gnuplot} %%===== FIGURE : begin ========== \begin{figure}[htbp] \begin{center} %\includegraphics[ scale=0.9]{./bilder/schwingung.eps} \input{./bilder/schwingung.tex} \caption{ \label{ABB:Schwingungsfigur} Darstellung einer Schwingungsfigur durch das Programm \texttt{gnuplot}} \vspace{ 5mm} \end{center} \end{figure} %%===== FIGURE : end ========== Erstellen Sie nun eine Datei mit dem Namen \textbf{kfeld.plt} in der folgende Steueranweisungen für das Programm \texttt{gnuplot} enthalten sind: \lstset{stepnumber=1} \lstinputlisting[caption={Steueranweisungen für das Programm \texttt{gnuplot}},label=gnuplot]{./programme/kfeld.plt} \begin{onehalfspace} \begin{center}\begin{tabular}{|c|p{12cm}|} \hline \textbf{Zeile} & \textbf{Erklärung}\\ \hline \hline 1 & Diagrammtitel festlegen\\ \hline 2 & Gitter erzeugen\\ \hline 3 & Legende nicht darstellen\\ \hline 4 & Beschriftung der x-Achse\\ \hline 5 & Beschriftung der y-Achse\\ \hline 6 & Kurvenausgabe: \newline aus Datei \texttt{kfeld.dat} Spalte 3 über Spalte 2 auftragen; \newline Punkte durch Linien verbinden\\ \hline 7 & Text \verb'"... weiter"' ausgeben und auf beliebigen Tastenanschlag warten\\ \hline \end{tabular}\end{center} \end{onehalfspace} Nachdem Sie \texttt{\textbf{kfeld.plt}} abgespeichert haben, rufen Sie das Program \texttt{gnuplot} mit foldender Komandozeile in einem shell-Fenster auf: \begin{quote} \begin{verbatim} student@rechner5:/home/student>gnuplot kfeld.plt \end{verbatim} \end{quote} Danach erscheint die graphische Ausgabe in einem neuen Fenster. Die Ausgabe wird beendet, wenn der Mauszeiger über dem shell-Fenster steht und die Eingabetaste gedrückt wird. Berechnen Sie nun \begin{align*} y_{1}(x) & =\sin(x) & y_{1}(x) & =\sin(x) & y_{1}(x) & = \sin(2x) \\ y_{2}(x) & =\cos(x) & y_{2}(x) & =\cos(3x) & y_{2}(x) & = \cos(3x) \end{align*} Weitere Berechnungen mit graphischer Ausgabe : \begin{align*} y_{1}(x) & =\sin(x) & y_{1}(x) & =x\cdot\sin(x) \\ y_{2}(x) & =\cos(x) & y_{2}(x) & =x\cdot\cos(3x) \end{align*} Um die Funktion $y_1(x)$ über $x$ aufzutragen muß die Zeile 6 in der Datei \texttt{\textbf{kfeld.plt}} wie folgt aussehen: \begin{quote} \begin{verbatim} plot "kfeld.dat" using 1:2 with lines \end{verbatim} \end{quote} Für die Darstellung von $y_2(x)$ über $x$ lautet diese Zeile \begin{quote} \begin{verbatim} plot "kfeld.dat" using 1:3 with lines \end{verbatim} \end{quote} %%---------------------------------------------------------------------- %% ÜBUNG : Umgang mit Texten %%---------------------------------------------------------------------- \chapter{Umgang mit Texten} %%---------------------------------------------------------------------- %% Buchstaben und Ziffern in einem Text abzählen %%---------------------------------------------------------------------- \section{Buchstaben und Ziffern in einem Text abzählen} \index{Buchstaben!abzählen} \index{Ziffern!abzählen} %%---------------------------------------------------------------------- %% Zustandsdiagramme %%---------------------------------------------------------------------- \begin{figure}[h] \subfigure[Wörter zählen] { \begin{picture}(80,80) \gasset{Nadjust=w,Nadjustdist=2} \node[fillcolor=Yellow,linewidth=.4](L)( 40, 40){ZWISCHENRAUM} \node[fillcolor=Yellow,linewidth=.4](W)( 40, 20){WORT} \imark[iangle=180](L) \drawedge[curvedepth=10](L,W){Buchstabe} \drawedge[curvedepth=10](W,L){Leerzeichen} \drawloop[loopangle= 0](L){Leerzeichen} \drawloop[loopangle=270](W){Buchstabe} \end{picture} } \subfigure[Wörter und Zahlen zählen] { \begin{picture}(80,80) \gasset{Nadjust=w,Nadjustdist=2} \node[fillcolor=Yellow,linewidth=.4](Z)(40, 60){ZAHL} \node[fillcolor=Yellow,linewidth=.4](L)(40, 40){ZWISCHENRAUM} \node[fillcolor=Yellow,linewidth=.4](W)(40, 20){WORT} \imark[iangle=180](L) \drawedge[curvedepth=10](Z,L){Leerzeichen} \drawedge[curvedepth=10](L,Z){Ziffer} \drawedge[curvedepth=10](L,W){Buchstabe} \drawedge[curvedepth=10](W,L){Leerzeichen} \drawloop[loopangle= 0](L){Leerzeichen} \drawloop[loopangle=270](W){Buchstabe} \drawloop[loopangle= 90](Z){Ziffer} \end{picture} } \caption{\label{cap:Zustandsdiagramme}Zustandsdiagramme\index{Zustanddiagramm} zur Wort- und Zahlenerkennung } \end{figure} \begin{itemize} \item Geben Sie das Beispielprogramm \texttt{string1.c} aus der Vorlesung ein, in welchem ein Text eingelesen, ausgegeben und die Anzahl der Klein- und Großbuchstaben ermittelt wird. Überprüfen Sie dessen Funktionsweise ! \item Erweiteren Sie das Programm so, daß auch Ziffern abgezählt werden können (Testfunktion: \texttt{isdigit()} ). \item Ändern Sie das Programm nun so, daß die Unterscheidung zwischen Klein- und Großbuchstaben entfällt und nur Buchstaben (Testfunktion: \texttt{isalpha()} ) und Ziffern abgezählt werden. \end{itemize} %%---------------------------------------------------------------------- %% Wörter in einem Text abzählen %%---------------------------------------------------------------------- \section{Wörter in einem Text abzählen} Das unter 4.1 entwickelte Programm soll nun so abgeändert werden, daß die Wörter im Eingabetext abgezählt und deren Anzahl ausgegeben werden. Die Analyse kann wie folgt durchgeführt werden: Das augenblicklich betrachtete Zeichen gehört entweder zu einem Wort oder zu einem Zwischenraum (Folge von Leerzeichen und/oder Tabulatoren). Jeder der beiden Zustände wird in einer Zustandsvariablen \texttt{zustand} \index{Zustandsvariablen} codiert, z.B. ZWISCHENRAUM: \texttt{zustand=0}, WORT: \texttt{zustand=1}. In jedem Schritt (d.h. beim jeweils nächsten zu betrachtenden Zeichen) wird überprüft, ob eine Zustandsänderung stattfindet (siehe Abb. \ref{cap:Zustandsdiagramme}). Beim Zustandsübergang ZWISCHENRAUM $\rightarrow$ WORT wird der Wortzähler erhöht. Zur Klassifizierung der einzelnen Zeichen können die C-Klassifizierungsfunktionen verwendet werden, die in der \texttt{h}-Datei \texttt{ctype.h} definiert sind (s.a. Abb \ref{cap:Hierarchie-der-Zeichenklassen}). %%---------------------------------------------------------------------- %% Wörter und Zahlen in einem Text abzählen %%---------------------------------------------------------------------- \section{Wörter und Zahlen in einem Text abzählen} Das unter 4.2 entwickelte Programm soll nun so abgeändert werden, daß zusätzlich Zahlen im Eingabetext erkannt, abgezählt und auch deren Anzahl ausgegeben wird. Dazu ist gemäß Abbildung \ref{cap:Zustandsdiagramme}b ein weiterer Zustand ZAHL einzufügen und die zusätzlichen Übergänge zu implementieren. Erweitern Sie das Programm indem Sie prüfen, ob in einer Buchstabenfolge eine Ziffer oder in einer Ziffernfolge ein Buchstabe auftritt. In diesem Fall soll das Programm eine Fehlermeldung ausgeben und über den Funktionsaufruf \texttt{exit(1)} verlassen werden. Erstellen Sie nun in einem Editor eine Textdatei \texttt{text.txt}, die eine größere Anzahl von Wörtern und Zahlen in einer einzigen Zeile enthält (höchstens 120 Zeichen). Führen Sie nun Ihr Programm von der Kommandozeile aus: \begin{quote} \begin{verbatim} .../home/student>prakt-4-3.e < text.txt \end{verbatim} \end{quote} Überprüfen Sie das Ergebnis ! Prüfen Sie nun Ihre Textdatei mit dem UNIX-Systemprogramm\index{UNIX!wc} \texttt{wc}\index{wc} (steht für word count): \begin{quote} \begin{verbatim} .../home/student>wc -w < text.txt \end{verbatim} \end{quote} Die ausgegebene Zahl muß der Summe der Wörter und Zahlen in der Ausgabe des eigenen Programmes entsprechen. \begin{figure}[h] \begin{center}\includegraphics{./bilder/zeichenklassen}\end{center} \caption{\label{cap:Hierarchie-der-Zeichenklassen}Hierarchie der Zeichenklassen\index{Zeichenklassen} und der Klassifizierungsfunktionen in C (\texttt{h}-Datei \texttt{ctype.h})} \end{figure} %%---------------------------------------------------------------------- %% ÜBUNG : Codieren und Decodieren von Texten %%---------------------------------------------------------------------- \chapter{Codieren und Decodieren von Texten} \index{codieren} \index{decodieren} \index{Text!codieren, decodieren} %%---------------------------------------------------------------------- %% Inhalt eines Feldes um n Positionen nach links oder rechts rotieren %%---------------------------------------------------------------------- \section{\label{sec:Codieren-1}Inhalt eines Feldes um n Positionen nach links oder rechts rotieren} Legen Sie ein Feld \texttt{ascii} vom Typ \texttt{int} mit n=128 Elementen an, füllen Sie das Feld mit der Zahlenfolge 0, 1, 2, 3, ... , 127 ( = jeweiliger Feldindex) und geben Sie das Feld in Zeilen zu 16 Elementen aus. Lesen Sie eine ganze Zahl $r$ ein die angibt, um wieviele Plätze der Feldinhalt zyklisch nach links (negative Zahl) oder nach rechts (positive Zahl) verschoben werden soll. Das folgende Beispiel zeigt eine Verschiebung um $r = 2$ nach links: % \begin{figure}[h] \begin{center}\includegraphics{./bilder/feld-rotieren-1}\end{center} \caption{\label{cap:Feldinhalt-um-2}Feldinhalt um 2 Positionen nach links verschieben} \end{figure} %%---------------------------------------------------------------------- %% Einen Teilbereich eines Feldes um n Positionen nach links oder rechts rotieren %%---------------------------------------------------------------------- \section{\label{sec:Codieren-2}Einen Teilbereich eines Feldes um n Positionen nach links oder rechts rotieren} Ändern Sie das Programm aus der Aufgabe \ref{sec:Codieren-1} so ab, daß zusätzlich die Anfangsposition $p_1$ und Endposition $p_2$ eines Bereiches des Feldes eingelesen wird. Nur die Feldelemente innerhalb dieses Bereiches sollen rotiert werden. Überprüfen Sie, ob vor der Verschiebung die folgenden Bedingungen erfüllt sind: \begin{align*} 0 \leq p_1 && p_1 < p_2 && p_2 < 128 \end{align*} Geben Sie das rotierte Feld mit derselben Formatierung wie das Originalfeld aus und überprüfen Sie das Ergebnis mit verschiedenen Links- und Rechtsverschiebungen. %%---------------------------------------------------------------------- %% Text chiffrieren %%---------------------------------------------------------------------- \section{\label{sec:Codieren-3}Text chiffrieren} \index{chiffrieren} Verwenden Sie das Programm aus Aufgabe \ref{sec:Codieren-2} und rotieren Sie das \texttt{int}-Feld zwischen $p_1 = 32$ und $p_2 = 126$ (=alle Nichtsteuerzeichen des ASCII-Codes) um $r = -5$ Positionen (nach links). Lesen Sie zeichenweise eine Datei \texttt{klar.txt} in einen Textpuffer\texttt{text} ein (s. Beispiel \texttt{string.c} aus der Vorlesung). Die Datei \texttt{klar.txt} soll einen einzeiligen Klartext enthalten. Die Feldelemente des Textpuffers enthalten die eingelesenen Zeichen in ASCII-Codierung. Diese liegt jeweils zwischen den Werten 0 und 127. Diese Werte können nun mit Hilfe des eingangs erzeugten Feldes in einfacher Weise chiffriert werden. Die Werte der Zeichen im Textpuffer \texttt{text} werden als Index des teilweise rotierten Feldes \texttt{ascii} zur Adressierung des Zielzeichens verwendet: \begin{quote} \begin{verbatim} putchar( ascii[ text[i] ] ); \end{verbatim} \end{quote} Wegen der Rotation der Nichtsteuerzeichen um 5 Positionen wird der Buchstabe A auf F, die Ziffer 1 auf 6 usw. abgebildet. Die Steuerzeichen (falls vorhanden) werden durch sich selbst codiert, d.h. nicht verändert. Das Feld vor der Rotation: Der Feldindex entspricht dem ASCII-Wert des Inhalts, der hier in lesbarer Form dargestellt ist (Abb. \ref{cap:Zeichenfeld-als-Hilfsmittel}, oben). % \begin{figure}[h] \begin{center}\includegraphics{./bilder/feld-rotieren-2}\end{center} \caption{\label{cap:Zeichenfeld-als-Hilfsmittel}Zeichenfeld als Hilfsmittel zur Textchiffrierung} \end{figure} Das Feld nach der Rotation: Wird das Feld mit dem Wert des Buchstabens B (=66) adressiert, wird nun der Inhalt 71 ausgelesen (entspricht dem ASCII-Wert von G), d.h. B wird durch G codiert (Abb. \ref{cap:Zeichenfeld-als-Hilfsmittel}, unten). %%---------------------------------------------------------------------- %% Text dechiffrieren %%---------------------------------------------------------------------- \section{Text dechiffrieren} \index{dechiffrieren} Kopieren Sie das Programm aus Aufgabe \ref{sec:Codieren-3} und rotieren Sie das \texttt{int}-Feld zwischen $p_1 = 32$ und $p_2 = 126$ (=alle Nichtsteuerzeichen des ASCII-Codes) um $r = +5$ Positionen (nach rechts). Führen Sie nun Ihr Programm von der Kommandozeile aus: \begin{quote} \begin{verbatim} .../home/student>prakt-5-4.e < geheim.tx > klar1.txt \end{verbatim} \end{quote} Bei richtiger Arbeitsweise beider Programme muß der Inhalt der Dateien \texttt{klar.txt} und \texttt{klar1.txt} übereinstimmen. %%---------------------------------------------------------------------- %% ÜBUNG : Einfache statistische Kennwerte %%---------------------------------------------------------------------- \chapter{Einfache statistische Kennwerte} \index{Kennwerte!statistische} %%---------------------------------------------------------------------- %% Statistische Kennwerte %%---------------------------------------------------------------------- \section{Statistische Kennwerte} Folgende Kennwerte einer Zahlenfolge $x_{1},...,x_{n}$ sind zu berechnen: %%+++++ TABLE : begin ++++++++++ \begin{onehalfspace} \begin{tabular}{|c|p{12cm}|} \hline \textbf{Kennwert} & \textbf{Berechnungsvorschrift}\\ \hline \hline Minimum\index{Minimum}& kleinster Wert der Zahlenfolge\\ \hline Maximum\index{Maximum}& größter Wert der Zahlenfolge\\ \hline Spanne\index{Spanne}& (Maximum - Minimum)\\ \hline Arithmetischer Mittelwert\index{Mittelwert!arithmetischer}& $$am=\sum _{i=1}^{n}x_{i}$$ \\ \hline Geometrischer Mittelwert\index{Mittelwert!geometrischer}& $$gm=\sqrt[n]{x_{1}x_{2}\cdots x_{n}}$$ Zur Berechnung siehe Abschnitt \ref{SEC:GeoMittel}. \\ \hline Quadratischer Mittelwert\index{Mittelwert!quadratischer}& $$qm=\sqrt{\frac{1}{n}\sum _{i=1}^{n}x_{i}^{2}}$$ \\ \hline Mittlere Abweichung\index{Abweichung}& $$ma=\frac{1}{n}\sum _{i=1}^{n}\Vert x_{i}-am\Vert $$ \\ \hline Median\index{Median}& Der Median einer Menge von Zahlen, die \textit{der Größe nach sortiert} sind, ist bei ungerader Anzahl der Wert in der Mitte, bei gerader Anzahl das arithmetische Mittel der beiden Werte in der Mitte. Zur Sortierung s. Abschnitt \ref{SEC:Sortieren}. \\ \hline \end{tabular} \end{onehalfspace} %%+++++ TABLE : end ++++++++++ Bei der Programmerstellung ist folgendermaßen vorzugehen: \begin{itemize} \item Verwenden Sie zur Berechnung der Kennwerte jeweils eine eigene Funktion. \item Es sollen 200 \texttt{double}-Werte berücksichtigt werden, die mit Hilfe des Zufallsgenerators \texttt{\textbf{rand()}} (Prototyp in \texttt{stdlib.h}) erzeugt werden können (Wertebereich 0 bis 100; eine Nachkommastelle, die ungleich Null sein kann). \item Schreiben Sie eine C-Funktion, die die Zahlenreihe in Zeilen zu 10 Werten auf den Bildschirm ausgibt. \item Zur Berechnung des geometrischen Mittels soll der natürliche Logarithmus verwendet werden ( s. Abschnitt \ref{SEC:GeoMittel}; Funktionen: \texttt{\textbf{log(), exp()}}, Prototypen in \texttt{math.h} ). Die Übergabe eines eindimensionalen Feldes an eine Funktion geschieht wie folgt: \end{itemize} \begin{quote} \begin{verbatim} double am ( double x[ ], int n ) { } \end{verbatim} \end{quote} %%---------------------------------------------------------------------- %% Sortieren durch Vertauschen %%---------------------------------------------------------------------- \section{\label{SEC:Sortieren}Sortieren durch Vertauschen} \index{Sortieren durch Vertauschen} \begin{floatingfigure}[r]{85mm} \includegraphics[ ]{./bilder/sortieren-vertauschen.eps} \caption{ Sortieren durch Vertauschen } \end{floatingfigure} \textbf{Vorgehensweise} Das erste und das zweite Element der vorgelegten Liste werden verglichen. Ist das erste größer als das zweite, so werden die beiden vertauscht. Der gleiche Vorgang wird auf das (nunmehr) zweite und dritte Element der Liste angewandt, dann auf das (nunmehr) dritte und vierte. Dies wird bis zum Vergleich des (n-1)-ten mit dem n-ten Element fortgesetzt. Nach (n-1) Vergleichen befindet sich das größte Element am Ende der Liste. Nach dem gleichen Verfahren wird nun in der um eine Position verkürzten Liste das zweitgrößte Element auf die vorletzte Position gebracht. Dies wird fortgesetzt an einer immer kürzer werdenden Restliste bis diese schließlich nur noch aus einem Element besteht. \textbf{Aufwand} Der Sortieraufwand\index{Sortieraufwand} A ergibt sich durch das Aufsummieren der in den einzelnen Durchläufen anfallenden Vergleichsschritte: \[ A=\sum _{i=1}^{n-1}\left(n-i\right)=\frac{n(n-1)}{2}\approx \frac{n^{2}}{2}\] \textbf{Vorteil} Das Verfahren hat den Vorteil, daß es keinerlei zusätzlichen Speicher benötigt. Der Sortiervorgang läuft innerhalb der vorgelegten Originalliste ab. \textbf{Nachteil} Ein schwerwiegender Nachteil ist die Zunahme des Aufwandes mit dem Quadrat der Listenlänge $n$. Das Verfahren ist daher nur für kurze, selten zu sortierende Listen geeignet. %%---------------------------------------------------------------------- %% Berechnung des geometrischen Mittelwertes %%---------------------------------------------------------------------- \section{\label{SEC:GeoMittel}Berechnung des geometrischen Mittelwertes} \index{Mittelwert!geometrischer} Durch Logarithmieren der Gleichung $$gm=\sqrt[n]{x_{1}x_{2}\cdots x_{n}}$$ mit dem natürlichen Logarithmus $\ln$ (Basis $e$) erhält man \index{Logarithmus!natürlicher} \begin{eqnarray*} GM= \ln{gm} &=& \ln{\sqrt[n]{x_{1}x_{2}\cdots x_{n}}} \\ &=& \frac{1}{n}(\ln{x_1}+\ln{x_2}+\ldots+\ln{x_n}) \\ &=& \frac{1}{n}\sum_{i=1}^{n}\ln{x_i} \end{eqnarray*} d.h. man berechnet zunächst den Logarithmus von $gm$ als arithmetisches Mittel der Summe der Logarithmen der Größen $x_i$. Man erhält nun das gesuchte Ergebnis $gm$ durch Potenzierung: $$gm=e^{GM}=e^{\ln{gm}}$$ %%---------------------------------------------------------------------- %% ÜBUNG : Vollständige Lösung einer quadratischen Gleichung %%---------------------------------------------------------------------- \chapter{Vollständige Lösung einer quadratischen Gleichung} \index{Gleichung!quadratische} \index{quadratische Gleichung} %%---------------------------------------------------------------------- %% Lösung einer quadratischen Gleichung %%---------------------------------------------------------------------- \section{Lösung einer quadratischen Gleichung} Für die allgemeine quadratische Gleichung $ax^{2}+bx+c=0$ wird üblicherweise die Lösungsformel \begin{equation} x_{1,2}=\frac{1}{2}\left[-b\pm \sqrt{b^{2}-4ac}\right]\label{eq:Lsg-Quadr-Gleichung} \end{equation} angegeben. Eine durch ein Programm automatisch zu bestimmende Lösung muß in der Regel \textit{logisch vollständig} entwickelt und programmiert werden. Jeder der Koeffizienten $a$, $b$ und $c$ kann gleich Null oder ungleich Null sein. Hierdurch ergeben sich bereits $2^{3}=8$ Fälle. Durch Betrachtung der Vorzeichen der Ausdrücke, die bei einzelnen Fällen unter einer Wurzel stehen, ergeben sich dann insgesamt 10 Fälle. Diese 10 Fälle sind in der folgenden Tabelle wiedergegeben. Es gilt mit den Hilfsgrößen: \begin{align*} u=-c/a && v=b^{2}-4ac && i=\sqrt{-1} \end{align*} \begin{doublespace} \begin{center}\begin{tabular}{|c|r|r|r|r|r|l|} \hline Fall& a& b& c& u& v& Berechnungsvorschrift\\ \hline \hline 0& $=0$& $=0$& $=0$& & & triviale Gleichung\\ \hline 1& $=0$& $=0$& $\neq 0$& & & Widerspruch\\ \hline 2& $=0$& $\neq 0$& $=0$& & & $x_{1}=0$\\ \hline 3& $=0$& $\neq 0$& $\neq 0$& & & $x_{2}=-c/b$\\ \hline 4& $\neq 0$& $=0$& $=0$& & & $x_{1}=x_{2}=0$\\ \hline 5.1& $\neq 0$& $=0$& $\neq 0$& $\geq 0$& & $x_{1,2}=\pm \sqrt{u}$\\ \hline 5.2& $\neq 0$& $=0$& $\neq 0$& $<0$& & $x_{1,2}=\pm i\sqrt{-u}$\\ \hline 6& $\neq 0$& $\neq 0$& $=0$& & & $x_{1}=0,x_{2}=-b/a$\\ \hline 7.1& $\neq 0$& $\neq 0$& $\neq 0$& & $\geq 0$& $x_{1,2}=\frac{1}{2a}\left[-b\pm \sqrt{v}\right]$\\ \hline 7.2& $\neq 0$& $\neq 0$& $\neq 0$& & $<0$& $x_{1,2}=\frac{1}{2a}\left[-b\pm i\sqrt{-v}\right]$\\ \hline \end{tabular}\end{center} \end{doublespace} Entwickeln Sie ein Programm, in welchem zunächst die Koeffizienten $a$, $b$ und $c$ eingelesen werden. Anschließend wird mit Hilfe einer vollständigen Fallunterscheidung der zutreffende Fall ermittelt und gelöst. Die gewonnene Lösung soll ausgegeben und durch eine anschließende Kontrollrechnung (Einsetzen von $x_{1}$ und $x_{2}$ in die Ausgangsgleichung) automatisch überprüft werden. %%---------------------------------------------------------------------- %% Kontrollrechnung für Fall 5.2 %%---------------------------------------------------------------------- \section{Kontrollrechnung für Fall 5.2} Für die konjugiert komplexen Lösungen $x_{1}$ und $x_{2}$ erhält man zunächst: \begin{eqnarray*} x_{1.2} & = & \pm s\cdot i\\ x_{1,2}^{2} & = & -s^{2} \end{eqnarray*} Durch Einsetzen in die Ausgangsgleichung (b = 0) erhält man nun \begin{eqnarray*} a\cdot (-s^{2})+c & = & 0 \end{eqnarray*} Der Absolutwert der linken Seite muß kleiner sein als eine positive Schranke $\varepsilon $ (s.u.). %%---------------------------------------------------------------------- %% Bestimmung der komplexen Lösungen für den Fall 7.2 %%---------------------------------------------------------------------- \section{Bestimmung der komplexen Lösungen für den Fall 7.2} \[ x_{1,2}=\frac{1}{2a}\left[-b\pm i\sqrt{-v}\right]=\left(\frac{-b}{2a}\right)\pm \left(\frac{\sqrt{-v}}{2a}\right)\cdot i=r\pm s\cdot i\] Die Ausdrücke in den runden Klammern sind reell und müssen getrennt berechnet werden (z.B. in den Variablen \texttt{r} und \texttt{s}). Bei der Druckausgabe wird die imaginäre Einheit $i$ als Text ausgegeben: \begin{verbatim} printf("x1 = %.3f %+.3f*i", r, +s ); printf("x2 = %.3f %+.3f*i", r, -s ); \end{verbatim} %%---------------------------------------------------------------------- %% Kontrollrechnung für Fall 7.2 %%---------------------------------------------------------------------- \section{Kontrollrechnung für Fall 7.2} Für die konjugiert komplexen Lösungen $x_{1}$ und $x_{2}$ erhält man zunächst: \begin{eqnarray*} x_{1,2} & = & r\pm s\cdot i\\ x_{1,2}^{2} & = & \left(r\pm s\cdot i\right)^{2}=\left(r^{2}-s^{2}\right)\pm \left(2rs\right)\cdot i \end{eqnarray*} Durch Einsetzen in die Ausgangsgleichung erhält man nun \begin{eqnarray*} a\left[\left(r^{2}-s^{2}\right)\pm \left(2rs\right)\cdot i\right] \quad + \quad b\left[r\pm s\cdot i\right] & = & 0 \\ \left[a\left(r^{2}-s^{2}\right)+br+c\right] \quad \pm\quad \left[a(2rs)+bs\right]\cdot i & = & 0 \end{eqnarray*} Die Ausdrücke in den eckigen Klammern müssen beide Null sein um die Gleichung zu erfüllen. Wegen der bekannten Eigenschaften der Gleitkommarechnung kann nicht direkt mit Null verglichen werden. Der Absolutwert des jeweiligen Ausdruckes muß kleiner sein als eine positive Schranke $\varepsilon $ (z.B. $\varepsilon =10^{-10}$). %%---------------------------------------------------------------------- %% ÜBUNG : Rekursion %%---------------------------------------------------------------------- \chapter{Rekursion} %%---------------------------------------------------------------------- %% Berechnung der Fakultät einer natürlichen Zahl %%---------------------------------------------------------------------- \section{Berechnung der Fakultät einer natürlichen Zahl} \index{Fakultät} %%===== FIGURE (floating) : begin ========== \begin{floatingfigure}[r]{70mm} \begin{center} \includegraphics[ ]{./bilder/rekurs-fakul.eps} \caption{ \label{Ablaufdiagramm-Fakultät} Ablaufdiagramm zur Berechnung der Fakultät } \vspace{ 5mm} \end{center} \end{floatingfigure} %%===== FIGURE (floating): end ========== Der Ausdruck $n!$ ist definiert als $$n!\quad = \quad n\cdot (n-1)\cdot (n-2)\ldots 2\cdot 1\quad = \quad n\cdot (n-1)!$$ Daraus ergibt sich die Möglichkeit, eine Funktion \texttt{fakul()} zur Berechnung der Fakultät rekursiv zu schreiben. Das vereinfachte Ablaufdiagramm ist in Abb. \ref{Ablaufdiagramm-Fakultät} wiedergegeben. Schreiben Sie ein Hauptprogramm, in welchem eine rekursive Funktion \texttt{ long fakul ( long n )} aufgerufen wird um eine Tabelle der Fakultäten der Zahlen von 1 bis 20 zu berechnen. Stellen Sie fest, bis zu welchem $n$ die berechnete Fakultät richtig ist. %%---------------------------------------------------------------------- %% Berechnung der Fibonacci-Zahlen %%---------------------------------------------------------------------- \section{Berechnung der Fibonacci-Zahlen} \index{Fibonacci-Zahlen} Die Fibonacci-Zahlen $f_{i}$ sind wie folgt rekursiv definiert: \begin{align} f_{1}=1 && f_{2}=1 && f_{n}=f_{n-1}+f_{n-2};\quad n\geq 3 \label{eq:fibinacci-Zahlen} \end{align} Schreiben Sie ein Hauptprogramm, in welchem eine rekursive Funktion \begin{quote} \begin{verbatim} int finonacci ( int n ) \end{verbatim} \end{quote} aufgerufen wird um die Fibonacci-Zahlen $f_1$ bis $f_{20}$ zu berechnen und in einer Tabelle auszugeben. Verwenden Sie eine globale Variable um die jeweils erforderliche Anzahl der Funktionsaufrufe festzustellen. Geben Sie die Anzahl der Funktionsaufrufe ebenfalls in der Tabelle aus. Ermitteln Sie die Abhängigkeit zwischen der Fibonacci-Zahl und der Anzahl der zur Berechnung erforderlichen Funktionsaufrufe. %%---------------------------------------------------------------------- %% Erzeugung von Permutationen %%---------------------------------------------------------------------- \section{Erzeugung von Permutationen} \index{Permutation} %%+++++ TABLE (floating) : begin ++++++++++ \begin{floatingtable}[r]{ \begin{tabular}{p{10mm} p{11mm} p{11mm} p{11mm}} & 1& 2& 3\\ & 1& 3& 2\\ & 2& 1& 3\\ & 2& 3& 1\\ & 3& 2& 1\\ & 3& 1& 2\\ \end{tabular}} \caption{ \label{cap:Permutationen-von-3} Permutationen von 3 Zahlen } \vspace{ 15mm} \end{floatingtable} %%+++++ TABLE (floating): end ++++++++++ Eine Permutation entsteht durch die Umordnung einer Objekt- oder Zahlenreihe. Eine Aufgabenstellung aus der Kombinatorik ist die systematische Erzeugung aller $n!$ Anordnungen einer Menge von $n$ Zahlen. Die Menge $(1,2,3)$ besitzt $3! = 6$ Permutationen (s. Tab. \ref{cap:Permutationen-von-3}). Eine Möglichkeit zur Erzeugung von Permutationen kann rekursiv programmiert werden. Ein Feld \texttt{a[ ]} ist anfänglich z.B. fortlaufend mit den Werten 0, 1, 2, ... 7 belegt und wird wie folgt permutiert: Die Permutation der Stufe 0 entsteht durch Eintauschen des Wertes des 1. Feldplatzes mit allen anderen Feldplätzen (8 Möglichkeiten). Die 1. Stufe berücksichtigt nur noch die Feldplätze 2 bis $n$ (Abb. \ref{cap:Erzeugung-von-Permutationen}a ), usw. Die Ordnung $n$ der Permutaionen wird in einer globalen Variablen \texttt{n} abgelegt. Die Funktion \texttt{void perm ( int k )} kann so geschrieben werden, daß bei einem Startaufruf mit \texttt{perm (0)} gemäß Ablauf in Abb. \ref{cap:Erzeugung-von-Permutationen}b die Permutationen für 0, 1, 2, 3, .. der Reihe nach erzeugt werden. Erst bei Erreichen der Stufe $n-1$ wird die jeweilige Permutation (Inhalt des Feldes \texttt{a[ ]} ) ausgegeben. \begin{figure}[h] \begin{center} \subfigure[Symmetrisches Tauschen]{\includegraphics[ scale=0.8]{./bilder/permutation}} \subfigure[Vereinfachtes Ablaufdiagramm]{\includegraphics[ scale=0.8]{./bilder/rekurs-perm}} \end{center} \caption{Erzeugung von Permutationen\label{cap:Erzeugung-von-Permutationen}} \end{figure} Die Korrektheit der Ergebnisse kann nur für kleine $n$ (z.B. $n = 2, 3 \ldots$ ) direkt überprüft werden. Für größere $n$ kann die Programmausgabe in eine Datei umgeleitet werden (z.B. für: $n = 8$; $8! = 40320$ ) : \begin{quote} \begin{verbatim} permutation.e > perm8.dat \end{verbatim} \end{quote} Wenn eine Zeile pro Permutation erzeugt wurde (hier 40320 Zeilen), kann mit dem Kommando \begin{quote} \begin{verbatim} wc -l perm8.dat \end{verbatim} \end{quote} die Anzahl der Zeilen der Datei \texttt{perm8.dat} festgestellt werden (\texttt{wc} ist ein UNIX-Kommando zur Wortzählung, die Option \texttt{-l} erzwingt jedoch die Zeilenzählung). Um festzustellen, ob alle Permutaionen voneinander verschieden sind, kann der Dateiinhalt sortiert werden: \begin{quote} \begin{verbatim} sort -u < perm8.dat > perm8sort.dat \end{verbatim} \end{quote} \texttt{sort} \index{sort} \index{UNIX!sort}ist das UNIX-Sortierkommando, die Option \texttt{-u} erzwingt, daß mehrfach vorhandene Datensätze nur einmal gezählt werden. Weicht die Satzanzahl von \texttt{perm8.dat} und \texttt{perm8sort.dat} voneinander ab, dann ist die Erzeugung noch fehlerhaft. %%---------------------------------------------------------------------- %% ÜBUNG : Zweidimensionale Felder - Bildverarbeitung %%---------------------------------------------------------------------- \chapter{Zweidimensionale Felder - Bildverarbeitung} \index{Bildverarbeitung} %%---------------------------------------------------------------------- %% Bilddatei lesen und speichern %%---------------------------------------------------------------------- \section{Bilddatei lesen und speichern} In der Datei \texttt{grau1.pgm} ist ein Grauwertbild\index{Grauwertbild} (Abb. \ref{cap:Grauwertbild}) wie folgt abgespeichert (s. Listing \ref{pgm-Datei} und Tab. \ref{cap:Aufbau-einer-pgm-Datei}): \lstset{language=C} \lstset{stepnumber=5} \lstinputlisting[lastline=24,caption={Beginn der pgm-Datei \texttt{grau1.pgm}},label=pgm-Datei]{./bilder/grau1.pgm} \begin{table}[h] \begin{onehalfspace} \begin{center}\begin{tabular}{|c|c|l|} \hline \textbf{Zeile}& \textbf{Inhalt}& \textbf{Bedeutung}\\ \hline \hline 1 & P2 & Codierung des Dateityps, hier pgm\\ \hline 2 & 256 256 & Bildbreite und -höhe in Pixel\\ \hline 3 & 255 & maximaler Grauwert (0 = schwarz , 255 = weiß)\\ \hline 4 bis Dateiende& & Grauwerte der einzelnen Bildpunkte; zeilenweise fortlaufend abgelegt\\ \hline \end{tabular}\end{center} \caption{Aufbau einer pgm-Datei\label{cap:Aufbau-einer-pgm-Datei}} \end{onehalfspace} \end{table} \begin{figure}[h] \begin{center} \includegraphics[scale=.5]{./bilder/grau1.eps} \end{center} \caption{Grauwertbild in der Datei \texttt{grau1.pgm}\label{cap:Grauwertbild}} \end{figure} Schreiben Sie ein Programm in welches die Datei \texttt{grau1.pgm} eingelesen wird. Die Bildinformationen (Zeile 1-3) sollen zur Kontrolle ausgegeben werden. Das Bild wird in einem hinreichend großen globalen Feld vom Typ \texttt{unsigned char} zeilenweise eingelesen. Anschließend ist das Bild im selben Dateiformat in eine Datei \texttt{grau2.pgm} zu speichern. Das abgespeicherte Bild kann mit den Programmen \texttt{xv\index{xv}} oder \texttt{kview\index{kview}} (Bildbetrachtung und -bearbeitung) dargestellt werden: \begin{quote} \begin{verbatim} xv grau1.pgm \end{verbatim} \end{quote} Programm \texttt{xv}: Bei Betätigung der rechten Maustaste erscheint ein Dialogfenster. Wenn der Mauszeiger über dem Bild steht, reicht die Eingabe des Buchstabens q um das Programm zu beenden. %%---------------------------------------------------------------------- %% Grauwertbild bearbeiten %%---------------------------------------------------------------------- \section{Grauwertbild bearbeiten} %%===== FIGURE (floating) : begin ========== \begin{floatingfigure}[r]{80mm} \begin{center} \includegraphics[ ]{./bilder/bildbearbeitung-menu.eps} \caption{Menu 'Bildbearbeitung'\label{cap:Menu-Bildbearbeitung}} \vspace{ 5mm} \end{center} \end{floatingfigure} %%===== FIGURE (floating): end ========== Im zweiten Schritt soll durch die Anwendung von Bearbeitungsschritten aus dem Originalbild ein Ergebnisbild erzeugt werden. Legen Sie zunächst ein weiteres Feld zur Aufnahme des bearbeiteten Bildes an, kopieren Sie das eingelesenen Bild vom ersten in das zweite Feld und geben Sie dann das zweite Feld in die Datei \texttt{grau2.pgm} aus. Geben Sie nun ein kleines Menü (Abb. \ref{cap:Menu-Bildbearbeitung}) aus und lesen Sie einen Buchstaben zur Auswahl ein. Mit diesem Buchstaben wird eine \texttt{switch}-Anweisung gesteuert, in welcher die Bildoperationen durchgeführt werden. \textbf{Invertierung}\index{Invertierung}. Bei der Invertierung wird der neue Grauwert $b_{ij}$ aus dem ursprünglichen Grauwert $a_{ij}$ wie folgt berechnet: $$b_{ij}=max.Grauwert-a_{ij}$$ Es entsteht ein Negativbild: Schwarz wird zu Weiß und umgekehrt. Kontrollieren Sie das Ergebnis mit dem Bildbetrachter \texttt{xv}. % \begin{figure} \begin{center} \includegraphics{./bilder/bildverarb-mittelwert} \end{center} \caption{Glättung durch Mittelwertbildung über 9 Bildpunkte\label{cap:Gl=E4ttung-durch-Mittelwertbildung}} \end{figure} \textbf{Schwellwertoperation}\index{Schwellwertoperation}. Alle Bildpunkte, die im Originalbild einen Grauwert kleiner 150 besitzen, werden im Ergebnisbild zu Null gesetzt. Alle anderen Grauwerte werden unverändert übernommen. \textbf{Glättung}\index{Glättung}. Bei der Glättung entsteht das Zielpixel durch Mittelwertbildung über das Originalpixel und dessen 8 Umgebungspixel (Abb. \ref{cap:Gl=E4ttung-durch-Mittelwertbildung}). Durch die Glättung werden harte Kontraste gemildert. % \begin{figure} \begin{center} \includegraphics[scale=1.0]{./bilder/bildverarb-kanten} \end{center} \caption[Kantenerkennung]{Kantenerkennung durch Verknüpfung einer 3x3-Umgebung des Originalbildes mit einer Gewichtungsmatrix\label{cap:Kantenerkennung-durch-Verkn=FCpfung}} \end{figure} \textbf{Kantenerkennung}\index{Kantenerkennung}. Objektkanten sind dort zu vermuten, wo sprungartige Helligkeitsübergänge vorhanden sind. Um Kanten rechnerisch zu ermitteln wird über das Bild ein sog. Operatorfenster geschoben. Der aktuelle Bildpunkt und die 8 Nachbarpunkte werden mit den Gewichtungen in Abb. \ref{cap:Kantenerkennung-durch-Verkn=FCpfung} multipliziert, addiert und zur Normierung durch 9 geteilt. Der Betrag dieses Ergebnisses ist der Wert des Zielbildpunktes. Wie bei der Glättung kann diese Operation nur auf die inneren Punkte des Originals angewendet werden. %%---------------------------------------------------------------------- %% Bildbereich füllen %%---------------------------------------------------------------------- \section{Bildbereich füllen} \index{Bildbereich füllen} %%===== FIGURE (floating) : begin ========== \begin{floatingfigure}[r]{95mm} \includegraphics[scale=1.0]{./bilder/bild-fuellen.eps} \caption{ \label{ABB:Fuellung-eines-Bildbereiches} Rekursives Füllen eines Bildbereiches } \end{floatingfigure} %%===== FIGURE (floating): end ========== Bei Grauwertbildern sollen zusammenhängende Bereiche mit einem neuen Grauwert versehen werden. Dazu wird ein Impfpixel auf einen neuen Wert gesetzt und rekursiv alle Nachbarpixel untersucht. Wenn ein Nachbarpixel denselben Originalgrauwert besitzt, dann erhält es ebenfalls den neuen Wert und seine Nachbarn müssen auch untersucht werden. Beachten Sie, daß jeder innere Bildpunkt 4 echte Nachbarn besitzt (Randpunkte entsprechend weniger !). In Abb. \ref{ABB:Fuellung-eines-Bildbereiches}, links, wird ein Hintergrundpixel mit einem neuen Grauwert ,,geimpft''. Im rechten Bild haben alle Hintergrundpixel rekursiv den neuen Grauwert erhalten. Verwenden Sie nachfolgenden Rahmen: \lstset{language=C} \lstinputlisting[caption={Rahmen für die rekursive Funktion \texttt{fill}},label=pgm-fill]{./programme/fill.c} %%---------------------------------------------------------------------- %% Verwendung von Strukturen %%---------------------------------------------------------------------- \section{Verwendung von Strukturen} \index{Struktur} Erstellen Sie eine neue Version des Programmes, in welcher die Grauwertbilder in einer Struktur (Listing \ref{pgm-struct}) abgelegt werden. Außerdem sollen alle Bildverarbeitungsfunktionen in jeweils einer eigenen Funktion dargestellt werden. Die Bilder sind mittels Zeiger an die Funktionen übergeben werden. \lstset{language=C} \lstinputlisting[caption={Strukturdefinition für ein pgm-Bild},label=pgm-struct]{./programme/bildverarb-struct.c} %%---------------------------------------------------------------------- %% ÜBUNG : Implementierung eines Stapels als Klasse %%---------------------------------------------------------------------- \chapter{Implementierung eines Stapels als Klasse} \index{Stapel} \index{Klasse} %%---------------------------------------------------------------------- %% Basisimplementierung eines Stapels als C++ - Klasse %%---------------------------------------------------------------------- \section{Basisimplementierung eines Stapels als C++ - Klasse} \begin{floatingfigure}[r]{75mm} \includegraphics[ ]{./bilder/stack.eps} \caption{ \label{Datenstruktur-Stapel} Datenstruktur Stapel } \end{floatingfigure} Abb. \ref{Datenstruktur-Stapel} zeigt die Skizze eines Stapels mit 100 Datenelementen. Der Stapelzeiger \texttt{top} zeigt auf den nächste freien Platz. Datenelemente des Stapels: \begin{itemize} \item Feld, 100 Elemente, zur Aufnahme der Daten \item Stapelzeiger (\texttt{top}) \item Feldumfang (zur Überwachung; globale \texttt{const}-Größe) \end{itemize} Operationen auf dem Stapel: \begin{itemize} \item Initialisieren (\texttt{top} = 0) \item Element auflegen (\texttt{push}) \item Element abnehmen (\texttt{pop}) \item Feststellen, ob der Stapel leer ist \item Anzahl der Datenelemente ermitteln \item Wert des obersten Elementes feststellen \end{itemize} Schreiben Sie ein C++-Programm (Dateiendung \texttt{.cc}), in welchem ein Stapel mit 100 Elementen als Klasse \texttt{stack} für die Aufnahme von \texttt{int}-Elementen implementiert ist. Die Datenelemente sind als \texttt{private}-Elemente, die Operationen (Methoden, Komponentenfunktionen) als \texttt{public}-Elemente einzurichten. Die Implementierung der Komponentenfunktionen soll außerhalb der Klassendefinition stehen und muß deshalb den scope-resolution-Operator ( \texttt{::} ) verwenden: \begin{quote} \begin{verbatim} void stack :: push ( int datum ) { . . . } \end{verbatim} \end{quote} Die Einrichtung eines Stapels geschieht z.B. durch \begin{quote} \begin{verbatim} stack stapel1; \end{verbatim} \end{quote} Der Aufruf einer Komponentenfunktion geschieht z.B. durch \begin{quote} \begin{verbatim} stapel1.push( 37 ); \end{verbatim} \end{quote} \begin{itemize} \item Schreiben Sie ein Hauptprogramm, in welchem der Stapel in einer Schleife mit einigen Elementen gefüllt wird. \item Geben Sie die Belegung des Stapels aus und bauen Sie den Stapel wieder ab (mit Ausgabe) um das richtige Funktionieren zu testen. \item Verhindern Sie Unterlauf und Überlauf des Stapels durch entsprechende Vorkehrungen in den Komponentenfunktionen. \item Ersetzen Sie die Initialisierungsfunktion durch einen Konstruktor. \item Verwenden Sie zur Eingabe und Ausgabe \texttt{cin} und \texttt{cout} ( \texttt{\#include } ). \end{itemize} %%---------------------------------------------------------------------- %% Konstruktor und Destruktor für Stapel beliebiger Größe %%---------------------------------------------------------------------- \section{Konstruktor und Destruktor für Stapel beliebiger Größe} \index{Konstruktor} \index{Destruktor} Ändern Sie die Klassendefinition so ab, daß mit Hilfe eines 1. Konstruktors ein Stapel beliebiger Länge zur Laufzeit angelegt werden kann (Operator \texttt{new}). Ein 2. Konstruktor, ohne Parameter, soll Stapel der Länge 1024 anlegen. Ein Destruktor soll den dynamische belegten Platz eines Stapels freigeben (Operator \texttt{delete}). Überprüfen Sie die Wirkung durch folgendes Experiment: Schreiben Sie eine rekursive Funktion \begin{quote} \begin{verbatim} void belege (int n) \end{verbatim} \end{quote} die einen Stapel der Größe 1024 als lokale Datenstruktur besitzt. Im Innern wird n um 1 vermindert (solange es ungleich Null ist). Anschließend ruft sich die Funktion selbst auf. Wenn n gleich Null ist, wird mit dem Systemaufruf \begin{quote} \begin{verbatim} system("free"); \end{verbatim} \end{quote} \index{UNIX!free} die augenblickliche Belegung des Hauptspeichers ausgegeben und die Funktion mit \texttt{return} beendet. Im Hauptprogramm wird vor und nach dem Aufruf von \texttt{belege(1024)} ebenfalls \verb'system("free")' aufgerufen (Prototyp in \verb'stdlib.h'). Der Vergleich der Speicherbelegungen sollte etwa 4 MByte ergeben (warum?). %%---------------------------------------------------------------------- %% Stapel-Objekte kopieren %%---------------------------------------------------------------------- \section{Stapel-Objekte kopieren} Schreiben Sie eine Komponentenfunktion \texttt{copy}, \begin{quote} \begin{verbatim} void copy ( const Stack &s ); \end{verbatim} \end{quote} die einen Stapel \texttt{s} (Aufrufargument) auf die Originalstruktur kopiert. Der zu kopierende Stapel wird als Referenz übergeben. Folgende Maßnahmen sind erforderlich: \begin{itemize} \item dynamisch belegtes Feld des Zielobjektes freigeben (\texttt{delete}), \item Feld gemäß Längenangabe von \texttt{s} im Zielobjekt neu belegen (\texttt{new}), \item Feldinhalt kopieren, \item die Datenelemente übernehmen. \end{itemize} Überprüfen Sie die Wirkung durch einen entsprechenden Test. Anmerkung: Die Funktion \texttt{copy} kann durch die Überladung des Zuweisungsoperators\index{Zuweisungsoperator} \texttt{=} ersetzt werden. %%---------------------------------------------------------------------- %% ÜBUNG : Klasse von Vektoren mit 3 Elementen %%---------------------------------------------------------------------- \chapter{Klasse von Vektoren mit 3 Elementen} \index{Vektor} Die Implementierung einer Klasse \texttt{Vek3} soll die wichtigsten Grundoperationen der Vektorarithmetik\index{Vektorarithmetik} für Vektoren der Länge 3 bereitstellen. \textbf{Datenelemente}: \begin{quote} \texttt{double}-Variablen \texttt{x, y, z} \end{quote} \textbf{Komponentenfunktionen}: \begin{tabular}{|c||p{14cm}|} \hline \textbf{Funktion}& \textbf{Beschreibung}\\ \hline \hline \texttt{Vek3}& 0 - 3 Komponente werden gesetzt (Ersatzwerte jeweils 0.0)\\ \hline \texttt{null}& alle Komponenten zu 0 setzen\\ \hline \texttt{e\_x}& Einheitsvektor\index{Einheitsvektor} in x-Richtung erzeugen\\ \hline \texttt{e\_y}& Einheitsvektor in y-Richtung erzeugen\\ \hline \texttt{e\_z}& Einheitsvektor in z-Richtung erzeugen\\ \hline \texttt{set\_x}& x-Komponente zuweisen\\ \hline \texttt{set\_y}& y-Komponente zuweisen\\ \hline \texttt{set\_z}& z-Komponente zuweisen\\ \hline \texttt{get\_x}& x-Komponente zurückgeben\\ \hline \texttt{get\_y}& y-Komponente zurückgeben\\ \hline \texttt{get\_z}& z-Komponente zurückgeben\\ \hline \texttt{norm}& Vektor auf die Länge 1.0 normieren\index{Vektor!normieren}\\ \hline \texttt{laenge}& Rückgabe der Vektorlänge\index{Vektor!Länge}\\ \hline & \textit{Die folgenden 3 Operationen verändern den eigenen Vektor und geben eine Referenz auf sich selbst zurück.}\\ \hline \texttt{plusgleich}& Vektoraddition\index{Vektor!Addition}\\ \hline \texttt{minusgleich}& Vektorsubtraktion\index{Vektor!Subtraktion}\\ \hline \texttt{mulgleich}& Multiplikation mit einem Skalar\index{Vektor!Multiplikation mit einem Skalar}\\ \hline & \textit{Die folgenden 3 Operationen erzeugen jeweils einen neuen Vektor und geben diesen zurück; der eigene Vektor bleibt unverändert.}\\ \hline \texttt{add}& Vektoraddition\\ \hline \texttt{sub}& Vektorsubtraktion\\ \hline \texttt{mul}& Multiplikation mit einem Skalar\\ \hline \texttt{skalarprodukt}& Skalarprodukt\index{Vektor!Skalarprodukt} zweier Vektoren\\ \hline \texttt{kreuzprodukt}& Kreuzprodukt\index{Vektor!Kreuzprodukt} zweier Vektoren (s.u.)\\ \hline \texttt{out}& einfache Ausgabefunktion\\ \hline \end{tabular} \begin{itemize} \item Alle Methoden sind in einem Hauptprogramm geeignet zu testen. \item Verwenden Sie die nachstehende Klassendefinition (Listing \ref{vek3-class}). \end{itemize} \lstset{language=C} \lstset{stepnumber=5} \lstinputlisting[caption={Definition der Klasse \texttt{Vek3}},label=vek3-class]{./programme/vek3-class.cc} %%---------------------------------------------------------------------- %% Berechnung des Kreuzproduktes %%---------------------------------------------------------------------- \section*{Berechnung des Kreuzproduktes} \index{Vektor!Kreuzprodukt} $$ \vec{a} \times \vec{b} = \left( \begin{array}{c} a_x \\ a_y \\ a_z \end{array} \right) \times \left( \begin{array}{c} b_x \\ b_y \\ b_z \end{array} \right) = \left( \begin{array}{c} a_y b_z - a_z b_y \\ a_z b_x - a_x b_z \\ a_x b_y - a_y b_x \end{array} \right) $$ %%---------------------------------------------------------------------- %% ÜBUNG : Überladen von Operatoren %%---------------------------------------------------------------------- \chapter{Überladen von Operatoren} \index{Operator} Die Klasse \texttt{Vek3} aus der vorhergehenden Übung soll nun mit Hilfe der Operatorüberladung\index{Operatorüberladung} so eingerichtet werden, daß die übliche mathematische Schreibweise für elementare Vektoroperationen möglich wird, also z.B.: \begin{quote} \begin{footnotesize} \begin{verbatim} double skprod; Vek3 u, v, w; u = Vek3( 1.0, 2.0, 3.0 ); // Anfangswerte u v = Vek3( -3.3, 2.5, 3.1 ); // Anfangswerte v w = 3.1*u + 23.4*v; // Vektorausdruck skprod = u*v; // Skalarprodukt w.norm(); // Vektor w normieren \end{verbatim} \end{footnotesize} \end{quote} Erzeugen Sie eine neue Version der Klasse \texttt{Vek3}, in der die Operatoren in den Tabellen \ref{cap:Zuweisungsoperatoren} und \ref{cap:friend-Funktionen} implementiert sind und testen Sie alle Operatoren. \begin{table}[h] \begin{onehalfspace} \begin{center}\begin{tabular}{|c|c|l|} \hline \textbf{Operator} & \textbf{1. Operand} & \textbf{Bemerkung} \\ \hline \hline \texttt{+} & & positives Vorzeichen\\ \hline \texttt{-} & & negatives Vorzeichen\\ \hline \texttt{+=} & \texttt{const Vek3 \&} & Vektoraddition mit Zuweisung\\ \hline \texttt{-=} & \texttt{const Vek3 \&} & Vektorsubtraktion mit Zuweisung\\ \hline \texttt{{*}=}& \texttt{double} & Streckung mit Zuweisung\\ \hline \texttt{/=} & \texttt{double} & Streckung mit Zuweisung\\ \hline \texttt{+} & \texttt{const Vek3 \&} & Vektoraddition\\ \hline \texttt{-} & \texttt{const Vek3 \&} & Vektorsubtraktion\\ \hline \texttt{/} & \texttt{double} & Streckung\\ \hline \end{tabular}\end{center} \caption{\label{cap:Zuweisungsoperatoren}Zuweisungsoperatoren der Klasse \texttt{Vek3}} \end{onehalfspace} \end{table} % \begin{table}[h] \begin{onehalfspace} \begin{center}\begin{tabular}{|c|c|c|c|} \hline \textbf{Operator}& \textbf{1. Operator} & \textbf{2. Operand} & \textbf{Bemerkung}\\ \hline \hline \texttt{{*}} & \texttt{const Vek3 \&} & \texttt{double} & Vektor{*}Skalar\\ \hline \texttt{{*}} & \texttt{double} & \texttt{const Vek3 \&} & Skalar{*}Vektor\\ \hline \texttt{{*}} & \texttt{const Vek3 \&} & \texttt{const Vek3 \&} & Skalarprodukt\\ \hline \texttt{<\,{}<} & \texttt{const Vek3 \&} & & Ausgabe\\ \hline \end{tabular}\end{center} \caption{\label{cap:friend-Funktionen}\texttt{friend}-Funktionen\index{friend-Funktionen} der Klasse \texttt{Vek3} } \end{onehalfspace} \end{table} %%---------------------------------------------------------------------- %% ÜBUNG : Vererbung %%---------------------------------------------------------------------- \chapter{Vererbung} %%---------------------------------------------------------------------- %% Implementierung der Klassen bahn und kbogen %%---------------------------------------------------------------------- \section{Implementierung der Klassen \texttt{bahn} und \texttt{kbogen}} Zur Implementierung der Klassen \texttt{bahn} und \texttt{kbogen} wird in dieser Übung die Klasse \texttt{Vek3} aus der vorhergehenden Übung benötigt. Erzeugen Sie zunächst aus der dort erstellten Lösung folgende Dateien: \begin{tabular}{lp{13cm}} \texttt{\textbf{vek3.h}}& header-Datei für die Klasse \texttt{Vek3}; enthält die Klassendefinition und \texttt{include}-Anweisungen für \texttt{iostream.h} und \texttt{math.h}\\ \texttt{\textbf{vek3.cc}}& Implementierung der Klasse \texttt{Vek3}; enthält am Anfang \verb'#include "vek3.h"' und anschließend die Implementierung der Methoden der Klasse \texttt{Vek3} .\\ \texttt{\textbf{praktikum-13-1.cc}}& Hauptprogramm zum Test der Klasse \texttt{Vek3}; enthält am Anfang \verb'#include "vek3.h"' und anschließend die Aufrufe und Testausgaben der Methoden der Klasse \texttt{Vek3} .\\ \end{tabular} Definieren und implementieren Sie danach die Klassen \texttt{bahn} und \texttt{kbogen} (s. Vorlesung): \begin{center}\begin{tabular}{|lll|} \hline \texttt{\textbf{bahn}}& \textbf{Datenkomponenten}& \texttt{pa}, \texttt{pe} Ortsvektoren; Anfangs- und Endpunkt der Bahn (Typ \texttt{Vek3})\\ & \textbf{Methoden}& Konstruktor ohne Parameter\\ & & Konstruktor mit 2 Vektoren als Parameter\\ & & Startpunkt setzen\\ & & Zielpunkt setzen\\ & & Länge berechnen\\ \hline \texttt{\textbf{kbogen}}& \textbf{Datenkomponenten}& pm Ortsvektor; mittlerer Bahnpunkt (Typ \texttt{Vek3})\\ & \textbf{Methoden}& Konstruktor ohne Parameter\\ & & Konstruktor mit 3 Vektoren als Parameter\\ & & mittleren Punkt setzen\\ & & Länge berechnen (vereinfacht als Summe der Länge der beiden Sehnen)\\ \hline \end{tabular}\end{center} Legen Sie im Hauptprogram \texttt{bahn}- und \texttt{kbogen}-Objekte mit und ohne Initialisierung an, berechnen Sie die Längen und geben Sie diese aus. Ergänzen Sie die Konstruktoren und die Längenberechnungen durch einfache Hilfsausgaben, die die jeweilige Funktion eindeutig benennen und kontrollieren Sie die Programmausgabe. %%---------------------------------------------------------------------- %% Initialisierungen mit Hilfe der Basisklassen-Konstruktoren %%---------------------------------------------------------------------- \section{Initialisierungen mit Hilfe der Basisklassen-Konstruktoren} Ändern Sie den parametrierten Konstruktor der abgeleiteten Klasse \texttt{kbogen} so ab, daß der Konstruktor der Basisklasse \texttt{bahn} für den Anfangs- und Endpunkt der Bahn verwendet wird. Verfolgen Sie die Aufrufreihenfolge mit Hilfe der oben eingerichteten Hilfsausgaben. %%---------------------------------------------------------------------- %% Implementierung der Klasse bahn als Basisklasse %%---------------------------------------------------------------------- \section{Implementierung der Klasse \texttt{bahn} als Basisklasse} \index{Basisklasse} Implementieren Sie die Klasse \texttt{bahn} als Basisklasse, die eine virtuelle Funktion\index{Funktion!virtuelle} \texttt{laenge()} enthält. \begin{itemize} \item Leiten Sie Klassen \texttt{gerade}, \texttt{kbogen} und \texttt{parabel} ab. \item Die Konstruktoren sollen den Konstruktor der Basisklasse \texttt{bahn} für die Anfangs- und Endpunkte verwenden. \item Die Funktionen zur Längenberechnung sollen jeweils überladen werden. \item Richten Sie entsprechende Objekte ein und verfolgen Sie die Aufrufe mittels Hilfsausgaben. \end{itemize} %%---------------------------------------------------------------------- %% Polymorphie %%---------------------------------------------------------------------- \section{Polymorphie} \index{Polymorphie} \begin{itemize} \item Richten Sie im Hauptprogramm ein Feld mit 100 Zeigern auf den Typ \texttt{bahn} ein: \\ \\ \verb'bahn *bz[100];'\\ \item Legen Sie im Hauptprogramm einige Teilbahnobjekte an (\texttt{gerade}, \texttt{kbogen}, \texttt{parabel}) und setzen Sie in das Feld \texttt{bz} fortlaufend Zeiger auf diese Objekte. \item Schreiben Sie nun eine Funktion \\ \\ \verb'double bahnlaenge ( bahn *bahnzeiger[], int n ) { ... } ' \\ \\ an die das Feld \texttt{bz} und die Anzahl der verzeigerten Elemente übergeben werden. Die Funktion soll die Summe der Längen aller Teilbahnen berechnen und über \texttt{return} zurückgeben. \end{itemize} %%---------------------------------------------------------------------- %% Absicherung einer Header-Datei gegen mehrfach-include %%---------------------------------------------------------------------- \section{Absicherung einer Header-Datei gegen mehrfach-\texttt{include}} Der gesamte Inhalt einer \texttt{h}-Datei\index{h-Datei} (außer dem Kommentar am Dateianfang) ist durch die folgende \texttt{if}-Anweisung (Präprozessor\index{Präprozessor}) gegen mehrfaches Einkopieren abzusichern: \begin{quote} \begin{verbatim} \#ifndef VEK3\_H // Name bekannt? \#define VEK3\_H // Name einrichten ... \#endif \end{verbatim} \end{quote} %%---------------------------------------------------------------------- %% Anhänge %%---------------------------------------------------------------------- \begin{appendix} %%---------------------------------------------------------------------- %% ANHANG : Editor %%---------------------------------------------------------------------- \chapter[Erstellen von Programmen]{Erstellen von Programmen \newline (Editieren, Compilieren, Binden)} \chaptermark{Erstellen von Programmen} \index{Editieren} \index{Compilieren} \index{Binden} \begin{figure}[h] \begin{center} \subfigure[\texttt{C-Run}]{\includegraphics[ scale=1.0]{./bilder/vim-5.eps}} \hspace{15mm} \subfigure[\texttt{Comments}]{\includegraphics[ scale=1.0]{./bilder/menu-comm.eps}} \hspace{15mm} \subfigure[\texttt{C-Statements}]{\includegraphics[ scale=1.0]{./bilder/menu-2.eps}} \end{center} \caption{\label{ABB:gvim-menu} GVIM : Menüs der C/C++-Unterstützung (Auswahl)} \end{figure} Zur Programmierung wird der sehr leistungsfähige Editor \index{Editor} \texttt{GVIM} \index{GVIM}verendet. Dieser Editor ist eine Weiterentwicklung des klassischen UNIX-Editors \texttt{vi}. \index{vi} Die nichtgraphische Version des \texttt{GVIM} heißt \texttt{VIM} \index{VIM}. Die Handhabung des Editors ist u.a. in den Büchern und Anleitungen beschrieben, die am Ende dieses Anhangs aufgeführt sind. \texttt{GVIM} kann als integrierte Entwicklungsumgebung (IDE) eingesetzt werden. Der Editor kann beliebig viele Dateien zum Editieren öffnen. Jede offene Datei wird in einem Editierpuffer gehalten (Das Menü \texttt{Buffers} ermöglicht die Navigation). Die Fenster können längs und quer geteilt werden. Das Menü \texttt{C-Run} (Abbildung \ref{ABB:gvim-menu}) ermöglicht die Compilierung des aktiven Puffers (Eintrag \texttt{save and compile}) mit Standardeinstellungen für den Compiler. Der Pufferinhalt wird vor der Übersetzung abgespeichert. Beim Auftreten von Übersetzungsfehlern wird ein Fehlerfenster geöffnet. Die fehlerhaften Code-Zeilen im Programmfenster können durch Auswahl der Fehlereinträge (Maus oder Richtungstasten) im Fehlerfenster angesprungen und berichtigt werden. Für Programme, die nur aus einer einzigen Datei bestehen, besteht die Möglichkeit, diese Datei nach dem Übersetzen zu binden (Menüeintrag \texttt{link}) und die Ausführung zu starten (Menüeintrag \texttt{run}). Dadurch kann die Erstellung eines \texttt{make}-Skriptes vermieden werden. Die Programmausgaben erscheinen in einer subshell im Editorfenster (Abb. \ref{ABB:vim-subshell} unten). Bei Anwahl des Menüpunktes \texttt{C-Run->link} wird der Pufferinhalt vor dem Binden übersetzt, wenn die evtl. vorhandene Object-Datei älter ist, als die vor dem Binden gerade gesicherte Quelldatei. Bei Anwahl des Menüpunktes \texttt{C-Run->run} wird der Pufferinhalt vor dem Starten des Programmes übersetzt und gebunden, wenn die evtl. vorhandene Object-Datei oder die ausführbare Datei älter ist, als die vor dem Starten gerade gesicherte Quelldatei. Für größere Projekte ist die Verwendung von \texttt{make}-Skripten \index{make} \index{UNIX!make} oder ähnlicher Werkzeuge erforderlich. Das \texttt{make}-Programm kann dann ebenfalls über das \texttt{C-Run}-Menü gestartet werden. Für Programme mit längeren Ausgaben ist der Aufruf mit Weiterleitung der Ausgaben durch einen pager (Programm zum Blättern in Dateien oder Konsolausgaben) vorgesehen. Die Hauptmenüeinträge \texttt{Comments}, \texttt{C-Statements} usw. erlauben das Einsetzen von vorbereiteten Kommentaren und von C- bzw. C++-Anweisungen (Abbildung \ref{ABB:gvim-menu}). Für einige der bei der Programmerzeugung häufig auszuführenden Tätigkeiten stehen Tastenkürzel zur Verfügung (s. Tab. \ref{TAB:gvim-tasten} ) \\ \\ %%+++++ TABLE : begin ++++++++++ \begin{table}[htbp] \begin{center} %%~~~~~ TABULAR : begin ~~~~~~~~~~ \begin{tabular}[]{|c|l|} \hline Tastenkombination& Wirkung\\ [0.0ex] \hline \hline F2 & Inhalt des aktiven Puffers sichern. \\ \hline F3 & Dialog zum Öffnen von Dateien aufrufen. \\ \hline F6 & Fehlerfenster öffnen. \\ \hline F7 & Zur Position des vorherigen Fehlers springen. \\ \hline F8 & Zur Position des nächsten Fehlers springen. \\ \hline Alt-F9 & Pufferinhalt abspeichern und danach den Pufferinhalt compilieren. \\ \hline F9 & Programm binden, ggf. vorher compilieren. \\ \hline Strg-F9 & Programm ausführen, ggf. vorher compilieren und binden. \\ \hline Shift-F9 & make aufrufen.\\ \hline \end{tabular} \\ [0.0ex] %%~~~~~ TABULAR : end ~~~~~~~~~~ \caption{ \label{TAB:gvim-tasten} GVIM : Die wichtigsten Tastenkombinationen der C/C++-Erweiterung} \vspace{ 5mm} \end{center} \end{table} %%+++++ TABLE : end ++++++++++ %%===== FIGURE : begin ========== \begin{figure}[htbp] \begin{center} \includegraphics[scale=0.9]{./bilder/run1.eps} \caption{ \label{ABB:vim-subshell} GVIM : Programmausgabe in einer subshell im Editorfenster } \vspace{ 5mm} \end{center} \end{figure} %%===== FIGURE : end ========== Der Editor VIM/GVIM ist ein leistungsstarker Programmiereditor für den Profi. Die Bedien- und Anwendungsmöglichkeiten sind entsprechend umfangreich. Neben der online-Hilfe und der Originaldokumentation stehen folgende Bücher und Anleitungen zur Verfügung: \begin{description} \item [Qualine, Steve ] Vi IMproved - Vim \footnote{mehrere Exemplare in der Bibliothek der FH SWF vorhanden}\\ New Riders Publishing, 2001, ISBN: 0735710015\\ oder unter http://vim.sourceforge.net/docs.php als PDF-Datei \item [Robbins, Arnold ] vi Editor kurz\&gut \footnotemark[1]\\ O'Reilly, 2000, ISBN 3-89721-213-7\\(Kurzanleitung, 63 Seiten, 2. Auflage) \item [Lamb, Linda / Robbins, Arnold ] Textbearbeitung mit dem vi-Editor \footnotemark[1]\\ O'Reilly, 1999, ISBN 3-89721-126-2\\(deutsche Übersetzung der 6. amerikanischen Auflage) \item [http://www.vim.org ] The VIM (Vi IMproved) Home Page\\ Homepage des Vim-Projektes; viele Verweise auf andere Seiten und auf Dokumentation. \item [http://vim.sourceforge.net ] Vim bei sourceforge\\ Vim-Skripte zur Erweiterung des Editors, Tips, Neuigkeiten, ... \end{description} %%---------------------------------------------------------------------- %% ANHANG : Testen von Programmen (Debugging) %%---------------------------------------------------------------------- \chapter[Testen von Programmen]{Testen von Programmen (Debugging)} \chaptermark{Testen von Programmen} \index{Testen} \index{Debugging} %%===== FIGURE : begin ========== \begin{figure}[htbp] \begin{center} \includegraphics[scale=0.9]{./bilder/ddd.eps} \caption{ \label{ABB:DDD} Der Debugger \texttt{DDD} } \vspace{ 5mm} \end{center} \end{figure} %%===== FIGURE : end ========== Zum Testen von Programmen kann der Debugger \texttt{DDD} \index{DDD} verwendet werden. Das zu testende Programm muß dazu als ausführbare Datei vorliegen, d.h. es muß übersetzt und gebunden sein und enthält damit keine syntaktischen Fehler mehr. Der DDD kann über das Symbol auf der Arbeitsfläche gestartet werden. Im Dialog wird das zu testende und ausführbare Programm geöffnet. Die zugehörige Quelldatei erscheint nun im Quelltextfenster (Abb. \ref{ABB:DDD} ). Außerdem erscheint im Quelltextfenster das frei verschiebbare Kommandofenster. \newpage %%===== FIGURE (floating) : begin ========== \begin{floatingfigure}[r]{70mm} \begin{center} \subfigure[Haltepunktmenü] { \includegraphics[ ]{./bilder/ddd-breakpoint-menu.eps} } \subfigure[Kommandomenü] { \includegraphics[ ]{./bilder/ddd-menu.eps} } \caption{ \label{ABB:DDD-menu} DDD : Haltepunktmenü und Kommandomenü} \end{center} \end{floatingfigure} %%===== FIGURE (floating): end ========== \textbf{Haltepunkte (breakpoints).} \index{Haltepunkt} \index{breakpoint} Setzt man die Schreibmarke an den Anfang einer ausführbaren Quellcodezeile und betätigen die rechte Maustaste, dann erscheint das Haltepunktmenü (Abb. \ref{ABB:DDD-menu}a). Die erste Auswahl (\texttt{Set Breakpoint}) setzt einen festen Haltepunkt. Der zweite Eintrag (\texttt{Set Temporary Breakpoint}) setzt einen Haltepunkt, der nach dem Erreichen wieder gelöscht wird. Der dritte Eintrag (\texttt{Continue Until Here}) ermöglicht die Programmausführung oder -weiterführung bis zu der Zeile vor der Schreibmarke. \\ \textbf{Programm schrittweise testen.} Durch die Anwahl des Eintrages \texttt{Run} im Kommandomenü (Abb. \ref{ABB:DDD-menu}b) wird das Programm gestartet und bis zur letzten ausführbaren Programmanweisung \textit{vor} dem Haltepunkt ausgeführt. Die erreichet Stelle wird durch einen roten Pfeil gekennzeichnet (Abb. \ref{ABB:DDD}). Mit Hilfe der anderen Möglichkeiten des Kommandomenüs kann das Programm Zeile für Zeile ausgeführt werden (Tab. \ref{TAB:DDD-Kommandomenü}). Nach jedem Schritt können dann z.B. Variablenwerte angesehen oder verändert werden. \vspace{ 5mm} %%+++++ TABLE : begin ++++++++++ \begin{table}[htbp] \begin{center} %%~~~~~ TABULAR : begin ~~~~~~~~~~ \begin{tabular}[]{|p{4cm}|p{12cm}|} \hline Haltepunkt setzen & - Cursor am Anfang der gewünschten Zeile positionieren \newline - rechte Maustaste niederhalten (Haltepunktmenü) \newline - \texttt{Set Breakpoint} oder \texttt{Delete Breakpoint} wählen \newline - am Zeilenanfang erscheint ein Stop-Schild \\ \hline Haltepunkt löschen & - Cursor über dem Stop-Schild positionieren \newline - rechte Maustaste niederhalten (Haltepunktmenü) \newline - \texttt{Delete Breakpoint} wählen \\ \hline Programm bis zum \newline Haltepunkt ausführen & - Menüeintrag \texttt{Run} wählen\\ \hline Wert einer Variable \newline ansehen & - Mauszeiger im Quelltextfenster über dem Variablennamen positionieren\\ \hline Datenelement im \newline Datenfenster anzeigen & - Mauszeiger im Quelltextfenster über dem Namen positionieren \newline - rechte Maustaste niederhalten (Display-Menü erscheint) \newline - \texttt{Display} wählen\newline - im Datenfenster erscheint die entsprechende Anzeige\\ \hline Datenelement im \newline Datenfenster erweitern & Bei Strukturen, Feldern, komplexen Objekten usw. kann \newline die Darstellung erweitert oder zusammengefaßt werden:\newline - Mauszeiger im Datenfenster über dem Datenelement positionieren \newline - rechte Maustaste niederhalten (Menü) \newline - \texttt{Show All} oder \texttt{Hide All} wählen\\ \hline \end{tabular} \\ [0.0ex] %%~~~~~ TABULAR : end ~~~~~~~~~~ \caption{ \label{TAB:DDD-Bedienung} DDD : Grundlegende Bedienung } \end{center} \end{table} %%+++++ TABLE : end ++++++++++ %%+++++ TABLE : begin ++++++++++ \begin{table}[htbp] \begin{center} %%~~~~~ TABULAR : begin ~~~~~~~~~~ \begin{tabular}[]{|l|l|} \hline Run & Starte das zu testende Programm \\ \hline Interrupt & Unterbreche das zu testende Programm \\ \hline Step & eine Zeile weiter (bei Unterprogammaufrufen wird in das Unterprogramm gesprungen) \\ \hline Next & eine Zeile weiter (bei Unterprogammaufrufen wird der Aufruf übersprungen) \\ \hline Until & Programm bis zur nächsten ausführbaren Zeile fortsetzen (zeilenweise Ausführung) \\ \hline Cont & Programm nach einem Haltepunkt fortsetzen \\ \hline Kill & Programm abbrechen \\ \hline \end{tabular} \\ [0.0ex] %%~~~~~ TABULAR : end ~~~~~~~~~~ \caption{ \label{TAB:DDD-Kommandomenü} DDD : Die Befehle des Kommandomenüs } \end{center} \end{table} %%+++++ TABLE : end ++++++++++ Der Debugger DDD ist äußerst leistungsfähig und steht für mehrere Rechnerplattformen zur Verfügung. Eine umfassendere Darstellung würde den Rahmen an dieser Stelle sprengen. Alles weitere muß der Originaldokumentation entnommen werden. \end{appendix} %%---------------------------------------------------------------------- %% Buchnachspann %%---------------------------------------------------------------------- \backmatter %%====================================================================== %% Stichwortverzeichnis %%====================================================================== \cleardoublepage \addcontentsline{toc}{chapter}{Stichwortverzeichnis} \printindex{} \end{document} %%%%%%%%%%%%%%%%%%%%%% LATEX-Dokument -- ENDE %%%%%%%%%%%%%%