This repository has been archived on 2021-05-17. You can view files and clone it, but cannot push or open issues or pull requests.
scientificComputing/programming/lectures/programming.tex

1298 lines
48 KiB
TeX

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{\tr{Programming basics}{Programmierung in \matlab}}
\section{Variablen und Datentypen}
\subsection{Variablen}
Eine Variable ist ein Zeiger auf eine Stelle im Speicher. Dieser
Zeiger hat einen Namen, den Variablennamen, und einen Datentyp
(Abbildung \ref{variablefig}). Im Speicher wird der Wert der Variablen
bin\"ar gespeichert. Wird auf den Wert der Variable zugegriffen, wird
dieses Bitmuster je nach Datentyp interpretiert. Das Beispiel in
Abbildung \ref{variablefig} zeigt, dass das gleiche Bitmuster im einen
Fall als 8-Bit Integer Datentyp zur Zahl 38 interpretiert wird und im
anderen Fall als Character zum kaufm\"annischen ``und'' ausgewertet
wird. In \matlab{} sind Datentypen nicht von sehr zentraler
Bedeutung. Wir werden uns dennoch sp\"ater etwas genauer mit ihnen
befassen.
\begin{figure}
\centering
\begin{subfigure}{.5\textwidth}
\includegraphics[width=0.8\textwidth]{variable}
\label{variable:a}
\end{subfigure}%
\begin{subfigure}{.5\textwidth}
\includegraphics[width=.8\textwidth]{variableB}
\label{variable:b}
\end{subfigure}
\caption{\textbf{Variablen.} Variablen sind Zeiger auf eine Adresse
im Speicher, die einen Namen und einen Datentypen beinhalten. Im
Speicher ist der Wert der Variable bin\"ar gespeichert. Abh\"angig
vom Datentyp wird dieses Bitmuster unterschiedlich
interpretiert.}\label{variablefig}
\end{figure}
\subsection{Erzeugen von Variablen}
In \matlab{} kann eine Variable auf der Kommandozeile, in einem Skript
oder einer Funktion an beliebiger Stelle erzeugen. Das folgende
Listing zeigt zwei M\"oglichkeiten:
\begin{lstlisting}[label=varListing1, caption=Erzeugen von Variablen]
>> y = []
y =
[]
>>
>> x = 38
x =
38
\end{lstlisting}
Die Zeile 1 kann etwa so gelesen werden:''Erzeuge eine Variable mit
dem Namen y und weise ihr einen leeren Wert zu.'' Das
Gleichheitszeichen ist der sogenannte
\emph{Zuweisungsoperator}. Zeile 5 definiert eine Variable x, der
nun der Zahlenwert 38 zugewiesen wird. Da \matlab{}, wenn nicht anders
angegeben immer den ``double'' Datentypen benutzt, haben beide
Variablen diesen Datentyp.
\begin{lstlisting}[label=varListing2, caption={Erfragen des Datentyps einer Variable, Listen aller definierten Variablen.}]
>>disp(class(x))
double
>>
>> who % oder whos um mehr Information zu bekommen
\end{lstlisting}
Bei der Namensgebung ist zu beachten, dass \matlab{} auf Gro{\ss}- und
Kleinschreibung achtet und ein Variablennane mit einem alphabethischen
Zeichen beginnen muss. Des Weiteren sind Umlaute, Sonder- und
Leerzeichen in Variablennamen nicht erlaubt.
\subsection{Arbeiten mit Variablen}
Nat\"urlich kann mit den Variablen auch gearbeitet, bzw
gerechnet werden. \matlab{} kennt alle normalen arithmetischen Operatoren wie
\code{+, -, *. /}. Die Potenz wird \"uber das Dach Symbol \code{\^}
dargestellt. Das folgende Listing zeigt, wie sie benutzt werden.
\begin{lstlisting}[label=varListing3, caption={Rechnen mit Variablen.}]
>> x = 1;
>> x + 10
ans =
11
>>
>> x % x wurde nicht veraendert
ans =
1
>>
>> y = 2;
>>
>> x + y
ans =
3
>>
>> z = x + y
z =
3
>>
>> z = z * 5;
>> z
z =
15
>>
>> clear z
\end{lstlisting}
Beachtenswert ist z.B. in Zeilen 3 und 6, dass wir mit dem Inhalt
einer Variablen rechnen k\"onnen, ohne dass dadurch ihr Wert
ver\"andert wird. Wenn der Wert einer Variablen ver\"andert werden
soll, dann muss dieser der Variable explizit zugewiesen werden (mit
dem \code{=} Zuweisungsoperator, z.B. Zeilen 16, 20). Zeile 25 zeigt
wie eine einzelne Variable gel\"oscht wird.
\subsection{Datentypen}
Der Datentyp bestimmt, wie die im Speicher abgelegten Bitmuster
interpretiert werden. Die wichtigsten Datentpyen sind folgende:
\begin{itemize}
\item \textit{integer} - Ganze Zahlen. Hier gibt es mehrere
Unterarten, die wir in \matlab{} (meist) ignorieren k\"onnen.
\item \textit{double} - Flie{\ss}kommazahlen. Im Gegensatz zu den reelen Zahlen, die durch diesen Datentyp dargestellt werden, sind sie abz\"ahlbar.
\item \textit{complex} - Komplexe Zahlen.
\item \textit{logical} - Boolesche Werte, die als wahr
(\code{true}) oder falsch (\code{false}) interpretiert werden.
\item \textit{char} - ASCII Zeichen
\end{itemize}
Unter den numerischen Datentypen gibt es verschiedene Arten mit
unterschiedlichem Speicherbedarf und Wertebreich.
\begin{table}[]
\centering
\caption{Grundlegende Datentypen und ihr Wertebereich.}
\label{dtypestab}
\begin{tabular}{llcl}\hline
Datentyp & Speicherbedarf & Wertebereich & Beispiel \rule{0pt}{2.5ex} \\ \hline
double & 64 bit & $\approx -10^{308}$ bis $\approx 10^{308} $& Flie{\ss}kommazahlen.\rule{0pt}{2.5ex}\\
int & 64 bit & $-2^{31}$ bis $2^{31}-1$ & Ganzzahlige Werte \\
int16 & 16 bit & $-2^{15}$ bis $2^{15}-1$ & Digitalisierte Spannungen. \\
uint8 & 8 bit & $0$ bis $255$ & Digitalisierte Imaging Daten. \\ \hline
\end{tabular}
\end{table}
\matlab{} arbeitet meist mit dem ``double'' Datentyp wenn numerische
Daten gespeichert werden. Dennoch lohnt es sich, sich ein wenig mit
den Datentypen auseinanderzusetzen. Ein Szenario, dass in der
Neurobiologie nicht selten ist, ist, dass wir die elektrische
Aktivit\"at einer Nervenzelle messen. Die gemessenen Spannungen werden
mittels Messkarte digitalisiert und auf dem Rechner
gespeichert. Typischerweise k\"onnen mit solchen Messkarten Spannungen
im Bereich $\pm 10$\,V gemessen werden. Die Aufl\"osung der Wandler
betr\"agt heutzutage meistens 16 bit. Das heisst, dass der gesamte
Spannungsbereich in $2^{16}$ Schritte aufgeteilt ist. Um Speicherplatz
zu sparen w\"are es sinnvoll, die gemessenen Daten als ``int16'' Werte im
Rechner abzulegen. Die Daten als ``echte'' Spannungen, also als
Flie{\ss}kommawerte, abzulegen w\"urde den 4-fachen Speicherplatz
ben\"otigen.
\section{Vektoren und Matrizen}
Vektoren und Matrizen sind die wichtigsten Datenstrukturen in
\matlab{}. In anderen Programmiersprachen heissen sie ein-
bzw. mehrdimensionalen Felder. Felder sind Datenstrukturen, die
mehrere Werte des geleichen Datentyps in einer Variablen vereinen. Da
\matlab{} seinen Ursprung in der Verarbeitung von mathematischen
Vektoren und Matrizen hat, werden sie hier auch so genannt. \matlab{}
macht keinen Unterschied zwischen Vektoren und Matrizen. Vektoren
sind 2--dimensionale Matrizen bei denen eine Dimension die Gr\"o{\ss}e
1 hat.
\subsection{Vektoren}
Im Gegensatz zu Variablen, die einzelene Werte beinhalten
(Skalare), kann ein Vektor mehrere Werte des gleichen Datentyps
beinhalten (Abbildung \ref{vectorfig} B). Die Variable ``test''
enth\"alt in diesem Beispiel vier ganzzahlige Werte.
\begin{figure}
\includegraphics[width=0.8\columnwidth]{scalarArray}
\caption{\textbf{Skalare und Vektoren. A)} Eine skalare Variable kann
genau einen Wert tragen. \textbf{B)} Ein Vektor kann mehrer
Werte des gleichen Datentyps (z.B. ganzzahlige Integer Werte)
beinhalten. \matlab{} kennt den Zeilen- (row-) und Spaltenvektor
(columnvector).}\label{vectorfig}
\end{figure}
Das folgende Listing zeigt, wie einfache Vektoren erstellt werden
k\"onnen.
\begin{lstlisting}[label=arrayListing1, caption={Erstellen einfacher Zeilenvektoren.}]
>> a = [0 1 2 3 4 5 6 7 8 9] % Erstellen eines Zeilenvektors
a =
0 1 2 3 4 5 6 7 8 9
>>
>> b = (0:9) % etwas bequemer
b =
0 1 2 3 4 5 6 7 8 9
>>
>> c = (0:2:10)
c =
0 2 4 6 8 10
\end{lstlisting}
Die L\"ange eines Vektors, d.h. die Anzahl der Elemente des Vektors,
kann mithilfe der Funktion \code{length()} bestimmt werden. \"Ahnliche
Information kann \"uber die Funktion \code{size()} erhalten werden. Im
Falle des Vektors \code{a} von oben erh\"alt man folgende Ausgabe:
\begin{lstlisting}[label=arrayListing2, caption={Gr\"o{\ss}e von Vektoren.}]
>> length(a)
ans =
10
>> size(a)
ans =
1 10
\end{lstlisting}
Diese Ausgabe zeigt, dass Vektoren im Grunde 2-dimensional sind. Bei
einem Zeilenvektor hat die erste Dimension die Gr\"o{\ss}e
1. \code{length(a)} gibt die l\"angste Ausdehnung an.
\begin{lstlisting}[label=arrayListing3, caption={Spaltenvektoren.}]
>> b = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] % Erstellen eines Spaltenvektors
b =
1
2
...
9
10
>> length(b)
ans =
10
>> size(b)
ans =
10 1
>> b = b'; % Transponieren
>> size(b)
ans =
1 10
\end{lstlisting}
Der \code{'}- Operator transponiert den Spaltenvektor zu einem
Zeilenvektor.
\subsubsection{Zugriff auf Inhalte von Vektoren}
\begin{figure}
\includegraphics[width=0.4\columnwidth]{arrayIndexing}
\caption{\textbf{Indices von Vektoren.} Jedes Feld eines Vektors hat
einen Index mit dem auf den jeweiligen Inhalt zugegriffen werden
kann.}\label{vectorindexingfig}
\end{figure}
Der Zugriff auf die Inhalte eines Vektors erfolgt \"uber den Index
(Abbildung \ref{vectorindexingfig}). Jedes Feld in einem Vektor hat
einen fortlaufenden \textit{Index}, \"uber den auf die Werte des
Vektors zugegriffen werden kann. Dabei spielt es keine Rolle, ob es
sich um einen Zeilen- oder Spaltenvektor handelt. \textbf{Achtung!}
Anders als viele andere Sprachen beginnt \matlab{} mit dem Index
1. Die Listings \ref{arrayListing4} und \ref{arrayListing5} zeigen wie
mit Indexen auf die Inhalte eines Vektors zugegriffen werden kann.
\begin{lstlisting}[label=arrayListing4, caption={Zugriff auf den Inhalt von Vektoren I}]
>> a = (11:20);
>> a(1) % das 1. Element
ans =
11
>> a(5) % das 5. Element
ans =
15
>> a(end) % das letzte Element
ans =
20
\end{lstlisting}
Hierbei kann auf einzelne Werte zugegriffen werden oder, analog zur
Erzeugung von Vektoren, die \code{:} Notation verwendet werden, um auf mehrere
Element gleichzeitig zuzugreifen.
\begin{lstlisting}[caption={Zugriff auf den Inhalt von Vektoren I}, label=arrayListing5]
>> a([1 3 5]) % das 1., 3. und 5. Element
ans =
11 13 15
>> a(2:4) % alle Elemente von Index 2 bis einschliesslich 4
ans =
12 13 14
>> a(1:2:end) %jedes zweite Element
ans =
11 13 15 17 19
\end{lstlisting}
\begin{exercise}{vectorsize.m}{vectorsize.out}
Der R\"uckgabewert von \code{size(a)} ist wieder ein Vektor der
L\"ange 2. Wie k\"onnte man also die Gr\"o{\ss}e von \code{a} in der
zweiten Dimension herausfinden?
\end{exercise}
\subsubsection{Operationen auf Vektoren}
Mit Vektoren kann sehr einfach gerechnet werden. Listing
\ref{arrayListing6} zeigt Rechnungen mit Vektoren.
\begin{lstlisting}[caption={Rechnen mit Vektoren.},label=arrayListing6]
>> a = (0:2:8);
>> a + 5 % addiere einen Skalar
ans =
5 7 9 11 13
>> a - 5 % subtrahiere einen Skalar
ans =
-5 -3 -1 1 3
>> a .* 2 % Multiplication
ans =
0 4 8 12 16
>> a ./ 2 % Division
ans =
0 1 2 3 4
>> a(1:3) + a(2:4) % Addieren von 2 Vektoren
ans =
2 6 10
>>
>> a(1:2) + a(2:4) % Vektoren muessen gleich gross sein!
??? Error using ==> plus
Matrix dimensions must agree.
\end{lstlisting}
Wird ein Vektor mit einem skalaren Wert verrechnet, dann ist das
problemlos m\"oglich. Bei der Multiplikation (Zeile 10), der Division
(Zeile 14) und auch der Potenzierung mu{\ss} mit vorangestellem '.'
klar gemacht werden, dass es sich um eine \emph{elementweise}
Verarbeitung handeln soll. F\"ur diese elementweisen Operationen kennt
\matlab{} die Operatoren \code{.*}, \code{./} und \code{.\^}. Die
einfachen Operatoren \code{*}, \code{/} und \code{\^} sind mit den
entsprechenden Matrixoperationen aus der linearen Algebrar belegt
(s.u.).
Zu Beachten ist des Weiteren noch die Fehlermeldung am Schluss von
Listing \ref{arrayListing6}. Wenn zwei Vektoren (elementweise)
miteinander verrechnet werden sollen, muss nicht nur die Anzahl der Elemente
übereinstimmen, sondern es muss auch das Layout (Zeilen- oder
Spaltenvektoren) \"ubereinstimmen.
Will man Elemente aus einem Vektor entfernen, dann weist man den
entsprechenden Zellen einen leeren Wert (\code{[]}) zu.
\begin{lstlisting}[label=arrayListing7, caption={L\"oschen von Elementen aus einem Vektor.}]
>> a = (0:2:8);
>> length(a)
ans =
5
>> a(1) = [] % loesche das erste Element
a = 2 4 6 8
>> a([1 3]) = []
a = 4 8
>> length(a)
ans =
2
\end{lstlisting}
Neben dem L\"oschen von Vektorinhalten k\"onnen Vektoren auch
erweitert oder zusammengesetzt werden. Auch hier muss das Layout der Vektoren
\"ubereinstimmen (Listing \ref{arrayListing8}, Zeile 12). Will man
einen Vektor erweitern, kann man \"uber das Ende hinaus
zuweisen. \matlab{} erweitert dann die Variable. Auch hierbei muss auf
das Layout geachtet werden. Zudem ist dieser Vorgang
``rechenintensiv'' und sollte soweit m\"oglich vermieden werden.
\begin{lstlisting}[caption={Zusammenf\"ugen und Erweitern von Vektoren.}, label=arrayListing8]
>> a = (0:2:8);
>> b = (10:2:19);
>> c = [a b] % erstelle einen Vektor aus einer Liste von Vektoren
c =
0 2 4 6 8 10 12 14 16 18
>> length(c)
ans =
10
>> length(a) + length(b)
ans =
10
>> c = [a b'];
Error using horzcat
Dimensions of matrices being concatenated are not consistent.
>> b(6:8) = [1 2 3 4];
\end{lstlisting}
\subsection{Matrizen}
Im Gegesatz zu den 1-dimensionalen Vektoren k\"onnen Martizen
n-dimensional sein, das hei{\ss}t, dass sie beliebig viele Dimensionen
haben k\"onnen. Von praktischer Bedeutung sind allerdings nur Matrizen
mit bis zu vier Dimensionen. Meist beschr\"ankt es sich jedoch auf 2-
bis 3-d Matrizen (Abbildung \ref{matrixfig} A,B).
\begin{figure}
\includegraphics[width=0.5\columnwidth]{matrices}
\caption{\textbf{Matrizen. A)} Eine Variable (``test'') die eine
2-dimensionale Matrize ist. \textbf{B)} Illustration einer
3-dimensionalen Matrize. Die Pfeile zeigen den Rang der
Dimensionen an.}\label{matrixfig}
\end{figure}
Erzeugt werden Matrizen sehr \"ahnlich zu den Vektoren (Listing
\ref{matrixListing}). Die Definition einer Matrize wird, wie beim
Vektor, durch \code{[]} eingeschlossen. Das \code{;} trennt die
einzelnen Zeilen der Matrize.
\begin{lstlisting}[label=matrixListing, caption={Erzeugen von Matrizen.}]
>> a = [1 2 3; 4 5 6; 7 8 9]
>> a =
1 2 3
4 5 6
7 8 9
>>
>> b = ones(3,3,2);
>> b
b(:,:,1) =
1 1 1
1 1 1
1 1 1
b(:,:,2) =
1 1 1
1 1 1
1 1 1
\end{lstlisting}
Zur Defintion von mehr-dimensionalen Matrizen ist die Notation in
Zeile 1 nicht geeignet. Es gibt allerdings eine Reihe von
Helferfunktionen, die n-dimensionale Matrizen erstellen k\"onnen
(z.B. \code{ones}, Zeile 7). Sollte sich die Notwendigkeit ergeben
mehrdimensionale Matrizen zusammenzuf\"ugen hilft die \code{cat}
Funktion.
Um Informationen \"uber die Gr\"{\ss}e einer Matrize zu bekommen ist
die Funktion \code{length} nicht geeignet. Wie oben erw\"ahnt gibt sie
die Gr\"o{\ss}e der l\"angsten Dimension aus. Wann immer es um
Matrizen geht, wird \code{size} benutzt.
\begin{figure}
\includegraphics[width=0.9\columnwidth]{matrixIndexing}
\caption{\textbf{Indices von Matrizen.} Jedes Feld einer Matrize
wird durch einen Index individuell angesprochen. Der Index setzt
sich aus so vielen Zahlen zusammen wie es Dimensionen gibt (links
2, rechts 3). Dabei steht die 1. Stelle immer f\"ur die Zeile, die
2. f\"uer die Spalte und die dritte f\"ur das Blatt,
etc.. }\label{matrixindexingfig}
\end{figure}
Der Zugriff auf Inhalte von Matrizen erfolgt \"uber den Index
(Abbildung \ref{matrixindexingfig}, Listing
\ref{matrixIndexing}). \"Ahnlich zu den Positionen in einem
Koordinatensystem wird jede Zelle einer Matrize mit einem Index
angesprochen, der aus $n$ Zahlen besteht wobei $n$ die
Dimensionalit\"at der Matrize ist. Diese Art des Zugriffs wird
\textit{subsript indexing} genannt.
\begin{lstlisting}[caption={Zugriff auf Inhalte von Matrizen,
Indexierung.}, label=matrixIndexing]
>> x = randi(100, [3, 4, 5]); % 3-D Matrix mit Zufallszahlen
>> size(x)
ans =
3 4 5
>> x(1,1,1); % obere linke Ecke
ans(1,1,1) =
14
>>
>> x(1,1,:) % obere linke Ecke entlang der 3. Dimension
ans(1,1,:) =
14
ans(:,:,2) =
58
ans(:,:,3) =
4
ans(:,:,4) =
93
ans(:,:,5) =
56
\end{lstlisting}
Alternativ zum \textit{subscript indexing} k\"onnen die Zellen einer
Matrize auch \textit{linear} angesprochen werden (Abbildung
\ref{matrixlinearindexingfig}). Diese Art der Adressierung ist nicht
so intuituiv verst\"andlich, kann aber sehr hilfreich sein. Der
``linare'' Index einer Zelle reicht von 1 bis \code{numel(M)}
Elemente. Wobei dieser erst entlang der 1. Dimension, dann der 2.,
3. etc. Dimension ansteigt. Listing \ref{matrixLinearIndexing} zeigt
ein Beispiel fuer den Einsatz des linearen Indexierens z.B. wenn man
den Minimalwert aller Elemente einer Matrize ermitteln m\"ochte..
\begin{figure}
\includegraphics[width=0.9\columnwidth]{matrixLinearIndexing}
\caption{\textbf{Lineares Indexieren von Matrizen.} Der Index steigt
linear von 1 bis zur Anzahl Elemente in der Matrize an. Dabei
steigt der Index zuerst entlang der ersten, zweiten, dritten und
weiterer Dimensionen an.}\label{matrixlinearindexingfig}
\end{figure}
\begin{lstlisting}[label=matrixLinearIndexing, caption={Lineares Indexieren in Matrizen.}]
>> x = randi(100, [3, 4, 5]); % 3-D Matrix mit Zufallszahlen
>> size(x)
ans =
3 4 5
>> numel(x)
ans =
60
>> min(min(min(x))) % Minumum uber die Zeilen, Spalten, Blaetter...
ans =
4
>> min(x(:)) % oder so
ans =
4
\end{lstlisting}
Beim Rechnen mit Matrizen gelten die gleichen Regeln wie bei
Vektoren. Matrizen k\"onnen solange elementweise miteinander
Verrechnet werden, wie die Dimensionalit\"aten
\"ubereinstimmen. Besondere Vorsicht sollte man immer dann walten
lassen, wenn man Matrizen miteinander mulitplizieren, dividieren oder
potenzieren will. Hier ist es wichtig sich klarzumachen was man will:
Eine elementweise Multiplikation (\code{.*} Operator, Listing
\ref{matrixOperations} Zeile 18) oder ob eine Matrixmultiplikation
(\code{*} Operator, Listing \ref{matrixOperations} Zeile 12)
durchgef\"uhrt werden soll.
\begin{lstlisting}[label=matrixOperations, caption={Zwei Arten von Multiplikationen auf Matrizen.}]
>> A = randi(10, [3, 3]) % 2-D Matrix
A =
3 8 2
2 10 3
10 7 1
>> B = randi(10, [3, 3]) % dto
B =
2 1 7
1 5 9
5 10 5
>>
>> A * B % Matrix Multiplikation
ans =
24 63 103
29 82 119
32 55 138
>>
>> A .* B % Elementweise Multiplikation
ans =
6 8 14
2 50 27
50 70 5
>>
\end{lstlisting}
\section{Boolesche Operationen}
Boolesche Ausdr\"ucke sind Anweisungen, die zu \emph{wahr} oder
\emph{falsch} ausgewertet werden. Man kennt sie z.B. aus der
Mengenlehre. In der Programmierung werdens sie eingesetzt, um z.B. die
Beziehung zwischen Entit\"aten zu testen. Hierzu werden die
\emph{relationalen Operatoren} (\code{>}, \code{<}, \code{==},
\code{!}, gr\"o{\ss}er als, kleiner als, gleich und nicht)
eingesetzt. Mehrere Ausdr\"ucke werden mittels der \textit{logischen
Operatoren} (\code{\&}, \code{|}, UND, ODER ) verkn\"upft. Sie sind f\"ur
uns nicht nur wichtig um Codeabschnitte bedingt auszuf\"uhren
(Verzweigungen, \ref{controlstructsec}) sondern auch um aus Vektoren
und Matrizen bequem Elemente auszuw\"ahlen (logisches Indizieren,
\ref{logicalindexingsec}). Die folgenden Tabellen zeigen die
Wahrheitstabellen f\"ur das logische UND (\ref{logicalandor}, links)
aund das logische ODER (\ref{logicalandor}, rechts). Es werden die
Aussagen A und B mit dem Operator verkn\"upft. Beim logischen UND ist
der gesamte Ausdruck nur dann wahr, wenn beide Ausdr\"ucke sich zu
wahr auswerten lassen.
\begin{table}[tp]
\caption{Wahrheitstabellen logisches UND (links) und logisches ODER (rechts).}\label{logicalandor}
\begin{minipage}[t]{0.4\textwidth}
\begin{tabular}{llll}
\multicolumn{2}{l}{\multirow{2}{*}{}} & \multicolumn{2}{c}{\textbf{B}} \\
\multicolumn{2}{l}{} & \multicolumn{1}{|c|}{wahr} & falsch \\ \cline{2-4}
\multirow{2}{*}{\textbf{A}} & \multicolumn{1}{l|}{wahr} & \multicolumn{1}{c|}{\textcolor{mygreen}{wahr}} & \textcolor{red}{falsch} \\ \cline{2-4}
& \multicolumn{1}{l|}{falsch} & \multicolumn{1}{l|}{\textcolor{red}{falsch}} & \textcolor{red}{falsch}
\end{tabular}
\end{minipage}
\begin{minipage}[t]{0.4\textwidth}
\begin{tabular}{llll}
\multicolumn{2}{l}{\multirow{2}{*}{}} & \multicolumn{2}{c}{\textbf{B}} \\
\multicolumn{2}{l}{} & \multicolumn{1}{|c|}{wahr} & falsch \\ \cline{2-4}
\multirow{2}{*}{\textbf{A}} & \multicolumn{1}{l|}{wahr} & \multicolumn{1}{c|}{\textcolor{mygreen}{wahr}} & \textcolor{mygreen}{wahr} \\ \cline{2-4}
& \multicolumn{1}{l|}{falsch} & \multicolumn{1}{l|}{\textcolor{mygreen}{wahr}} & \textcolor{red}{falsch}
\end{tabular}
\end{minipage}
\end{table}
Anders ist das beim logischen ODER. Hier ist der gesamte
Ausdruck wahr, wenn sich der eine \emph{oder} der andere Ausdruck zu
wahr auswerten l\"a{\ss}t. Tabelle \ref{logicaloperators} zeigt die
logischen Operatoren, die in \matlab{} definiert sind. Zu bemerken
sind hier noch die \code{\&\&} und \code{||} Operatoren. Man kann
beliebige Ausdr\"ucke verkn\"upfen und h\"aufig kann schon anhand des
ersten Ausdrucks entschieden werden, ob der gesamte Boolesche Ausdruck
zu wahr oder falsch ausgewertet werden wird. Wenn zwei Aussagen mit
einem UND verkn\"upft werden und der erste zu falsch ausgewerte wird,
dann muss der zweite gar nicht mehr gepr\"uft werden. Die Verwendung
der ``short-circuit'' Versionen spart Rechenzeit. Das auschliessende
ODER (XOR) ist in \matlab{} nur als Funktion \code{xor(A, B)}
verf\"ugbar.
\begin{table}[th]
\caption{\label{logicaloperators}
\textbf{Logische Operatoren in \matlab.}}
\begin{center}
\begin{tabular}{c|c}
\hline
\textbf{Operator} & \textbf{Beschreibung} \\ \hline
$\sim$ & logisches NOT\\
$\&$ & logisches UND\\
$|$ & logisches ODER\\
$\&\&$ & short-circuit logical UND\\
$\|$ & short-circuit logical ODER\\
\hline
\end{tabular}
\end{center}
\end{table}
Um Werte miteinander zu vergleichen gibt es die \textit{relationalen
Operatoren} (Tabelle \ref{relationaloperators}). Mit ihnen kann man
auf Dinge wie Gleicheit (\code{==}) gr\"o{\ss}er oder kleiner als
(\code{>}, \code{<}) testen.
\begin{table}[th]
\caption{\label{relationaloperators}
\textbf{Relationale Operatoren in \matlab.}}
\begin{center}
\begin{tabular}{c|c}
\hline
\textbf{Operator} & \textbf{Beschreibung} \\ \hline
$<$ & kleiner als\\
$>$ & gr\"osser als \\
$==$ & gleich \\
$>=$ & gr\"osser oder gleich \\
$<=$ & kleiner oder gleich \\
$\sim=$ & ungleich\\
\hline
\end{tabular}
\end{center}
\end{table}
Das Ergebnis eines Booleschen Ausdrucks ist immer vom Datentyp
\textit{logical}. Man kann jede beliebige Variable zu wahr oder falsch
auswerten indem man in den Typ \textit{logical} umwandelt. Dabei
werden von \matlab{} alle Werte, die nicht 0 sind als wahr
eingesch\"atzt. Listing \ref{booleanexpressions} zeigt einige
Beispiele. \matlab{} kennt die Schl\"usselworte \code{true} und
\code{false}. Diese sind jedoch nur Synonyme f\"ur die
\textit{logical} Werte 1 und 0. Man beachte, dass der
Zuweisungsoperator \code{=} und der logische Operator \code{==} zwei
grundverschiedene Dinge sind. Da sie umgangsprachlich gleich sind kann
man sie leider leicht verwechseln.
\begin{lstlisting}[caption={Boolesche Ausdr\"ucke.}, label=booleanexpressions]
>> true
ans =
1
>> false
ans =
0
>> logical(1)
ans =
1
>> 1 == true
ans =
1
>> 1 == false
ans =
0
>> logical('test')
ans =
1 1 1 1
>> 1 > 2
ans =
0
>> 1 < 2
ans =
1
>> x = [2 0 0 5 0] & [1 0 3 2 0]
x =
1 0 0 1 0
>> ~([2 0 0 5 0] & [1 0 3 2 0])
ans =
0 1 1 0 1
>> [2 0 0 5 0] | [1 0 3 2 0]
ans =
1 0 1 1 0
\end{lstlisting}
\section{Logisches Indizieren}\label{logicalindexingsec}
Einer der wichtigsten Einsatzorte f\"ur Bollesche Ausdr\"ucke ist das
logische Indizieren. Das logische Indizieren ist eines der
Schl\"usselkonzepte in \matlab{}. Nur mit diesem k\"onnen
Filteroperationen auf Vektoren und Matrizen effizient durchgef\"uhrt
werden. Es ist sehr m\"achtig und, wenn es einmal verstanden wurde,
sehr intuitiv zu benuzten.
Das Grundkonzept hinter der logischen Indizierung ist, dass man durch
die Verwendung eines Booleschen Ausdrucks auf z.B. einen Vektor einen
logischen Vektor gleicher Gr\"o{\ss}e erh\"alt. Dieser wird nun
benutzt um auf den urspr\"unglichen Vektor zuzugreifen. \matlab{} gibt
nun die Werte an den Stellen zur\"uck, an denen der logische Vektor
\textit{wahr} ist (Listing \ref{logicalindexing1}).
\begin{lstlisting}[caption={Beispiel logisches Indizieren.}, label=logicalindexing1]
>> x = randn(10, 1);
>> % in zwei Schritten
>> x_smaller_zero = x < 0; % logischer vektor
>> elements_smaller_zero = x(x_smaller_zero); % benutzen, um zuzugreifen
>> % oder in einem Schritt
>> elements_smaller_zero = x(x < 0);
\end{lstlisting}
\begin{exercise}{logicalVector.m}{logicalVector.out}
Erstelle einen Vektor x mit den Werten 0-10.
\begin{enumerate}
\item F\"uhre aus: \code{y = x < 5}
\item Gib den Inhalt von \code{y} auf dem Bildschirm aus.
\item Was ist der Datentyp von \code{y}?
\item Gibt alle Elemente aus x zur\"uck, die kleiner als 5 sind.
\end{enumerate}
Die letzte Zeile kann wie folgt gelesen werden: Gib mir die Elemente
von (\code{x}) an den Stellen, an denen \code{x < 5} wahr ist.
\end{exercise}
Logisches Indizieren wurde oben so benutzt, dass die Auswahl
auf dem Inhalt desselben Vektors beruhte. Ein sehr h\"auiger Fall ist
jedoch, dass man die Auswahl aus einem Vektor auf den Inhalt eines
zweiten Vektors basiert. Ein Beispiel ist, dass man \"uber einen
gewissen Zeitraum Daten aufnimmt und aus diesen die Daten eines
bestimmten Zeitraums ausw\"ahlen m\"ochte (Abbildung
\ref{logicalindexingfig}).
\begin{figure}[h]
\includegraphics[width= 0.9\columnwidth]{logicalIndexingTime}
\caption{\textbf{Beispiel f\"ur ``indirektes'' logisches Indizieren.}
Der rot markierte Abschnitt aus den Daten wurde ``indirekt''
anhand logischen Indizierens auf dem Zeitvektor
ausgew\"ahlt.}\label{logicalindexingfig}
\end{figure}
\begin{exercise}{logicalIndexingTime.m}{}
Angenommen es werden \"uber einen bestimmten Zeitraum Messwerte
genommen. Bei solchen Messungen er\"alt man einen Vektor, der die
Zeitpunkte der Messung speichert und einen zweiten mit den
jeweiligen Messwerten.
\begin{itemize}
\item Erstelle einen Vektor \code{t= 0:0.001:10;}, der z.B. die Zeit
repr\"asentiert.
\item Erstelle einen zweiten Vektor \code{x} mit Zufallszahlen der
die gleiche L\"ange hat wie \code{t}. Die Werte darin stellen
Messungen zu den Zeitpunkten in \code{t} dar.
\item Benutze das logische Indizieren um die Messwerte
auszuw\"ahlen, die dem zeitlichen Abschnitt 5-6\,s entsprechen.
\end{itemize}
\end{exercise}
\section{Kontrollstrukturen}\label{controlstructsec}
In der Regel wird ein Programm Zeile f\"ur Zeile von oben nach unten
ausgef\"uhrt. Manchmal muss der Kontrollfluss aber so gesteuert
werden, dass bestimmte Teile des Programmcodes wiederholt oder nur
unter bestimmten Bedingungen ausgef\"uhrt werden. Von gro{\ss}er
Bedeutung sind hier zwei Strukturen:
\begin{enumerate}
\item Schleifen.
\item Bedingte Anweisungen und Verzweigungen.
\end{enumerate}
\subsection{Schleifen}
Schleifen werden gebraucht um wiederholte Ausf\"uhrung desselben Codes
zu vereinfachen. In einer \"Ubung wurde die Fakult\"at von 5 wie in
Listing \ref{facultylisting} berechnet:
\begin{lstlisting}[caption={Berechnung der Fakult\"at von 5 in f\"unf
Schritten}, label=facultylisting]
>> x = 1;
>> x = x * 2;
>> x = x * 3;
>> x = x * 4;
>> x = x * 5;
>> x
x =
120
\end{lstlisting}
Im Prinzip ist das obige Programm v\"ollig in Ordnung. Es f\"allt
jedoch auf, dass die Zeilen 2 bis 5 sehr \"ahnlich sind; bis auf die
Multiplikation mit einer ansteigenden Zahl \"andert sich nichts. Die
Verwendung von mehr oder weniger exakten Klonen einzelner Zeilen oder
Abschnitte ist schlechter Prgrammierstil. Dabei geht es nicht nur um
einen \"asthetischen Aspekt sondern vielmehr darum, dass es schwerwiegende Nachteile gibt.
\begin{enumerate}
\item Fehleranf\"alligkeit: Beim ``Copy-and-paste'' kann leicht
vergessen werden in einzelnen Klonen die entscheidende \"Anderung
auch wirklich vorzunehmen.
\item Flexibilit\"at: Das obige Programm ist f\"ur genau einen Zweck,
Berechnung der Fakult\"at von f\"unf, gemacht und kann nichts
anderes.
\item Wartung: Wenn ich einen Fehler gemacht habe, dann muss ich den
Fehler in allen Klonen korrigieren (sehr wird dabei der ein oder
andere Klon \"ubersehen).
\item Verst\"andlichkeit: Solche Abschnitte sind schwerer zu lesen/zu
verstehen. Das liegt zum Teil daran, dass man dazu neigt \"uber sich
wiederholende Zeilen zu springen (ist ja eh das gleiche...) und dann
den entscheidenden Teil verpasst.
\end{enumerate}
Alle Programmiersprachen bieten zur L\"osung dieses Problems die
Schleifen. Eine Schleife wird immer dann eingesetzt, wenn man
Abschnitte wiederholt ausf\"uhren will.
\subsubsection{Die \code{for} -- Schleife}
Der am h\"aufigsten benutzte Vertreter der Schleifen ist die
\textit{for-Schleife}. Sie besteht aus dem \textit{Schleifenkopf} und
dem \textit{Schleifenk\"orper}. Der Kopf regelt, wie h\"aufig der Code
im K\"orper ausgef\"uhrt wird. Der Schleifenkopf beginnt mit dem
Schl\"usselwort \code{for} auf welches folgend die
\textit{Laufvariable} definiert wird. In \matlab ``l\"auft''/iteriert
eine for-Schleife immer(!) \"uber einen Vektor. Die
\textit{Laufvariable} nimmt mit jeder Iteration einen Wert dieses
Vektors an. Im Schleifenk\"orper k\"onnen beliebige Anweisungen
ausgef\"uhrt werden. Die Schleife wird durch das Schl\"usselwort
\code{end} beendet. Listing \ref{looplisting} zeigt das
Grundger\"ust einer for-Schleife.
\begin{lstlisting}[caption={Beispiel einer \code{for} Schleife. Die Laufvariable \code{x} nimmt mit jeder Iteration der Schleife einen Wert des Vektors \code{1:5} an.}, label=looplisting]
for x = 1:5
% ... etwas sinnvolles mit x ...
end
\end{lstlisting}
\begin{exercise}{facultyLoop.m}{facultyLoop.out}
Wie k\"onnte Fakult\"at mit einer Schleife implementiert werden?
Implementiere eine for Schleife, die die Fakul\"at von einer Zahl
\code{n} berechnet.
\end{exercise}
\subsubsection{Die \code{while} -- Schleife}
Eine weiterer Schleifentyp, der weniger h\"aufig eingesetzt wird, ist
die \code{while}-Schleife. Auch sie hat ihre Entsprechungen in fast
allen Programmiersprachen. \"Ahnlich zur \code{for} Schleife wird
auch hier der in der Schleife definierte Programmcode iterativ
ausgef\"uhrt. Der Schleifenkopf beginnt mit dem Schl\"usselwort
\code{while} gefolgt von einem \underline{Booleschen
Ausdruck}. Solange dieser zu \code{true} ausgewertet werden kann,
wird der Code im Schleifenk\"orper ausgef\"uhrt. Die Schleife wird
mit dem Schl\"usselwort \code{end} beendet.
\begin{lstlisting}[caption={Grundstruktur einer \code{while} Schleife.}, label=whileloop]
while x == true
% fuehre diesen sinnvollen code aus ...
end
\end{lstlisting}
\begin{exercise}{facultyWhileLoop.m}{}
Implementiere die Fakult\"at mit einer \code{while}-Schleife.
\end{exercise}
\begin{exercise}{neverendingWhile.m}{}
Implementiere eine \code{while}-Schleife, die unendlich
l\"auft. Tipp: wenn der Boolesche Ausdruck hinter dem \code{while}
zu wahr ausgewertet wird, wird die Schleife weiter ausgef\"uhrt.
\end{exercise}
\subsubsection{Vergleich \code{for} -- und \code{while}--Schleife}
\begin{itemize}
\item Beide f\"uhren den Code im Schleifenk\"orper iterativ aus.
\item Der K\"orper einer \code{for} Schleife wird mindestens 1 mal
betreten. % XXX Nur wenn die Liste im Kopf nicht leer ist, oder ?
\item Der K\"orper einer \code{while} Schleife wird nur dann betreten,
wenn die Bedingung im Kopf \code{true} ist. \\$\rightarrow$ auch
``Oben-abweisende'' Schleife genannt.
\item Die \code{for} Schleife eignet sich f\"ur F\"alle in denen f\"ur
jedes Element eines Vektors der Code ausgef\"uhrt werden soll.
\item Die \code{while} Schleife ist immer dann gut, wenn nicht klar
ist wie h\"aufig etwas ausgef\"uhrt werden soll. Sie ist
speichereffizienter.
\item Jedes Problem kann mit beiden Typen gel\"ost werden.
\end{itemize}
\subsection{Bedingte Anweisungen und Verzweigungen}
Bedingte Anweisungen und Verzweigungen sind Kontrollstrukturen, die
regeln, dass der in ihnen eingeschlossene Programmcode nur unter
bestimmten Bedingungen ausgef\"uhrt wird.
\subsubsection{Die \code{if} -- Anweisung}
Am h\"aufigsten genutzter Vertreter ist die \code{if} -
Anweisung. Sie Wird genutzt um Programmcode nur unter bestimmten
Bedingungen auszuf\"uhren.
Der Kopf der if - Anweisung beginnt mit dem Schl\"usselwort \code{if}
welches von einem \underline{Booleschen Ausdruck} gefolgt wird. Wenn
dieser zu \code{true} ausgewertet werden kann, wird der Code im
K\"orper der Anweisung ausgef\"uhrt. Optional k\"onnen weitere
Bedingungen mit dem Schl\"usselwort \code{elseif} folgen. Ebenfalls
optional ist die Verwendung eines finalen \code{else} Falls. Dieser
wird immer dann ausgef\"uhrt wenn alle vorherigen Bedingungen nicht
erf\"ullt werden. Die \code{if} Anweisung wird mit \code{end}
beendet. Listing \ref{ifelselisting} zeigt den Aufbau einer
if-Anweisung.
\begin{lstlisting}[label=ifelselisting, caption={Grundger\"ust einer \code{if} Anweisung.}]
if x < y
% fuehre diesen code aus
elseif x > y
% etwas anderes soll getan werden
else
% wenn x == y wieder etwas anderes
end
\end{lstlisting}
\begin{exercise}{ifelse.m}{}
Ziehe eine Zufallszahl und \"uberpr\"ufe mit einer geegneten \code{if} Anweisung, ob sie:
\begin{enumerate}
\item ... kleiner als 0.5 ist.
\item ... kleiner oder gr\"o{\ss}er-gleich 0.5 ist.
\item ... kleiner als 0.5, gr\"o{\ss}er oder gleich 0.5 aber kleiner
als 0.75 ist oder gr\"o{\ss}er oder gleich 0.75 ist.
\end{enumerate}
\end{exercise}
\subsubsection{Die \code{switch} -- Verzweigung}
Die \code{switch} Verzweigung Wird eingesetzt wenn mehrere F\"alle
auftreten k\"onnen, die einer unterschiedlichen Behandlung bed\"urfen.
Wird mit dem Schl\"usselwort \code{switch} begonnen, gefolgt von der
\textit{switch Anweisung} (Zahl oder String). Jeder Fall auf den die
Anweisung \"uberpr\"ft werden soll wird mit dem Schl\"usselwort
\code{case} eingeleitet. Diese wird gefolgt von der \textit{case
Anweisung} welche definiert gegen welchen Fall auf
\underline{Gleichheit} getestet wird. F\"ur jeden Fall wird der
Programmcode angegeben, der ausgef\"uhrt werden soll Optional k\"onnen
mit dem Schl\"usselwort \code{otherwise} alle nicht explizit genannten
F\"alle behandelt werden. Die \code{switch} Anweisung wird mit
\code{end} beendet (z.B. in Listing \ref{switchlisting}).
\begin{lstlisting}[label=switchlisting, caption={Grundger\"ust einer \code{switch} Anweisung.}]
mynumber = input('Enter a number:');
switch mynumber
case -1
disp('negative one');
case 1
disp('positive one');
otherwise
disp('something else');
end
\end{lstlisting}
Wichtig ist hier, dass in jedem \code{case} auf \underline{Gleichheit} der
switch-Anweisung und der case-Anweisung getestet wird.
\subsubsection{Vergleich \code{if} -- Anweisung und \code{switch} -- Verzweigung}
\begin{itemize}
\item Mit der \code{if} Anweisung k\"onnen beliebige F\"alle
unterschieden und entsprechender code ausgef\"uhrt werden.
\item Die \code{switch} Anweisung leistet \"ahnliches allerdings wird in
jedem Fall auf Gleichheit getestet.
\item Die \code{switch} Anweisung ist etwas kompakter, wenn viele F\"alle
behandelt werden m\"ussen.
\item Die \code{switch} Anweisung wird deutlich seltener benutzt und
kann immer durch eine \code{if} Anweisung erstezt werden.
\end{itemize}
\subsection{Die Schl\"usselworte \code{break} und \code{continue}}
Soll die Ausf\"uhrung einer Schleife abgebrochen oder \"ubersprungen
werden, werden die Schl\"usselworte \code{break} und
\code{continue} eingesetzt (Listing \ref{breakcontinuelisting}
zeigt, wie sie eingesetzt werden k\"onnen).
\begin{lstlisting}[caption={Ensatz der \code{continue} und \code{break} Schl\"usselworte um die Ausf\"uhrung von Code-Abschnitten in Schleifen zu \"uberspringen oder abzubrechen.}, label=breakcontinuelisting]
for x = 1:10
if(x > 2 & x < 5)
continue;
end
disp(x);
end
x = 1;
while true
if(x > 5)
break;
end
disp(x);
x = x + 1
end
\end{lstlisting}
\begin{exercise}{logicalIndexingBenchmark.m}{logicalIndexingBenchmark.out}
Vergleich von logischem Indizieren und ``manueller'' Auswahl von
Elementen aus einem Vektor. Es wurde oben behauptet, dass die
Auswahl von Elementen mittels logischem Indizieren effizienter
ist. Teste dies indem ein Vektor mit vielen (100000) Zufallszahlen
erzeugt wird aus dem die Elemente gefiltert und gespeichert werden,
die kleiner $0.5$ sind. Umgebe den Programmabschnitt mit den
Br\"udern \code{tic} und \code{toc}. Auf diese Weise misst \matlab{}
die zwischen \code{tic} und \code{toc} vergangene Zeit.
\begin{enumerate}
\item Benutze eine \code{for} Schleife um die Elemente auszuw\"ahlen.
\item Benutze logisches Indizieren.
\end{enumerate}
\end{exercise}
\begin{exercise}{simplerandomwalk.m}{}
Programmiere einen 1-D random walk. Ausgehend von der Startposition
$0$ ``l\"auft'' ein Agent zuf\"allig in die eine oder andere
Richtung.
\begin{itemize}
\item In dem Programm sollen 10 Realisationen eines random walk mit
jeweils 1000 Schritten durchgef\"uhrt werden.
\item Die Position des Objektes ver\"andert sich in jedem Schritt zuf\"allig um
+1 oder -1.
\item Merke Dir alle Positionen.
\item Plotte die Positionen als Funktion der Schrittnummer.
\end{itemize}
\end{exercise}
\section{Skripte und Funktionen}
\subsection{Was ist ein Programm?}
Ein Programm ist eine Sammlung von Anweisungen, die in einer Datei auf
dem Rechner abgelegt sind. Wenn es durch den Aufruf zum Leben erweckt
wird, dann wird es Zeile f\"Ur Zeile von oben nach unten ausgef\"uhrt.
\matlab{} kennt drei Arten von Programmen:
\begin{enumerate}
\item Skripte
\item Funktionen
\item Objekte (werden wir ignorieren)
\end{enumerate}
Alle Programme werden in den sogenannten \textit{m-files} gespeichert
(z.B. \textit{meinProgramm.m}). Um sie zu benutzen werden sie von der
Kommandozeile aufgerufen oder in anderen Programmen
verwendet. Programme erh\"ohen die Wiederverwertbarkeit von
Programmcode. Bislang haben wir ausschlie{\ss}lich Skripte
verwendet. Dabei wurde jede Variable, die erzuegt wurde im
\textit{Workspace} abgelegt und konnte wiederverwendet werden. Hierin
liegt allerdings auch eine Gefahr. In der Regel sind Datenanalysen auf
mehrere Skripte verteilt und alle teilen sich den gemeinsamen
Workspace. Verwendet nun ein aufgerufenes Skript eine bereits
definierte Variable und weist ihr einen neuen Wert zu, dann kann das
erw\"unscht und praktisch sein. Wenn es aber unbeabsichtigt passiert
kann es zu Fehlern kommen, die nur sehr schwer erkennbar sind, da ja
jedes Skript f\"ur sich enwandtfrei arbeitet. Eine L\"osung f\"ur
dieses Problem bieten die \emph{Funktionen}.
\subsection{Funktionen}
Eine Funktion in \matlab{} wird \"ahnlich zu einer mathematischen
Funktion definiert:
\[ y = f(x) \]
Die Funktion hat einen Namen $f$, sie h\"angt von einem Argument $x$
ab und liefert ein Ergebnis $y$ zur\"uck. Listing
\ref{functiondefinitionlisting} zeigt wie das in \matlab{} umgesetzt
wird.
\begin{lstlisting}[caption={Funktionsdefinition in \matlab{}}, label=functiondefinitionlisting]
function [y] = function_name(arg_1, arg_2)
% ^ ^ ^
% Rueckgabewert Argument_1, Argument_2
\end{lstlisting}
Ein Funktion beginnt mit dem Schl\"usselwort \code{function} gefolgt
von den R\"uckgabewerte(n), dem Funktionsnamen und (in Klammern) den
Argumenten. Auf den Funktionskopf folgt der auszuf\"uhrende
Programmcode im Funktionsk\"orper. Die Funktionsdefinition wird
% optional %XXX es ist vielleicht optional, aber gute stil ware es immer hinzuschreiben, oder?
mit einem \code{end} abgeschlossen. Jede Funktion, die vom
Nutzer direkt verwendet werden soll, ist in einer eigenen Datei
definiert. \"Uber die Definition/Benutzung von Funktionen wird folgendes erreicht:
\begin{itemize}
\item Kapseln von Programmcode, der f\"ur sich eine Aufgabe l\"ost.
\item Definierte Schnittstelle.
\item Eigener G\"ultigkeitsbereich:
\begin{itemize}
\item Variablen im Workspace sind in der Funktion \emph{nicht} sichtbar.
\item Variablen, die in der Funktion definiert werden erscheinen
\emph{nicht} im Workspace.
\end{itemize}
\item Erh\"oht die Wiederverwendbarkeit von Programmcode.
\item Erh\"oht die Lesbarkeit von Programmen, da sie
\"ubersichtlicher werden.
\end{itemize}
Das Folgende Beispiel (Listing \ref{badsinewavelisting}) zeigt eine
Funktion, die eine Reihe von Sinusschwingungen unterschiedlicher
Frequenzen berechnet und graphisch darstellt.
\begin{lstlisting}[caption={Eine Beispielfunktion, die eine Reihe Sinus plottet.},label=badsinewavelisting]
function meine_erste_funktion() % Funktionskopf
t = (0:0.01:2); % hier faengt der Funktionskoerper an
frequenz = 1.0;
amplituden = [0.25 0.5 0.75 1.0 1.25];
for i = 1:length(amplituden)
y = sin(frequenz * t * 2 * pi) * amplituden(i);
plot(t, y)
hold on;
end
\end{lstlisting}
Das obige Beispiel ist ein Paradebeispiel f\"ur eine schlechte
Funktion. Sie hat folgende Probleme:
\begin{itemize}
\item Der Name ist nicht aussagekr\"aftig.
\item Die Funktion ist f\"ur genau einen Zweck geeignet.
\item Was sie tut, ist festgelegt und kann von au{\ss}en nicht
beeinflusst oder bestimmt werden.
\item Sie tut drei Dinge aus einmal: Sinus berechnen \emph{und}
Amplituden \"andern \emph{und} graphisch darstellen.
\item Es ist nicht (einfach) m\"oglich an die berechneten Daten zu
kommen.
\item Keinerlei Dokumentation. Man muss den code lesen um zu
rekonstruieren, was sie tut.
\end{itemize}
Bevor wir anfangen die Funktion zu verbessern mu{\ss} definiert werden
was das zu l\"osende Problem ist:
\begin{enumerate}
\item Welches Problem soll gel\"ost werden?
\item Aufteilen in Teilprobleme.
\item Gute Namen finden.
\item Definieren der Schnittstellen --- Was m\"ussen die beteiligten Funktionen
wissen? Was sollen sie zur\"uckliefern?
\item Daten zur\"uck geben (R\"uckgabewerte definieren).
\end{enumerate}
Das Beispielproblem aus Listing \ref{badsinewavelisting} kann in drei
Teilprobleme aufgetrennt werden. (i) Berechnen der \emph{einzelnen}
Sinus. (ii) Plotten der jeweils berechneten Daten und (iii)
Koordination von Berechnung und Darstellung mit unterschiedlichen
Amplituden.
\paragraph{I. Berechnung eines einzelnen Sinus}
Die Berechnung eines einzelnen Sinus ist ein typischer Fall f\"ur eine
Funktion. Wiederum macht man sich klar, (i) wie die Funktion
hei{\ss}en soll, (ii) welche Information sie ben\"otigt und (iii)
welche Daten sie zur\"uckliefern soll.
\begin{enumerate}
\item \textbf{Name:} der Name sollte schon beschreiben, was die Funktion
tut. In diesem Fall berechnet sie einen Sinus. Ein geeigneter Name
w\"are also \code{calculate\_sinwave}.
\item \textbf{Argumente:} die zu brechnende Sinusschwingung sei durch
ihre Frequenz und die Amplitude bestimmt. Des Weiteren soll noch
festgelegt werden, wie lang der Sinus sein soll und mit welcher
zeitlichen Aufl\"osung gerechnet werden soll. Es werden also vier
Argumente ben\"otigt, sie k\"onnten hei{\ss}en: \code{amplitude},
\code{frequency}, \code{t\_max}, \code{t\_step}.
\item \textbf{R\"uckgabewerte:} Um den Sinus korrekt darstellen zu k\"onnen brauchen wir die
Zeitachse und die entsprechenden Werte. Es werden also zwei
Variablen zur\"uckgegeben: \code{time, sine}
\end{enumerate}
Mit dieser Information ist es nun gut m\"oglich die Funktion zu
implementieren (Listing \ref{sinefunctionlisting}).
\begin{lstlisting}[caption={Funktion, die einen Sinus berechnet.}, label=sinefunctionlisting]
function [time, sine] = calculate_sinewave(frequency, amplitude, t_max, t_step)
% The function calculates a sinewave with a given frequency and
% amplitude.
% Arguments: frequency, the frequency of the sine
% amplitude, the amplitude of the sine
% t_max, the duration of the sine in seconds
% t_step, the temporal resolution in seconds
% Returns: time, the time axis
% sine, the calculated sinewave
time = (0:t_step:t_max);
sine = sin(frequency .* time .* 2 * pi) .* amplitude;
\end{lstlisting}
\paragraph{II. Plotten einer einzelnen Schwingung}
Diese Aufage kann auch von einer Funktion \"ubernommen werden. Diese
Funktion hat keine andere Aufgabe, als die Daten zu plotten. Ihr Name
sollte sich an dieser Aufgabe orientieren
(z.B. \code{plot\_sinewave}). Um einen einzelnen Sinus zu plotten
werden im Wesentlichen die x-Werte und die zugeh\"origen y-Werte
ben\"otigt. Da mehrere Sinus geplottet werden sollen ist es auch
sinnvoll eine Zeichenkette f\"ur die Legende an die Funktion zu
\"ubergeben. Da diese Funktion keine Berechnung durchf\"uhrt wird kein
R\"uckgabewert ben\"otigt (Listing \ref{sineplotfunctionlisting}).
\begin{lstlisting}[caption={Funktion, die die Daten plottet.}, label=sineplotfunctionlisting]
function plot_sinewave(x_data, y_data, name)
% Plots x-data against y-data and sets the display name.
% Arguments: x_data, the x-data
% y_data, the y-data
% name, the displayname
plot(x_data, y_data, 'displayname', name)
\end{lstlisting}
\paragraph{III. Erstellen eines Skriptes zur Koordinierung}
Die letzt Aufgabe ist die Koordinierung der Berechung und des Plottens
f\"ur mehrere Amplituden. Das ist die klassische Aufgabe f\"ur ein
Skript. Auch hier gilt es einen ausdrucksvollen Name zu finden. Da es
keine Argumente und R\"uckgabewerte gibt bleibt und nur, die
ben\"otigten Information direkt in dem Skript zu defninieren. Dies
sind: ein Vektor, f\"ur die Amplituden, je eine Variable f\"ur die
gew\"unschte Frequenz, die maximale Zeit auf der x-Achse und die
zeitliche Aufl\"osung. Das Skript \"offnet schlie{\ss}lich noch eine
neue Abbildung und setzt das \code{hold on} da nur das Skript
wei{\ss}, das mehr als ein Plot erzeugt werden soll. Das Skript ist in
Listing \ref{sinesskriptlisting} dargestellt.
\begin{lstlisting}[caption={Kontrollskript, das die Berechnung und plotting koordiniert.}, label=sinesskriptlisting]
amplitudes = 0.25:0.25:1.25;
frequency = 2;
t_max = 10;
t_step = 0.01;
figure()
hold on
for i = 1:length(amplitudes)
[x_data, y_data] = calculate_sinewave(frequency, amplitudes(i), ...
t_max, t_step);
plot_sinewave(x_data, y_data, sprintf('freq: %5.2f, ampl: %5.2f',...
frequency, amplitudes(i)))
end
legend('show')
\end{lstlisting}
\begin{exercise}{plotMultipleSinewaves.m}{}
Erweitert das Programm so, dass auch ein Satz von Frequenzen benutzt
wird.
\end{exercise}
\subsection{Fazit}
Funktionen sind kleine Code Fragmente, die
\begin{enumerate}
\item ... genau eine Aufgabe erledigen.
\item ... Argumente entgegennehmen k\"onnen.
\item ... R\"uckgabewerte haben k\"onnen.
\item ... ihren eigenen G\"ultigkeitsbereich haben.
\item ... Skripten fast immer vorzuziehen sind.
\end{enumerate}
Die vorangegangene Aussagen klingen, als ob Skripte zu
verteufeln w\"aren und und vermieden werden sollten. Dem ist nicht
so. In Wahrheit sind sie daf\"ur gemacht, Hand in Hand mit den
Funktionen ein Probelm zu l\"osen. W\"ahrend die Funktionen relativ
kleine ``verdauliche'' Teilprobleme l\"osen. Sind die Skripte daf\"ur
gemacht den Rahmen zu bilden und den Ablauf zu koordinieren (Abbildung
\ref{programlayoutfig}).
\begin{figure}
\includegraphics[width=0.5\columnwidth]{./images/simple_program.pdf}
\caption{\textbf{Ein typisches Programmlayout.} Das Kontrollskript
koordiniert den Aufruf der Funktionen, \"ubergibt Argumente und
nimmt R\"uckgabewerte entgegen.}\label{programlayoutfig}
\end{figure}