2 Gnu Octave | |
→ | 2.6 Eingabe |
Funktionen werden mit
function [Rückgabevariable(n)] = Funktionsname(Argument(e)) Funktionskörper endfunction
definiert, siehe auch Beispiel Selbsdefinierte Funktion.
Im Funktionskörper müssen die Rückgabevariablen auf den Wert
gesetzt werden, der als Funktionsergebnis zurückgegeben werden
soll.
Die Anweisungen innerhalb einer Funktion werden üblicherweise immer
mit Semikolon abgeschlossen.
Beispiel:
Die Funktion
function [y] = kugeloberflaeche(r) y = 4 * %pi * r ^ 2; endfunction A1 = kugeloberflaeche(3.5);
berechnet die Oberfläche einer Kugel mit gegebenem Radius.
Eine Funktion kann auch mehrere Werte in Form einer Liste zurückgeben, z.B.:
function [A, V] = kugeldaten(r) A = 4 * %pi * r ^ 2; V = (A * r) / 3; endfunction [A1, V1] = kugeldaten(3.5);
Für alle Funktionen, die üblicherweise einen Skalar als Argument
erhalten, ist es sinnvoll, automatische Vektorisierung zu
ermöglichen.
D.h. wird die Funktion mit einem Vektor oder einer Matrix
aufgerufen, soll sie als Ergebnis einen Vektor bzw. eine Matrix
gleicher Größe liefern, wobei die Berechnung auf jedes Element
einzeln angewandt wird.
Wir verwenden die Operatoren für elementweise Berechnungen, wenn
beteiligte Operanden Skalare, Vektoren oder Matrizen sein
dürfen.
function [A, V] = kugeldaten(r) A = 4 * %pi .* r .^ 2; V = (A .* r) / 3; endfunction M1 = [1 2 3 ; 4 5 6 ; 7 8 9]; [A1, V1] = kugeldaten(M1);
Innerhalb einer Funktion sind alle Variablen lokal, d.h. von innerhalb des Funktionskörpers kann nicht auf Variablen außerhalb, z.B. Variablen des Arbeitsbereiches zugegriffen werden.
Soll eine Funktion auf Variablen des Arbeitsbereiches zugreifen, muss die entsprechende Variable vor der ersten Wertzuweisung als "global" definiert werden. Dies muss zum einen in der Funktion passieren (Hinweis, dass die Variable nicht lokal für die Funktion ist), zum anderen im Arbeitsbereich (Erlaubnis zum Zugriff aus Funktionen heraus erteilen).
global a;
a = 5;
function y = test1(x)
global a;
printf('a alt: %g\n', a);
a = x;
printf('a neu: %g\n', a);
y = x;
endfunction
printf('a (1) %g\n', a);
test1(3);
printf('a (2) %g\n', a);
Die Ausgabe
a (1) 5 a alt: 5 a neu: 3 a (2) 3
zeigt, dass die Funktion test() die Variable a des Arbeitsbereiches geändert hat.
Innerhalb einer Funktion kann mit
nargin
die Anzahl der Argumente
und mit
nargout
die Anzahl der erwarteten Rückgabewerte ermittelt werden.
Dies ist insbesondere interessant für Funktionen, die eine Liste
von Rückgabewerten liefern. Derartige Funktionen können auch so
aufgerufen werden, dass die Ergebnisliste (Liste der Variablen auf
der linken Seite der Zuweisung) kleiner ist als die Liste der
Rückgabewerte, die überzähligen Elemente der Rückgabeliste werden
dann ignoriert. Die Berechnung der nicht benötigten Rückgabewerte
kann dann entfallen.
Im Beispiel
function [A, V] = kugeldaten(r) A = NA(size(r)); V = NA(size(r)); if nargout > 0 disp("Berechnung Oberflaeche"); A = (4 * pi) .* r .^ 2; if nargout > 1 disp("Berechnung Volumen"); V = (r .* A) ./ 3; endif endif endfunction M1 = [1 2 3 ; 4 5 6 ; 7 8 9]; [A1, V1] = kugeldaten(M1); A2 = kugeldaten(M1);
wird in der Funktion getestet, wieviele Ergebnisse aus der Rückgabeliste benötigt werden. Die Volumenberechnung wird nur durchgeführt, wenn mehr als ein Element der Rückgabeliste benötigt wird.
Soll die Argumenteanzahl flexibel sein (z.B. um den Mittelwert
verschieden großer Mengen an Zahlen zu bilden), wird nur ein
Argument varargin benutzt. Dieses ist ein Zellenfeld.
Falls eine Mindestanzahl an Argumenten verlang ist, ist
varargin das letzte Argument, steht also nach den
geforderten Argumenten.
Im Beispiel wird eine Funktion my_average() definiert, die
den Durchschnitt von unterschiedlich großen Mengen an Zahlen
bildet.
Da die verwendete Funktion sum() nicht mit Zellenfeldern
arbeitet, werden zunächst alle Elemente des Zellen-Feldes in einer
Matrix zusammengefasst, mit sum() wird die Summe gebildet,
anschließend durch die Anzahl der Elemente im Zellenfeld
dividiert.
function myavg = my_average(varargin) myavg = sum([varargin{:}]) / length(varargin); endfunction my_average(1,2,3) my_average(1,2,3,4,5,6,7)
Soll die Anzahl der Rückgabewerte variabel sein, so wird nur
eine Rückgabevariable varargout (ein Zellen-Feld)
benutzt.
Ist eine Mindestanzahl an Rückgabewerten gefordert, so steht
varargout nach den geforderten Rückgabewerten.
Im Beispiel wird für eine beliebige lange Listen von Zahlen eine
Liste mit den Abweichungen der Zahlen zum Mittelwert der Argumente
generiert.
Die Rückgabelist varargout kann natürlich nur so lang sein
wie die Argumentliste varargin. Wenn weniger Rückgabewerte
verlangt sind, wird nur eine Liste in der verlangten Größe
erzeugt.
Bei den ersten beiden Aufrufen von delta() erfolgt keine
Zuweisung von Ergebnissen zu Variablen, die Rückgabeliste hat somit
die Länge 0.
Die nächsten beiden Aufrufe erzeugen Rückgabelisten mit 3 bzw. 7
Werten.
Der letzte Aufruf führt zu einer Fehlermeldung, da 8 Rückgabewerte
Variablen zugewiesen werden sollen, aber aus 7 Argumenten mit
unserer Funktion nur 7 Rückgabewerte erzeugt werden können.
function varargout = delta(varargin) myavg = sum([varargin{:}]) / length(varargin); lgt = length(varargin); if nargout < lgt lgt = nargout; endif if lgt > 0 for i = 1:lgt varargout{i} = varargin{i} - myavg; endfor endif endfunction delta(1,2,3) delta(1,2,3,4,5,6,7) [a, b, c] = delta(1,2,3,4,5,6,7) [x1, x2, x3, x4, x5, x6, x7] = delta(1, 2, 3, 4, 5, 6, 7) [x1, x2, x3, x4, x5, x6, x7, x8] = delta(1, 2, 3, 4, 5, 6, 7)
In Funktionsaufrufen kann die Zuordnung von Werten zu Funktionsargumenten nicht nur anhand der Reihenfolge erfolgen sondern auch durch Angaben
Name=Wert
Für den Fall, dass nicht alle Argumente angegeben werden, können in der Funktionsdefinition Standardwerte vorgegeben werden:
function [y] = verzinsung(anfangsbetrag=1, zinssatz=1.25, zeit=1) y = anfangsbetrag .* exp(zeit .* log(1+zinssatz/100)); endfunction a = verzinsung(100, 2.5, 20) b = verzinsung(150) b = verzinsung(200, zeit=5) c = verzinsung(250, zinssatz=5.0) d = verzinsung(300, zeit=25, zinssatz=3.0) e = verzinsung()
Mit
return;
kann eine Funktion verlassen werden, ohne den restlichen Funktionskörper abzuarbeiten. Vor der return-Anweisung müssen die Rückgabevariablen gesetzt werden.
Funktionen wie die oben gezeigten können Sie manuell eingeben oder auch in Script-Dateien verwenden.
Da es unpraktisch ist, alle benötigten Funktionen in jeder Octave-Sitzung neu einzugeben oder manuell die entsprechenden Dateien mit den Funktionsdefinitionen zu laden, bietet GNU Octave einen automatischen Such-Mechanismus:
Funktions-Dateien sollten mit einem speziell formatierten Kommentar beginnen, siehe Beispieldatei circle_area.m:
## -*- texinfo -*- ## @deftypefn {Function File} circle_area (@var{r}) ## The function calculates the area for a circle with given radius @var{r}. ## @end deftypefn function [A] = circle_area(r) if nargin == 1 A = pi .* (r .^ 2); else error("circle_area: Expecting radius argument!"); endif endfunction
Dieser Hilfetext wird von
help circle_area
angzeigt.
Wird die Funktion mit fehlerhaften Argumenten verwendet, wird eine Fehlermeldung ausgegeben und dann abgebrochen. Enthält der Text in error() kein abschließendes Newline (wie in unserem Beispiel), werden Trace-Meldungen ausgegeben, von wo aus der Aufruf der Funktion erfolgte (aus welcher Zeile welcher *.m-Datei). Damit kann die passende Stelle für eine Korrektur schnell gefunden werden.
Octave verwaltet einen Suchpfad, dies ist eine Liste von Verzeichnissen, die beim automatischen Laden nach Funktionsdateien durchsucht werden.
Mit
path
wird der Suchpfad angezeigt.
Mit
addpath(genpath('Verzeichnis'));
wird das angebebene Verzeichnis mitsamt allen Unterverzeichnissen am Anfang des Suchpfades eingefügt (vor den Octave-System-Verzeichnissen, aber nach dem aktuellen Verzeichnis).
Mit
addpath(genpath('Verzeichnis'), "-end");
wird der Verzeichnisbaum an das Ende des Suchpfades angehangen.
Beim Start von Octave werden automatisch die Dateien
abgearbeitet, falls vorhanden.
Hier können zwar auch Variablen und Funktionen definiert werden,
hauptsächlich werden diese Dateien aber benutzt, um mit
addpath() den Suchpfad für Funktionsdateien zu
erweitern.
Das SourceForge-Projekt Octave-Forge stellt zusätzliche Pakete
für Octave bereit.
Sie finden das Projekt unter http://octave.sourceforge.net.
Hier finden Sie unter "Packages" auch eine Liste der verfügbaren
Pakete mit Informationen zum jeweiligen Verwendungszweck und einem
API der enthaltenen Funktionen.
Die Installation von Octave-Forge-Paketen erfolgt aus Octave
heraus. Sind Sie dabei als "normaler" Benutzer angemeldet, erfolgt
die Installation nach ${HOME}/octave (also in Ihr
Homeverzeichnis).
Sind Sie als root angemeldet bzw. führen Octave unter Windows als
Administrator aus, erfolgt die Installation systemweit, so dass das
Paket dann für alle Nutzer verfügbar ist. Das Zielverzeichnis dabei
liegt unterhalb des Baumes datarootdir/octave/packages, das
Verzeichnis datarootdir wurde beim Erstellen von Octave
konfiguriert, es ist unter Linux/Unix häufig "/usr/share" oder
"/usr/local/share". Unter Windows ist es ein Verzeichnis "share"
unterhalb des Verzeichnisses, in das GNU Octave installiert
wurde.
Der Octave-Befehl
pkg install -forge Paket
installiert das angegebene Paket.
Beispiel:
pkg install -forge splines
Octave-Pakete liegen als *.tar.gz-Dateien vor. Nach dem Download starten Sie Octave und geben das Kommando
pkg install dateiname.tar.gz
ein.
Auch hier erfolgt die Paketinstallation nach ${HOME}/octave für
nichtprivilegierte Nutzer bzw. in ein systemweites Verzeichnis,
wenn die Installation durch root bzw. einen Administrator
erfolgt.
Unter Windows müssen Vorwärts-Striche anstelle von Backslashes im Dateinamen geschrieben werden. Wurde beispielsweise ein Paket nach "C:\Users\joe\Downloads\meinpaket.tar.gz" gedownloadet, lautet das Kommando zur Installation:
pkg install C:/Users/joe/Downloads/meinpaket.tar.gz
Es kann entweder ein bestimmtes Paket explizit geladen werden
oder man setzt den Suchpfad so, dass für aufgerufene Funktionen die
entsprechende *.m-Datei automatisch gefunden werden kann.
Für Pakete ist explizites Laden die bevorzugte Methode, die
automatische Suche im Suchpfad sollte hauptsächlich für
selbstgeschriebene *.m-Dateien verwendet werden.
Mit dem Kommando
pkg load meinpaket;
Wird ein Paket - im Beispiel "meinpaket" - geladen.
Diese Anweisung muss in einer interaktiven Sitzung einmal vor der
ersten Verwendung des Paketes ausgeführt werden. Für häufig oder
regelmäßig verwendete Pakete kann die Anweisung auch in die Datei
".octaverc" geschrieben werden.
Um alle selbst installierten Pakete mit in den Suchpfad einzuschließen, sollte in ${HOME}/.octaverc eine Zeile wie
addpath(genpath('/home/joe/octave'));
eingetragen werden, dabei muss "/home/joe" natürlich durch das Homeverzeichnis des jeweiligen Nutzers ersetzt werden.
Die genpath()-Anweisung erzeugt für das angegebene
Verzeichnis einen Pfad-Wert, der rekursiv alle Unterverzeichnisse
mit einschließt.
Mit addpath() wird dieser Pfad-Wert dem Suchpfad
hinzugefügt, dabei wird der neue Pfad-Wert dem bestehenden Suchpfad
vorangestellt.
Um alle vom Administrator installierten Pakete in den Suchpfad mit aufzunehmen, sollte die Datei datarootdir/octave/site/m/startup/octaverc eine Zeile der Form
addpath(genpath('/usr/share/octave/packages'), '-end');
enthalten, dabei muss das Verzeichnis ggf. für das jeweils
zutreffende Verzeichnis datarootdir/octave/packages
korrigiert werden.
Die im Beispiel genutzte Option -end sorgt dafür, dass der
neue Pfad-Wert an den bestehenden Suchpfad angehangen wird, anstatt
ihn voranzustellen.