1530 lines
58 KiB
TeX
1530 lines
58 KiB
TeX
\chapter{Programmierung in \matlab}
|
|
|
|
\section{Variablen und Datentypen}
|
|
|
|
\subsection{Variablen}
|
|
|
|
Eine \determ{Variable} ist ein Zeiger auf eine Stelle im
|
|
Speicher. Dieser Zeiger hat einen Namen, den Variablennamen, und einen
|
|
\determ{Datentyp} (Abbildung \ref{variablefig}). Im Speicher wird der
|
|
Wert der Variablen bin\"ar als eine Folge von \determ[Bit]{Bits} (0
|
|
oder 1) 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}
|
|
\titlecaption{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 erzeugt werden. Listing
|
|
\ref{varListing1} zeigt drei Beispiele:
|
|
\begin{lstlisting}[label=varListing1, caption={Erzeugen von Variablen.}]
|
|
>> x = 38
|
|
x =
|
|
38
|
|
|
|
>> y = []
|
|
y =
|
|
[]
|
|
|
|
>> z = 'A'
|
|
z =
|
|
A
|
|
\end{lstlisting}
|
|
|
|
Die Zeile 1 kann etwa so gelesen werden:''Erzeuge eine Variable mit
|
|
dem Namen \varcode{x} und weise ihr den Wert 38 zu''. Das
|
|
Gleichheitszeichen ist der sogenannte
|
|
\codeterm{Zuweisungsoperator}. Zeile 5 definiert eine Variable \varcode{y}, der
|
|
ein leerer Wert zugewiesen wird. Da \matlab{}, wenn nicht anders
|
|
angegeben, immer den \codeterm{double} Datentypen benutzt, haben beide
|
|
Variablen diesen Datentyp. In Zeile 9 wird der Variablen \varcode{z} der Buchstabe
|
|
``A'' zugewiesen. \varcode{z} ist nicht ein Flie{\ss}kommazahl von Typ \codeterm{double},
|
|
sondern ein \codeterm{character} (Zeichen).
|
|
|
|
Der Datentyp einer Variable kann mit \code{class()} abgefragt werden.
|
|
Eine Liste aller definierten Variablen gibt \code{who}
|
|
zur\"uck. Detailliertere Informationen \"uber Variablen zeigt
|
|
\code{whos} an.
|
|
|
|
\begin{lstlisting}[label=varListing2, caption={Erfragen des Datentyps einer Variable, Listen aller definierten Variablen.}]
|
|
>>class(x)
|
|
ans =
|
|
double
|
|
|
|
>> who
|
|
Your variables are:
|
|
|
|
x y z
|
|
|
|
>> whos
|
|
Name Size Bytes Class Attributes
|
|
|
|
x 1x1 8 double
|
|
y 0x0 0 double
|
|
z 1x1 2 char
|
|
\end{lstlisting}
|
|
|
|
\begin{important}[Namen von Variablen]
|
|
Bei der Namensgebung ist zu beachten, dass \matlab{} auf Gro{\ss}-
|
|
und Kleinschreibung achtet und ein Variablenname mit einem
|
|
alphabetischen Zeichen beginnen muss. Umlaute, Sonder- und
|
|
Leerzeichen sind in Variablennamen nicht erlaubt.
|
|
\end{important}
|
|
|
|
\subsection{Arbeiten mit Variablen}
|
|
|
|
Nat\"urlich kann mit den Variablen auch gearbeitet, bzw. gerechnet
|
|
werden. \matlab{} kennt alle normalen
|
|
\codeterm[Operator!arithmetischer]{arithmetischen Operatoren} wie
|
|
\code[Operator!arithmetischer!1add@+]{+},
|
|
\code[Operator!arithmetischer!2sub@-]{-},
|
|
\code[Operator!arithmetischer!3mul@*]{*} und
|
|
\code[Operator!arithmetischer!4div@/]{/}. Die Potenz wird \"uber das
|
|
Dachsymbol \code[Operator!arithmetischer!5pow@\^{}]{\^{}}
|
|
dargestellt. Listing \ref{varListing3} zeigt, wie sie benutzt werden.
|
|
|
|
\pagebreak[4]
|
|
\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 % loesche die Variable z
|
|
\end{lstlisting}
|
|
|
|
Beachtenswert ist in Zeilen 2 und 6, dass mit dem Inhalt einer
|
|
Variablen gerechnet werden kann, ohne dass dadurch ihr Wert
|
|
ver\"andert wird. Wenn der Wert einer Variablen ver\"andert werden
|
|
soll, dann muss der neue Wert explizit einer Variablen zugewiesen werden
|
|
(mit dem \code[Operator!Zuweisung!=]{=} Zuweisungsoperator,
|
|
z.B. Zeilen 14 und 18). Zeile 23 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:
|
|
\begin{itemize}
|
|
\item \codeterm{integer}: Ganze Zahlen. Hier gibt es mehrere
|
|
Unterarten, die wir in \matlab{} (meist) ignorieren k\"onnen.
|
|
\item \codeterm{double}: Flie{\ss}kommazahlen. Im Gegensatz zu den reelen Zahlen, die durch diesen Datentyp dargestellt werden, sind sie abz\"ahlbar.
|
|
\item \codeterm{complex}: Komplexe Zahlen.
|
|
\item \codeterm{logical}: Boolesche Werte, die als wahr
|
|
(\code{true}) oder falsch (\code{false}) interpretiert werden.
|
|
\item \codeterm{char}: ASCII Zeichen
|
|
\end{itemize}
|
|
Unter den numerischen Datentypen gibt es verschiedene Arten mit
|
|
unterschiedlichem Speicherbedarf und Wertebreich (siehe
|
|
Tabelle~\ref{dtypestab}).
|
|
|
|
\begin{table}[t]
|
|
\centering
|
|
\titlecaption{Grundlegende numerische Datentypen und ihr Wertebereich.}{}
|
|
\label{dtypestab}
|
|
\begin{tabular}{llcl}\hline
|
|
Datentyp & Speicherbedarf & Wertebereich & Beispiel \erh \\ \hline
|
|
\code{double} & 64 bit & $\approx -10^{308}$ bis $\approx 10^{308} $& Flie{\ss}kommazahlen.\erb\\
|
|
\code{int} & 64 bit & $-2^{31}$ bis $2^{31}-1$ & Ganzzahlige Werte \\
|
|
\code{int16} & 16 bit & $-2^{15}$ bis $2^{15}-1$ & Digitalisierte Spannungen. \\
|
|
\code{uint8} & 8 bit & $0$ bis $255$ & Digitalisierte Imaging Daten. \\ \hline
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\matlab{} arbeitet meist mit dem \codeterm{double} Datentyp wenn numerische
|
|
Daten gespeichert werden. Dennoch lohnt es sich, sich ein wenig mit
|
|
den Datentypen auseinanderzusetzen (Box \ref{daqbox}).
|
|
|
|
\begin{ibox}[t]{\label{daqbox}Digitalisierung von Messdaten}
|
|
Szenario: Die elektrische Aktivit\"at (z.B. die Membranspannung)
|
|
einer Nervenzelle wird gemessen. Die gemessene Spannung wird mittels
|
|
Messkarte digitalisiert und auf dem Computer f\"ur weitere Analysen
|
|
gespeichert. Typischerweise k\"onnen mit solchen Messkarten
|
|
Spannungen im Bereich $\pm 10$\,V gemessen werden. Die Aufl\"osung
|
|
der Analog-Digitalwandler betr\"agt heutzutage meistens 16 bit. Das
|
|
heisst, dass der gesamte Spannungsbereich in $2^{16}$ Schritte
|
|
eingeteilt ist. Die gemessenene Spannung wird auf digitalisierte
|
|
Werte abgebildet.\vspace{0.25cm}
|
|
|
|
\begin{minipage}{0.5\textwidth}
|
|
\includegraphics[width=0.9\columnwidth]{data_acquisition}
|
|
\end{minipage}
|
|
\begin{minipage}{0.5\textwidth}
|
|
Um die Spannung auf den \code{int16} Datentyp abzubilden:
|
|
\[ y = x \cdot 2^{16}/20\] mit $x$ der gemessenen Spannung und $y$
|
|
dem digitalisierten Wert bei einem Spannungsbereich von
|
|
$\pm10$\,V. Das ergibt ganzzahlige Werte zwischen $-2^{15}=-32768$
|
|
und $2^{15}-1 = 32767$.
|
|
|
|
Durch Umkehrung kann der digitalisierte Wert wieder
|
|
in eine Spannung zur\"uckgewandelt werden:
|
|
\[ x = y \cdot 20/2^{16} \]
|
|
\end{minipage}\vspace{0.25cm}
|
|
|
|
Um Speicherplatz zu sparen ist es sinnvoll, die gemessenen Daten als
|
|
\code{int16} anstelle der \code{double} Werte im Rechner abzulegen. Die
|
|
Daten als Spannungswerte, also als Flie{\ss}kommawerte,
|
|
abzulegen ben\"otigt den 4-fachen Speicherplatz (8 statt 2 Bytes)
|
|
und bietet keine zus\"atzliche Information.
|
|
\end{ibox}
|
|
|
|
|
|
\section{Vektoren und Matrizen}
|
|
|
|
Vektoren und Matrizen sind die wichtigsten Datenstrukturen in
|
|
\matlab{}. In anderen Programmiersprachen hei{\ss}en sie ein-
|
|
bzw. mehrdimensionalen Felder. Felder sind Datenstrukturen, die
|
|
mehrere Werte des gleichen Datentyps in einer Variablen vereinen. Da
|
|
\matlab{} seinen Ursprung in der Verarbeitung von mathematischen
|
|
Vektoren und Matrizen hat, werden sie hier auch so genannt. Dabei
|
|
macht \matlab{} intern 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 \varcode{a}
|
|
enth\"alt im Beispiel in Abbildung \ref{vectorfig} vier ganzzahlige Werte.
|
|
|
|
\begin{figure}
|
|
\includegraphics[width=0.8\columnwidth]{scalarArray}
|
|
\titlecaption{Skalare und Vektoren.}{\textbf{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 Spaltenvektoren
|
|
(columnvector).}\label{vectorfig}
|
|
\end{figure}
|
|
|
|
Das folgende Listing \ref{generatevectorslisting} zeigt, wie Vektoren erstellt
|
|
werden k\"onnen.
|
|
|
|
\begin{lstlisting}[label=generatevectorslisting, 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 Funktionen \code{length()} und \code{numel()}
|
|
bestimmt werden. \"Ahnliche Information kann \"uber die Funktion
|
|
\code{size()} erhalten werden (Listing \ref{vectorsizeslisting}). Der
|
|
Vektor \varcode{a} von oben hat folgende Gr\"o{\ss}en:
|
|
|
|
\begin{lstlisting}[label=vectorsizeslisting, caption={Gr\"o{\ss}e von Vektoren.}]
|
|
>> length(a)
|
|
ans =
|
|
10
|
|
>> size(a)
|
|
ans =
|
|
1 10
|
|
\end{lstlisting}
|
|
|
|
Die Ausgabe der \code{size()}-Funktion zeigt, dass Vektoren im Grunde
|
|
2-dimensional sind. Bei einem Zeilenvektor hat die erste Dimension die
|
|
Gr\"o{\ss}e 1. \code[length()]{length(a)} gibt die l\"angste
|
|
Ausdehnung an. Im folgenden Listing \ref{columnvectorlisting} transponiert der
|
|
\code[Operator!Matrix!']{'} - Operator einen Spaltenvektor
|
|
zu einem Zeilenvektor (Zeilen 14 ff.).
|
|
|
|
\begin{lstlisting}[label=columnvectorlisting, 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
|
|
b =
|
|
1 2 3 4 5 6 7 8 9 10
|
|
|
|
>> size(b)
|
|
ans =
|
|
1 10
|
|
\end{lstlisting}
|
|
|
|
|
|
\subsubsection{Zugriff auf Inhalte von Vektoren}
|
|
\begin{figure}
|
|
\includegraphics[width=0.4\columnwidth]{arrayIndexing}
|
|
\titlecaption{Indices von Vektoren.}{Jedes Feld eines Vektors hat
|
|
einen Index (kleine Zahl) mit dem auf den jeweiligen Inhalt
|
|
(gro{\ss}e Zahl) 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 \codeterm{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.
|
|
|
|
\begin{important}[Indizieren]
|
|
Der Zugriff auf Inhalte eines Vektors mittels seines Indexes wird
|
|
Indizieren genannnt.
|
|
|
|
Der Index des ersten Elements eines Vektors ist in \matlab{} die Eins.
|
|
|
|
Der Index des letzten Elements entspricht der L\"ange des Vektors.
|
|
\end{important}
|
|
|
|
Die Listings \ref{vectorelementslisting} und \ref{vectorrangelisting} zeigen wie
|
|
mit Indexen auf die Inhalte eines Vektors zugegriffen werden kann.
|
|
Hierbei kann auf einzelne Werte zugegriffen werden oder, analog zur
|
|
Erzeugung von Vektoren, die \code[Operator!Matrix!:]{:} Notation
|
|
verwendet werden, um auf mehrere Element gleichzeitig zuzugreifen.
|
|
|
|
\begin{lstlisting}[label=vectorelementslisting, caption={Zugriff auf den Inhalt von Vektoren: einzelne Elemente}]
|
|
>> a = (11:20)
|
|
a =
|
|
11 12 13 14 15 16 17 18 19 20
|
|
|
|
>> a(1) % das 1. Element
|
|
ans = 11
|
|
>> a(5) % das 5. Element
|
|
ans = 15
|
|
>> a(end) % das letzte Element
|
|
ans = 20
|
|
\end{lstlisting}
|
|
|
|
\begin{lstlisting}[caption={Zugriff auf den Inhalt von Vektoren: Bereiche}, label=vectorrangelisting]
|
|
>> 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
|
|
|
|
>> a(:) % alle Elemente als Zeilenvektor
|
|
ans =
|
|
11 12 13 14 15 16 17 18 19 20
|
|
\end{lstlisting}
|
|
|
|
\begin{exercise}{vectorsize.m}{vectorsize.out}
|
|
Erstelle einen Zeilenvektor \varcode{a} mit 5 Elementen.
|
|
Der R\"uckgabewert von \code[size()]{size(a)} ist wieder ein Vektor der
|
|
L\"ange 2. Wie k\"onnte also die Gr\"o{\ss}e von \varcode{a} in der
|
|
zweiten Dimension herausgefunden werden?
|
|
\end{exercise}
|
|
|
|
\subsubsection{Operationen auf Vektoren}
|
|
|
|
Mit Vektoren kann sehr einfach gerechnet werden. Listing
|
|
\ref{vectorscalarlisting} zeigt die Verrechnung von Vektoren mit Skalaren
|
|
mit den Operatoren \code[Operator!arithmetischer!1add@+]{+},
|
|
\code[Operator!arithmetischer!2sub@-]{-},
|
|
\code[Operator!arithmetischer!3mul@*]{*},
|
|
\code[Operator!arithmetischer!4div@/]{/}
|
|
\code[Operator!arithmetischer!5powe@.\^{}]{.\^}.
|
|
|
|
\begin{lstlisting}[caption={Rechnen mit Vektoren und Skalaren.},label=vectorscalarlisting]
|
|
>> a = (0:2:8)
|
|
a =
|
|
0 2 4 6 8
|
|
|
|
>> a + 5 % Addition von einem Skalar
|
|
ans =
|
|
5 7 9 11 13
|
|
|
|
>> a - 5 % Subtraktion von einem Skalar
|
|
ans =
|
|
-5 -3 -1 1 3
|
|
|
|
>> a * 2 % Multiplikation mit einem Skalar
|
|
ans =
|
|
0 4 8 12 16
|
|
|
|
>> a / 2 % Division mit einem Skalar
|
|
ans =
|
|
0 1 2 3 4
|
|
|
|
>> a .^ 2 % Potenzierung mit einem Skalar
|
|
ans =
|
|
0 4 16 36 64
|
|
\end{lstlisting}
|
|
|
|
Bei der elementweisen Verrechnung von zwei Vektoren muss
|
|
sichergestellt werden, dass sie die gleiche L\"ange und das gleiche
|
|
Layout (Spalten- oder Zeilenvektor) haben. Addition und Subtraktion
|
|
erfolgt immer elementweise (Listing~\ref{vectoradditionlisting}).
|
|
|
|
\begin{lstlisting}[caption={Elementweise Addition und Subtraktion von
|
|
Vektoren.},label=vectoradditionlisting]
|
|
>> a = [4 9 12];
|
|
>> b = [4 3 2];
|
|
>> a + b % Addition von 2 Vektoren
|
|
ans =
|
|
8 12 14
|
|
|
|
>> a - b % Subtraktion von 2 Vektoren
|
|
ans =
|
|
0 6 10
|
|
|
|
>> c = [8 4];
|
|
>> a + c % Beide Vektoren muessen gleich gross sein!
|
|
Error using +
|
|
Matrix dimensions must agree.
|
|
>> d = [8; 4; 2];
|
|
>> a + d % Beide Vektoren muessen das gleiche Layout haben!
|
|
Error using +
|
|
Matrix dimensions must agree.
|
|
\end{lstlisting}
|
|
|
|
Bei der Multiplikation, der Division und der Potenzierung mu{\ss} mit
|
|
vorangestellem '.' angezeigt werden, dass es sich um eine
|
|
\emph{elementweise} Verarbeitung handeln soll. F\"ur diese
|
|
elementweisen Operationen kennt \matlab{} die Operatoren
|
|
\code[Operator!arithmetischer!3mule@.*]{.*},
|
|
\code[Operator!arithmetischer!4dive@./]{./} und
|
|
\code[Operator!arithmetischer!5powe@.\^{}]{.\^{}}
|
|
(Listing~\ref{vectorelemmultiplicationlisting}).
|
|
|
|
\begin{lstlisting}[caption={Elementweise Multiplikation, Division und
|
|
Potenzierung von Vektoren.},label=vectorelemmultiplicationlisting]
|
|
>> a .* b % Elementweise Multiplikation
|
|
ans =
|
|
16 27 24
|
|
|
|
>> a ./ b % Elementweise Division
|
|
ans =
|
|
1 3 6
|
|
|
|
>> a ./ b % Elementweise Potenzierung
|
|
ans =
|
|
256 729 144
|
|
|
|
>> a .* c % Beide Vektoren muessen gleich gross sein!
|
|
Error using .*
|
|
Matrix dimensions must agree.
|
|
>> a .* d % Beide Vektoren muessen das gleiche Layout haben!
|
|
Error using .*
|
|
Matrix dimensions must agree.
|
|
\end{lstlisting}
|
|
|
|
Die einfachen Operatoren \code[Operator!arithmetischer!3mul@*]{*},
|
|
\code[Operator!arithmetischer!4div@/]{/} und
|
|
\code[Operator!arithmetischer!5pow@\^{}]{\^{}} sind mit den
|
|
entsprechenden Matrixoperationen aus der linearen Algebrar belegt (Box
|
|
\ref{matrixmultiplication}). Insbesondere ist die Multiplikation eines
|
|
Zeilenvektors $\vec a$ mit einem Spaltenvektor $\vec b$ das Skalarprodukt
|
|
$\sum_i = a_i b_i$.
|
|
|
|
\begin{lstlisting}[caption={Multiplikation von Vektoren.},label=vectormultiplicationlisting]
|
|
>> a * b % Multiplikation zweier Zeilenvektoren
|
|
Error using *
|
|
Inner matrix dimensions must agree.
|
|
>> a' * b' % Multiplikation zweier Spaltenvektoren
|
|
Error using *
|
|
Inner matrix dimensions must agree.
|
|
|
|
>> a * b' % Multiplikation Zeilenvektor mit Spaltenvektor
|
|
ans =
|
|
67
|
|
|
|
>> a' * b % Multiplikation Spaltenvektor mit Zeilenvektor
|
|
ans =
|
|
16 12 8
|
|
36 27 18
|
|
48 36 24
|
|
\end{lstlisting}
|
|
|
|
\pagebreak[4]
|
|
Zum Entfernen von Elementen aus einem Vektor, wird den
|
|
entsprechenden Zellen ein leeren Wert (\code[Operator!Matrix!{[]}]{[]}) zugewiesen:
|
|
\begin{lstlisting}[label=vectoreraselisting, 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]) = [] % loesche das erste und dritte Element
|
|
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{vectorinsertlisting}, Zeile
|
|
10). Zum Erweitern eines Vektors kann \"uber das Ende hinaus
|
|
zugewiesen werden (Zeile 20). \matlab{} erweitert dann die Variable
|
|
entsprechend. Dieser Vorgang ist rechenintensiv da der ganze Vektor
|
|
an eine neue Stelle im Arbeitsspeicher kopiert wird und sollte, soweit
|
|
m\"oglich, vermieden werden.
|
|
|
|
\begin{lstlisting}[caption={Zusammenf\"ugen und Erweitern von Vektoren.}, label=vectorinsertlisting]
|
|
>> a = [4 3 2 1];
|
|
>> b = [10 12 14 16];
|
|
>> c = [a b] % erstelle einen Vektor aus einer Liste von Vektoren
|
|
c =
|
|
4 3 2 1 10 12 14 16
|
|
>> length(c)
|
|
ans = 8
|
|
>> length(a) + length(b)
|
|
ans = 8
|
|
|
|
>> c = [a b']; % Vektorlayout muss uebereinstimmen
|
|
Error using horzcat
|
|
Dimensions of matrices being concatenated are not consistent.
|
|
|
|
>> a(1:3) = [5 6 7] % Weise den ersten drei Elementen neue Werte zu
|
|
a =
|
|
5 6 7 1
|
|
>> a(1:3) = [1 2 3 4]; % Laenge der Vektoren muss uebereinstimmen
|
|
In an assignment A(I) = B, the number of elements in B and I must be the same.
|
|
|
|
>> a(3:6) = [1 2 3 4] % Zuweisung ueber die Laenge des Vektors hinweg
|
|
a =
|
|
5 6 1 2 3 4
|
|
\end{lstlisting}
|
|
|
|
|
|
\subsection{Matrizen}
|
|
|
|
Vektoren sind 1-dimensionale Spezialf\"alle von $n$-dimensionalen
|
|
Matrizen. Matrizen k\"onnen in \matlab{} beliebig viele Dimensionen
|
|
haben. 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}
|
|
\titlecaption{Matrizen.}{\textbf{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[Operator!Matrix!{[]}]{[]} eingeschlossen. Das
|
|
Semikolon \code[Operator!Matrix!;]{;} 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, 4, 2)
|
|
b(:,:,1) =
|
|
1 1 1 1
|
|
1 1 1 1
|
|
1 1 1 1
|
|
b(:,:,2) =
|
|
1 1 1 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). Die \code{cat()}-Funktion kann
|
|
mehrdimensionale Matrizen zusammenzuf\"ugen.
|
|
|
|
Um Informationen \"uber die Gr\"o{\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. Die \code{size()}-Funktion
|
|
gibt dagegen die L\"ange jeder Dimension als Vektor zur\"uck.
|
|
|
|
\begin{figure}
|
|
\includegraphics[width=0.9\columnwidth]{matrixIndexing}
|
|
\titlecaption{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\"ur 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
|
|
\codeterm{subscript indexing} genannt. Dabei bestimmt die errste Zahl
|
|
die Zeilennumer, die zweite die Splatennumer.
|
|
|
|
\begin{lstlisting}[caption={Zugriff auf Inhalte von Matrizen,
|
|
Indizierung.}, label=matrixIndexing]
|
|
>> x=rand(3,4) % 2-D Matrix mit Zufallszahlen mit 3 Zeilen und 4 Spalten
|
|
x =
|
|
0.8147 0.9134 0.2785 0.9649
|
|
0.9058 0.6324 0.5469 0.1576
|
|
0.1270 0.0975 0.9575 0.9706
|
|
>> size(x)
|
|
ans =
|
|
3 4
|
|
|
|
>> x(1,1) % obere linke Ecke
|
|
ans =
|
|
0.8147
|
|
>> x(2,3) % Element der 2. Zeile, 3. Spalte
|
|
ans =
|
|
0.5469
|
|
|
|
>> x(1,:) % erste Zeile
|
|
ans =
|
|
0.8147 0.9134 0.2785 0.9649
|
|
>> x(:,2) % zweite Spalte
|
|
ans =
|
|
0.9134
|
|
0.6324
|
|
0.0975
|
|
\end{lstlisting}
|
|
|
|
Alternativ zum \codeterm{subscript indexing} k\"onnen die Zellen einer
|
|
Matrize auch \emph{linear} angesprochen werden (Abbildung
|
|
\ref{matrixlinearindexingfig}). Diese Art der Adressierung ist nicht
|
|
so intuitiv verst\"andlich, kann aber sehr hilfreich sein. Der lineare
|
|
Index einer Zelle reicht von 1 bis \code{numel()} Elemente. Wobei
|
|
dieser erst entlang der 1. Dimension, dann der 2., 3. etc. Dimension
|
|
ansteigt. Listing \ref{matrixLinearIndexing} zeigt ein Beispiel f\"ur
|
|
den Einsatz des linearen Indizierens, z.B. zum Ermitteln des kleinsten
|
|
Wertes in einer Matrize.
|
|
|
|
\begin{figure}
|
|
\includegraphics[width=0.9\columnwidth]{matrixLinearIndexing}
|
|
\titlecaption{Lineares Indizieren 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 Indizieren 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))) % Minimum ueber die Zeilen, Spalten, Blaetter...
|
|
ans =
|
|
4
|
|
>> min(x(:)) % oder so
|
|
ans =
|
|
4
|
|
\end{lstlisting}
|
|
|
|
\begin{ibox}[t]{\label{matrixmultiplication} Matrixmultiplikation.}
|
|
Die Matrixmuliplikation aus der linearen Algebra ist nicht eine
|
|
elementweise Multiplikation. Die Matrixmultiplikation ist nur dann
|
|
m\"oglich, wenn die Anzahl Spalten der ersten Matrize gleich der
|
|
Anzahl Zeilen in der zweiten Matrize ist. Formaler: zwei Matrizen
|
|
$\mathbf{A}$ und $\mathbf{B}$ k\"onnen mulipiziert $(\mathbf{A}
|
|
\cdot \mathbf{B})$ werden, wenn $\mathbf{A}$ die Gr\"o{\ss}e $(m \times n)$ und
|
|
$\mathbf{B}$ die Gr\"o{\ss}e $(n \times k)$ hat. Die Mulitplikation ist
|
|
m\"oglich wenn die \determ{inneren Dimensionen} $n$ gleich sind.
|
|
|
|
Dann sind die Elemente $c_{i,j}$ des Matrixprodukts $\mathbf{C} =
|
|
\mathbf{A} \cdot \mathbf{B}$ gegeben durch das Skalarprodukt jeder
|
|
Zeile von $\mathbf{A}$ mit jeder Spalte aus $\mathbf{B}$:
|
|
\[ c_{i,j} = \sum_{k=1}^n a_{i,k} \; b_{k,j} \; . \]
|
|
|
|
Die Matrixmultiplikation ist im Allgemeinen auch nicht kommutativ:
|
|
\[ \mathbf{A} \cdot \mathbf{B} \ne \mathbf{B} \cdot \mathbf{A} \; . \]
|
|
|
|
Als Beispiel betrachten wir die beiden Matrizen
|
|
\[\mathbf{A}_{(3 \times 2)} = \begin{pmatrix} 1 & 2 \\ 5 & 4 \\ -2 & 3 \end{pmatrix}
|
|
\quad \text{und} \quad \mathbf{B}_{(2 \times 2)} = \begin{pmatrix}
|
|
-1 & 2 \\ -2 & 5 \end{pmatrix} \; . \]
|
|
F\"ur das Produkt $\mathbf{A} \cdot \mathbf{B}$ stimmen die inneren
|
|
Dimensionen der Matrizen \"uberein ($(3 \times 2) \cdot (2
|
|
\times 2)$), die Matrixmultiplikation ist also m\"oglich. Nachdem
|
|
$\mathbf{A}$ drei Zeilen und $\mathbf{B}$ zwei Spalten hat, hat das
|
|
Ergebnis von $\mathbf{A} \cdot \mathbf{B}$ die Gr\"o{\ss}e $(3
|
|
\times 2)$:
|
|
\[ \mathbf{A} \cdot \mathbf{B} = \begin{pmatrix} 1 \cdot -1 + 2 \cdot -2 & 1 \cdot 2 + 2\cdot 5 \\
|
|
5 \cdot -1 + 4 \cdot -2 & 5 \cdot 2 + 4 \cdot 5\\
|
|
-2 \cdot -1 + 3 \cdot -2 & -2 \cdot 2 + 3 \cdot 5 \end{pmatrix}
|
|
= \begin{pmatrix} -5 & 12 \\ -13 & 30 \\ -4 & 11\end{pmatrix} \; . \]
|
|
|
|
Das Produkt $\mathbf{B} \cdot \mathbf{A}$ ist dagegen nicht
|
|
definiert, da die inneren Dimensionen nicht \"ubereinstimmen
|
|
($(2 \times 2) \cdot (3 \times 2)$).
|
|
\end{ibox}
|
|
|
|
Beim Rechnen mit Matrizen gelten die gleichen Regeln wie bei
|
|
Vektoren. Matrizen k\"onnen solange elementweise miteinander
|
|
verrechnet werden, wie die Dimensionalit\"aten
|
|
\"ubereinstimmen. Wichtig ist auch hier wieder die Unterscheidung
|
|
zwischen elementweiser Multiplikation
|
|
(\code[Operator!arithmetischer!3mule@.*]{.*} Operator, Listing
|
|
\ref{matrixOperations} Zeile 10) oder Matrixmultiplikation
|
|
(\code[Operator!arithmetischer!3mul@*]{*} Operator, Listing
|
|
\ref{matrixOperations} Zeile 14, 17 und 21, Box~\ref{matrixmultiplication}).
|
|
Bei der Matrixmultiplikation m\"ussen die inneren Dimensionen der Matrizen \"ubereinstimmen
|
|
(Box~\ref{matrixmultiplication}).
|
|
|
|
\pagebreak[4]
|
|
\begin{lstlisting}[label=matrixOperations, caption={Zwei Arten der Multiplikation von Matrizen.}]
|
|
>> A = randi(5, [2, 3]) % 2-D Matrix
|
|
A =
|
|
1 5 3
|
|
3 2 2
|
|
>> B = randi(5, [2, 3]) % dito
|
|
B =
|
|
4 3 5
|
|
2 4 5
|
|
|
|
>> A .* B % elementweise Multiplikation
|
|
ans =
|
|
4 15 15
|
|
6 8 10
|
|
>> A * B % Matrixmultiplikation
|
|
Error using *
|
|
Inner matrix dimensions must agree.
|
|
>> A * B' % Matrixmultiplikation
|
|
ans =
|
|
34 37
|
|
28 24
|
|
>> A' * B % Matrixmultiplikation
|
|
ans =
|
|
10 15 20
|
|
24 23 35
|
|
16 17 25
|
|
\end{lstlisting}
|
|
|
|
\section{Boolesche Operationen}
|
|
|
|
Boolesche Ausdr\"ucke sind Anweisungen, die zu \codeterm{wahr} oder
|
|
\codeterm{falsch} ausgewertet werden. Man kennt sie z.B. aus der
|
|
Mengenlehre. In der Programmierung werden sie eingesetzt, um z.B. die
|
|
Beziehung zwischen Entit\"aten zu testen. Hierzu werden die
|
|
\codeterm{relationalen Operatoren} (\code[Operator!relationaler!>]{>},
|
|
\code[Operator!relationaler!<]{<},
|
|
\code[Operator!relationaler!==]{==},
|
|
\code[Operator!relationaler!"!]{!}, gr\"o{\ss}er als, kleiner als,
|
|
gleich und nicht) eingesetzt. Mehrere Ausdr\"ucke werden mittels der
|
|
\codeterm[Operator!logischer]{logischen Operatoren}
|
|
(\code[Operator!logischer!and1@\&]{\&}, \code[Operator!logischer!or1@{"|} {}]{|},
|
|
UND, ODER) verkn\"upft. Sie sind 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 Tabellen \ref{logicalandor} zeigen die Wahrheitstabellen f\"ur das
|
|
logische UND, das logische ODER und das logische XOR
|
|
(entweder-oder). 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. Anders
|
|
ist das beim logischen ODER. Hier ist der gesamte Ausdruck wahr, wenn
|
|
sich der eine \emph{oder} der andere Ausdruck, oder beide Ausdr\"ucke
|
|
zu wahr auswerten lassen. Das auschlie{\ss}ende ODER (XOR) ist nur
|
|
wahr, wenn entweder der eine oder der andere Ausdruck wahr ist und ist
|
|
in \matlab{} als Funktion \code[xor()]{xor(A, B)} verf\"ugbar.
|
|
|
|
\begin{table}[tp]
|
|
\titlecaption{Wahrheitstabellen logisches UND, ODER und XOR.}{}\label{logicalandor}
|
|
\begin{tabular}{llll}
|
|
\multicolumn{2}{l}{\multirow{2}{*}{}} & \multicolumn{2}{c}{\textbf{B}} \\
|
|
& \sffamily{\textbf{und}} & \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} \erb \\
|
|
& \multicolumn{1}{l|}{falsch} & \multicolumn{1}{l}{\textcolor{red}{falsch}} & \textcolor{red}{falsch}
|
|
\end{tabular}
|
|
\hfill
|
|
\begin{tabular}{llll}
|
|
\multicolumn{2}{l}{\multirow{2}{*}{}} & \multicolumn{2}{c}{\textbf{B}} \\
|
|
& \sffamily{\textbf{oder}} & \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} \erb \\
|
|
& \multicolumn{1}{l|}{falsch} & \multicolumn{1}{l}{\textcolor{mygreen}{wahr}} & \textcolor{red}{falsch}
|
|
\end{tabular}
|
|
\hfill
|
|
\begin{tabular}{llll}
|
|
\multicolumn{2}{l}{\multirow{2}{*}{}} & \multicolumn{2}{c}{\textbf{B}} \\
|
|
& \sffamily{\textbf{xor}} & \multicolumn{1}{|c}{wahr} & falsch \\ \cline{2-4}
|
|
\multirow{2}{*}{\textbf{A}} & \multicolumn{1}{l|}{wahr} & \multicolumn{1}{c}{\textcolor{red}{falsch}} & \textcolor{mygreen}{wahr} \erb \\
|
|
& \multicolumn{1}{l|}{falsch} & \multicolumn{1}{l}{\textcolor{mygreen}{wahr}} & \textcolor{red}{falsch}
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
Tabelle \ref{logicalrelationaloperators} zeigt die logischen Operatoren, die in
|
|
\matlab{} definiert sind. Zu bemerken sind hier noch die
|
|
\code[Operator!logischer!and2@\&\&]{\&\&} und
|
|
\code[Operator!logischer!or2@{"|}{"|} {}]{||} 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 ausgewertet wird,
|
|
muss der zweite gar nicht mehr gepr\"uft werden. Die Verwendung der
|
|
\enterm{short-circuit} Versionen spart Rechenzeit, da die Ausdr\"ucke
|
|
nur sowei wie n\"otig ausgewertet werden.
|
|
|
|
\begin{table}[t]
|
|
\titlecaption{\label{logicalrelationaloperators}
|
|
Logische (links) und relationale (rechts) Operatoren in \matlab.}{}
|
|
\begin{tabular}{cc}
|
|
\hline
|
|
\textbf{Operator} & \textbf{Beschreibung} \erh \\ \hline
|
|
\varcode{$\sim$} & logisches NICHT \erb \\
|
|
\varcode{$\&$} & logisches UND\\
|
|
\varcode{$|$} & logisches ODER\\
|
|
\varcode{$\&\&$} & short-circuit logisches UND\\
|
|
\varcode{$\|$} & short-circuit logisches ODER\\
|
|
\hline
|
|
\end{tabular}
|
|
\hfill
|
|
\begin{tabular}{cc}
|
|
\hline
|
|
\textbf{Operator} & \textbf{Beschreibung} \erh \\ \hline
|
|
\varcode{$==$} & gleich \erb \\
|
|
\varcode{$\sim=$} & ungleich\\
|
|
\varcode{$>$} & gr\"o{\ss}er als \\
|
|
\varcode{$<$} & kleiner als \\
|
|
\varcode{$>=$} & gr\"o{\ss}er oder gleich \\
|
|
\varcode{$<=$} & kleiner oder gleich \\
|
|
\hline
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
Um Werte miteinander zu vergleichen gibt es die
|
|
\codeterm[Operator!relationaler]{relationalen Operatoren} (Tabelle
|
|
\ref{logicalrelationaloperators}). Mit ihnen kann man auf Dinge wie
|
|
Gleichheit (\varcode{==}) gr\"o{\ss}er oder kleiner als (\varcode{>},
|
|
\varcode{<}) testen.
|
|
|
|
\begin{important}[Zuweisungs- und Gleichheitsoperator]
|
|
Der Zuweisungsoperator \code[Operator!Zuweisung!=]{=} und der
|
|
logische Operator \code[Operator!logischer!==]{==} sind zwei
|
|
grundverschiedene Dinge. Da sie umgangsprachlich gleich sind
|
|
k\"onnen sie leider leicht verwechselt werden.
|
|
\end{important}
|
|
|
|
Das Ergebnis eines booleschen Ausdrucks ist immer vom Datentyp
|
|
\codeterm{logical}. Jede beliebige Variable zu wahr oder falsch
|
|
ausgewertet werden indem diese in den Typ \code{logical} umgewandelt
|
|
wird. 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 Synonyme f\"ur die \code{logical} Werte 1 und
|
|
0.
|
|
|
|
\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 boolesche Ausdr\"ucke ist das
|
|
logische Indizieren. Logisches 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 durch die
|
|
Verwendung eines booleschen Ausdrucks auf z.B. einen Vektor ein
|
|
logischer Vektor gleicher Gr\"o{\ss}e zur\"uckgegeben wird. Dieser
|
|
wird benutzt um die Elemente des urspr\"unglichen Vektors
|
|
auszuw\"ahlen, bei denen der logische Vektor \codeterm{wahr} ist
|
|
(Listing \ref{logicalindexing1}). Zeile 14 kann wie
|
|
folgt gelesen werden: Gib die Elemente von \varcode{x} an den
|
|
Stellen, an denen \varcode{x < 0} wahr ist, zur\"uck.
|
|
|
|
\begin{lstlisting}[caption={Beispiel logisches Indizieren.}, label=logicalindexing1]
|
|
>> x = randn(1, 6) % Zeilenvektor mit 6 Zufallszahlen
|
|
x =
|
|
-1.4023 -1.4224 0.4882 -0.1774 -0.1961 1.4193
|
|
|
|
>> % logisches Indizieren in zwei Schritten:
|
|
>> x_smaller_zero = x < 0 % logischer Vektor
|
|
x_smaller_zero =
|
|
1 1 0 1 1 0
|
|
>> elements_smaller_zero = x(x_smaller_zero) % benutzen, um zuzugreifen
|
|
elements_smaller_zero =
|
|
-1.4023 -1.4224 -0.1774 -0.1961
|
|
|
|
>> % logisches Indizieren in einem Schritten:
|
|
>> elements_smaller_zero = x(x < 0)
|
|
elements_smaller_zero =
|
|
-1.4023 -1.4224 -0.1774 -0.1961
|
|
\end{lstlisting}
|
|
|
|
\begin{exercise}{logicalVector.m}{logicalVector.out}
|
|
Erstelle einen Vektor \varcode{x} mit den Werten 0--10.
|
|
\begin{enumerate}
|
|
\item F\"uhre aus: \varcode{y = x < 5}
|
|
\item Gib den Inhalt von \varcode{y} auf dem Bildschirm aus.
|
|
\item Was ist der Datentyp von \varcode{y}?
|
|
\item Gibt alle Elemente aus \varcode{x} zur\"uck, die kleiner als 5 sind.
|
|
\end{enumerate}
|
|
\pagebreak[4]
|
|
\end{exercise}
|
|
|
|
\begin{figure}[t]
|
|
\includegraphics[width= 0.9\columnwidth]{logicalIndexingTime}
|
|
\titlecaption{Beispiel f\"ur logisches Indizieren.}
|
|
{Der rot markierte Abschnitt aus den Daten wurde indirekt
|
|
mit logischem Indizieren auf dem Zeitvektor
|
|
ausgew\"ahlt (\varcode{x(t > 5 \& t < 6)}).}\label{logicalindexingfig}
|
|
\end{figure}
|
|
|
|
Logisches Indizieren wurde oben so benutzt, dass die Auswahl auf dem
|
|
Inhalt desselben Vektors beruhte. Ein weiterer sehr h\"aufiger Fall
|
|
ist jedoch, dass die Auswahl aus einem Vektor auf dem Inhalt eines
|
|
zweiten Vektors basiert. Ein Beispiel ist, dass \"uber einen
|
|
gewissen Zeitraum Daten aufgenommen werden und aus diesen die Daten eines
|
|
bestimmten Zeitraums ausgew\"ahlt werden sollen (\figref{logicalindexingfig}).
|
|
|
|
\begin{exercise}{logicalIndexingTime.m}{}
|
|
Angenommen es werden \"uber einen bestimmten Zeitraum Messwerte
|
|
genommen. Bei solchen Messungen erh\"alt man einen Vektor, der die
|
|
Zeitpunkte der Messung speichert und einen zweiten mit den
|
|
jeweiligen Messwerten.
|
|
|
|
\begin{itemize}
|
|
\item Erstelle einen Vektor \varcode{t = 0:0.001:10;}, der die Zeit
|
|
repr\"asentiert.
|
|
\item Erstelle einen zweiten Vektor \varcode{x} mit Zufallszahlen, der
|
|
die gleiche L\"ange hat wie \varcode{t}. Die Werte darin stellen
|
|
Messungen zu den Zeitpunkten in \varcode{t} dar.
|
|
\item Benutze 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 wiederholt oder nur
|
|
unter bestimmten Bedingungen ausgef\"uhrt werden sollen. 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 Wiederholungen einzelner
|
|
Zeilen oder ganzer 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 Wiederholungen die entscheidende
|
|
\"Anderung auch wirklich vorzunehmen.
|
|
\shortquote{Copy and paste is a design error.}{David Parnas}
|
|
\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 ein Fehler gemacht wurde, dann muss der Fehler in
|
|
allen Wiederholungen korrigiert werden (sehr leicht wird dabei etwas
|
|
\"ubersehen).
|
|
\item Verst\"andlichkeit: Solche Abschnitte sind schwerer zu lesen und
|
|
schwer 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. Zum Anderen
|
|
f\"uhrt Codeduplication zu langen, un\"ubersichtlichen Programmen.
|
|
\end{enumerate}
|
|
Alle Programmiersprachen bieten zur L\"osung dieses Problems die
|
|
Schleifen. Eine Schleife wird immer dann eingesetzt, wenn
|
|
Abschnitte wiederholt ausgef\"uhrt werden sollen.
|
|
|
|
\subsubsection{Die \code{for} -- Schleife}
|
|
|
|
Der am h\"aufigsten benutzte Vertreter der Schleifen ist die
|
|
\codeterm{for-Schleife}. Sie besteht aus dem
|
|
\codeterm[Schleife!Schleifenkopf]{Schleifenkopf} und dem
|
|
\codeterm[Schleife!Schleifenk{\"o}rper]{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 \codeterm{Laufvariable} definiert wird. In \matlab
|
|
``l\"auft''/iteriert eine for-Schleife immer(!) \"uber einen
|
|
Vektor. Die \codeterm{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 \varcode{for}-Schleife.}, label=looplisting]
|
|
>> for x = 1:3
|
|
x
|
|
end
|
|
% die Laufvariable x nimmt mit jeder Iteration der Schleife
|
|
% einen Wert des Vektors 1:3 an:
|
|
1
|
|
2
|
|
3
|
|
\end{lstlisting}
|
|
|
|
|
|
\begin{exercise}{facultyLoop.m}{facultyLoop.out}
|
|
Wie k\"onnte Fakult\"at mit einer Schleife implementiert werden?
|
|
Implementiere eine \code{for} Schleife, die die Fakul\"at von einer
|
|
Zahl \varcode{n} berechnet.
|
|
\end{exercise}
|
|
|
|
|
|
\subsubsection{Die \varcode{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 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 \varcode{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.
|
|
Das Programm kann mit \keycode{Ctrl+C} abgebrochen werden.
|
|
\end{exercise}
|
|
|
|
|
|
\subsubsection{Vergleich \varcode{for} -- und \varcode{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 (au{\ss}er wenn der Vektor im Schleifenkopf leer ist).
|
|
\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 \varcode{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 \code{if} - Anweisung beginnt mit dem Schl\"usselwort \code{if}
|
|
welches von einem 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 wurden. Die \code{if} - Anweisung wird mit \code{end}
|
|
beendet. Listing \ref{ifelselisting} zeigt den Aufbau einer
|
|
\code{if} - Anweisung.
|
|
|
|
|
|
\begin{lstlisting}[label=ifelselisting, caption={Grundger\"ust einer \varcode{if} Anweisung.}]
|
|
if x < y
|
|
% fuehre diesen code aus wenn x < y
|
|
elseif x > y
|
|
% etwas anderes soll getan werden fuer x > y
|
|
else
|
|
% wenn x == y, wieder etwas anderes
|
|
end
|
|
\end{lstlisting}
|
|
|
|
\begin{exercise}{ifelse.m}{}
|
|
Ziehe eine Zufallszahl und \"uberpr\"ufe mit einer geeigneten \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 (i) kleiner als 0.5, (ii) gr\"o{\ss}er oder gleich 0.5 aber kleiner
|
|
als 0.75 oder (iii) gr\"o{\ss}er oder gleich 0.75 ist.
|
|
\end{enumerate}
|
|
\end{exercise}
|
|
|
|
\subsubsection{Die \varcode{switch} -- Verzweigung}
|
|
|
|
Die \code{switch} Verzweigung wird eingesetzt wenn mehrere F\"alle
|
|
auftreten k\"onnen, die einer unterschiedlichen Behandlung bed\"urfen.
|
|
|
|
Sie wird mit dem Schl\"usselwort \code{switch} begonnen, gefolgt von der
|
|
\codeterm{switch Anweisung} (Zahl oder String). Jeder Fall, auf den diese
|
|
Anweisung \"uberpr\"uft werden soll, wird mit dem Schl\"usselwort
|
|
\code{case} eingeleitet. Dieses wird gefolgt von der \codeterm{case
|
|
Anweisung}, die definiert gegen welchen Fall auf
|
|
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 \varcode{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 Gleichheit der
|
|
switch-Anweisung und der case-Anweisung getestet wird.
|
|
|
|
|
|
\subsubsection{Vergleich \varcode{if} -- Anweisung und \varcode{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 (Listings \ref{continuelisting}
|
|
und \ref{continuelisting} zeigen, wie sie eingesetzt werden k\"onnen).
|
|
|
|
\begin{lstlisting}[caption={Abbrechen von Schleifen mit \varcode{break}.}, label=breaklisting]
|
|
>> x = 1;
|
|
while true
|
|
if (x > 3)
|
|
break;
|
|
end
|
|
disp(x);
|
|
x = x + 1;
|
|
end
|
|
% output:
|
|
1
|
|
2
|
|
3
|
|
\end{lstlisting}
|
|
|
|
\begin{lstlisting}[caption={\"Uberspringen von Code-Abschnitten in Schleifen mit \varcode{continue}.}, label=continuelisting]
|
|
for x = 1:5
|
|
if(x > 2 & x < 5)
|
|
continue;
|
|
end
|
|
disp(x);
|
|
end
|
|
% output:
|
|
1
|
|
2
|
|
5
|
|
\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 \codeterm[Skript]{Skripte}
|
|
\item \codeterm[Funktion]{Funktionen}
|
|
\item \codeterm[Objekt]{Objekte} (werden wir hier nicht behandeln)
|
|
\end{enumerate}
|
|
Alle Programme werden in den sogenannten \codeterm{m-files} gespeichert
|
|
(z.B. \file{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 erzeugt wurde im
|
|
\codeterm{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 \codeterm[Funktion]{Funktionen}.
|
|
|
|
\subsection{Funktionen}
|
|
|
|
Eine Funktion in \matlab{} wird \"ahnlich zu einer mathematischen
|
|
Funktion definiert:
|
|
\[ y = f(x) \]
|
|
Die Funktion hat einen Namen $f$, sie \"uber das Argument $x$
|
|
einen Input und liefert ein Ergebnis in $y$ zur\"uck. Listing
|
|
\ref{functiondefinitionlisting} zeigt wie das in \matlab{} umgesetzt
|
|
wird.
|
|
|
|
\begin{lstlisting}[caption={Funktionsdefinition in \matlab{}}, label=functiondefinitionlisting]
|
|
function [y] = functionName(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={Ein schlechtes Beispiel einer Funktion, die eine Reihe Sinusse plottet.},label=badsinewavelisting]
|
|
function meineErsteFunktion() % 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
|
|
\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 auf 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 und 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}
|
|
Sinusse. (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 \codeterm[Funktion!Name]{Name}: der Name sollte beschreiben, was
|
|
die Funktion tut. In diesem Fall berechnet sie einen Sinus. Ein
|
|
geeigneter, kurzer Name w\"are also \code{sinewave()}.
|
|
\item \codeterm[Funktion!Argumente]{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: \varcode{amplitude}, \varcode{frequency},
|
|
\varcode{t\_max}, \varcode{t\_step}.
|
|
\item \codeterm[Funktion!R{\"u}ckgabewerte]{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: \varcode{time}, \varcode{sine}
|
|
\end{enumerate}
|
|
Mit dieser Information ist es nun gut m\"oglich die Funktion zu
|
|
implementieren (Listing \ref{sinefunctionlisting}).
|
|
|
|
\begin{lstlisting}[caption={Funktion zur Berechnung eines Sinus.}, label=sinefunctionlisting]
|
|
function [time, sine] = sinewave(frequency, amplitude, t_max, t_step)
|
|
% Calculate a sinewave of a given frequency, amplitude,
|
|
% duration and temporal resolution.
|
|
%
|
|
% [time, sine] = sinewave(frequency, amplitude, t_max, t_step)
|
|
%
|
|
% 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: vector of the time axis
|
|
% sine: vector of the calculated sinewave
|
|
time = (0:t_step:t_max);
|
|
sine = sin(frequency .* time .* 2 * pi) .* amplitude;
|
|
end
|
|
\end{lstlisting}
|
|
|
|
|
|
\paragraph{II. Plotten einer einzelnen Schwingung}
|
|
Das Plotten der berechneten Sinuschwingung 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{plotFunction()}). 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 zur graphischen Darstellung der Daten.}, label=sineplotfunctionlisting]
|
|
function plotFunction(x_data, y_data, name)
|
|
% Plots x-data against y-data and sets the display name.
|
|
%
|
|
% plotFunction(x_data, y_data, name)
|
|
%
|
|
% Arguments:
|
|
% x_data: vector of the x-data
|
|
% y_data: vector of the y-data
|
|
% name : the displayname
|
|
plot(x_data, y_data, 'displayname', name)
|
|
end
|
|
\end{lstlisting}
|
|
|
|
|
|
\paragraph{III. Erstellen eines Skriptes zur Koordinierung}
|
|
Die letzte Aufgabe ist die Koordinierung der Berechung und des
|
|
Plottens f\"ur mehrere Amplituden. Das ist die klassische Aufgabe
|
|
f\"ur ein \codeterm{Skript}. Auch hier gilt es einen ausdrucksvollen
|
|
Name zu finden. Da es keine Argumente und R\"uckgabewerte gibt,
|
|
m\"ussen die ben\"otigten Informationen direkt in dem Skript
|
|
defniniert werden. Es werden ben\"otigt: 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 mit
|
|
\code{figure()} 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 zur Koordination von Berechnung und graphischer Darstellung.},label=sinesskriptlisting]
|
|
amplitudes = 0.25:0.25:1.25;
|
|
frequency = 2.0;
|
|
t_max = 10.0;
|
|
t_step = 0.01;
|
|
|
|
figure()
|
|
hold on
|
|
for i = 1:length(amplitudes)
|
|
[x_data, y_data] = sinewave(frequency, amplitudes(i), ...
|
|
t_max, t_step);
|
|
plotFunction(x_data, y_data, sprintf('freq: %5.2f, ampl: %5.2f',...
|
|
frequency, amplitudes(i)))
|
|
end
|
|
hold off
|
|
legend('show')
|
|
\end{lstlisting}
|
|
|
|
\begin{exercise}{plotMultipleSinewaves.m}{}
|
|
Erweiter das Programm so, dass die Sinusse f\"ur einen Satz von
|
|
Frequenzen geplottet wird.
|
|
\pagebreak[4]
|
|
\end{exercise}
|
|
|
|
\subsection{Einsatz von Funktionen und Skripten}
|
|
|
|
Funktionen sind kleine Codefragmente, die im Idealfall genau eine
|
|
Aufgabe erledigen. Sie besitzen einen eigenen
|
|
\determ{G\"ultigkeitsbereich}, das hei{\ss}t, dass Variablen aus dem
|
|
globalen Workspace nicht verf\"ugbar sind und Variablen, die lokal in
|
|
der Funktion erstellt werden nicht im globalen Workspace sichtbar
|
|
werden. Dies hat zur Folge, dass Funktionen all die Informationen, die
|
|
sie ben\"otigen, von au{\ss}en erhalten m\"ussen. Sie nehmen
|
|
\determ{Argumente} entgegen und k\"onnen \determ{R\"uckgabwerte}
|
|
zur\"uckliefern.
|
|
|
|
Die Verwendung von Funktionen ist der Verwendung von Skripten fast
|
|
immer vorzuziehen sind. Das hei{\ss}t aber nicht, das Skripte zu
|
|
verteufeln w\"aren und und vermieden werden sollten. In Wahrheit sind
|
|
beide daf\"ur gemacht, Hand in Hand ein Problem zu l\"osen. W\"ahrend
|
|
die Funktionen relativ kleine ``verdauliche'' Teilprobleme l\"osen,
|
|
werden Skripte eingesetzt um den Rahmen zu bilden und den Ablauf zu
|
|
koordinieren (Abbildung \ref{programlayoutfig}).
|
|
|
|
\begin{figure}
|
|
\includegraphics[width=0.5\columnwidth]{simple_program.pdf}
|
|
\titlecaption{Ein typisches Programmlayout.}{Das Kontrollskript
|
|
koordiniert den Aufruf der Funktionen, \"ubergibt Argumente und
|
|
nimmt R\"uckgabewerte entgegen.}\label{programlayoutfig}
|
|
\end{figure}
|