Ausdrücke

Dieser Abschnitt erläutert

Datentypen

EULER verwendet die folgenden Datentypen

Die Bedeutung der ersten fünf Datentypen sollte offensichtlich sein. EULER versucht eine Auswertung reell zu halten. Sobald jedoch komplexe Daten in die Berechnung einfließen, wird die gesamte Berechnung komplex. Deshalb ergibt

    >sqrt(-1)

eine sinnlose Antwort, jedoch ist

    >sqrt(complex(-1))

0+1*i. complex(x) ist eine Möglichkeit zu zeigen, dass die Zahl nicht reell, sondern komplex ist.

Strings werden zur Erläuterung der Ausgaben verwendet, zur Übergabe an Funktionen, als Ausdrücke von Funktionen und als Funktionstasten-Text. Es gibt nur zwei Operatoren - zum Zusammensetzen | (senkrechter Strich) und die Vergleichsoperatoren.

Verweise werden intern für Parameter von Funktionen genutzt (siehe Abschnitt Programmieren).

Funktionen sind die selbstdefinierten Funktionen einschließlich der Funktionen aus den Programmdateien.

Alle diese Daten werden auf dem Stack gehalten. Normalerweise muss sich der Anwender um den Stack nicht kümmern, da EULER die normale mathematische Notation für Ausdrücke verwendet. Intern jedoch wird der Stack zur Auswertung eines Ausdruck stark in Anspruch genommen. Programme werden im unteren Bereich des Stacks gehalten. Der Stack wird ebenso bei der Übergabe von Parametern an Build-In- und selbstdefinierten Funktionen sowie für die lokalen Variablen solcher Funktionen verwendet.

Wir möchten noch anmerken, dass die in diesem Abschnitt beschriebenen Daten zu unterscheiden sind von den Build-In-Funktionen, die auf die gleiche Weise wie selbstdefinierte Funktionen verwendet werden können. Es gibt auch noch Kommandos, die weder in Ausdrücken noch in Funktionen verwendet werden können. Build-In-Funktionen und solche Kommandos sind Teil des Codes von EULER.

Eine vollständige Liste der Build-In-Funktionen, Kommandos und selbstdefinierter Funktionen wird durch

    >list

ausgegeben. Eine Liste aller Variablen erhält man durch

    >listvar

Wenn Größeninformationen benötigt werden, kann man

    >memorydump

verwenden. Die Hexadezimalschreibweise von Daten erhält man durch

    >hexdump name

doch das ist nur sinnvoll, wenn Sie wissen, was Sie damit anfangen wollen.

    >store("filename")

speichert den Inhalt des EULER-Stacks in eine Datei.

    >restore("filename")

lädt eine solche Datei. Dies ist eine schnelle Möglichkeit eine Sitzung einschließlich der globalen Variablen und Funktionen zu speichern. Beachten Sie bitte, dass solche Dateien anhängig vom System sind.

Kommandos

Eine EULER Eingabe ist entweder ein "Kommando", ein "Ausdruck" oder eine "Zuweisung". Im Programmiermodus arbeitet EULER ein wenig anders, was durch ein anderes Prompt-Zeichen angedeutet wird.

Ein Beispiel für ein Kommando ist

    >quit

womit EULER beendet wird. Im weiteren werden wir auch einige andere erwähnen. Ein anderes Beispiel ist "load", das Sie schon zum Laden der Demo verwendet haben.

Ausdrücke

Ein Ausdruck meint einen gültigen EULER-Ausdruck. Dieser hat einen Wert als Ergebnis. Wurde der Ausdruck für sich oder gefolgt von einem Komma "," eingegeben, so wird der Wert gedruckt.

    >3+4*5

druckt den Wert 23.00000. Die Ausgabe wird unterdrückt, wenn dem Ausdruck ein Semikolon ";" folgt. Das macht Sinn, weil einige Funktionen Seiteneffekte haben und ihr Ergebnis nicht gebraucht wird oder weil der Anwender die lange Ausgabe einer Zuweisung einfach nicht sehen möchte.

Die Ausgabe erfolgt in einem Format, das durch die Funktion

    >format([n,m])

bestimmt wird, wobei n die Gesamtlänge der Ausgabe ist und m die Anzahl der Ziffern hinter dem Dezimalpunkt. Oft macht

    >format(n,m)

das Gleiche, aber es ist ein wenig langsamer, da es als Funktion in util.e formuliert ist. Die Ausgabe wechselt automatisch in das Exponentialformat, falls nicht genug Platz da ist, um die Zahl in Festkommadarstellung anzuzeigen. Es gibt auch das Kommando

    >goodformat(n,m)

das endende Dezimalziffern weglässt, wenn sie Null sind.

    >longformat()

ist eine Funktion in util.e, die ein längeres Ausgabeformat setzt, während

    >shortformat()

ein kürzeres setzt. Beide benutzen dafür goodformat. Das längste Format ist

    >longestformat()

Sie können explizit angeben, ob Sie das Exponentialformat oder die Festkommadarstellung verwenden wollen.

    >expformat(n,m)
    >fixedformat(n,m)

Unterstützt werden auch Brüche (wie 1/3).

    >fracformat(n,eps)

gibt Zahlen mit n Stellen und einer Genauigkeit eps als Bruch aus. Die Vorgabe von n ist 20 und für eps wird das interne epsilon verwendet, so dass die Parameter entfallen können. Die anderen Formate (wie shortformat) schalten diese Art der Ausgabe wieder ab.

Für Intervalle können Sie

    >iformat(n)

verwenden. Dies gibt soviel Ziffern aus wie nötig, um Unterschiede zwischen der unteren und oberen Grenze des Intervalls zu zeigen. Die Länge der Ausgabe ist dann mindestens n.

    >iformat(0)

wechselt zurück in das gewöhnliche Format.

Zuweisungen

Eine Zuweisung sieht etwa aus wie

    >variablename=value

Ein Variablenname muss mit einem Buchstaben beginnen, weitere Zeichen können Buchstaben oder Ziffern sein. Das Kommando weist den Wert der Variablen zu, die durch die Zuweisung zugleich deklariert wird und druckt den Wert aus. Der Ausdruck wird unterdrückt, falls der Zuweisung ein ";" folgt. Die Zuweisung kann auch mit "," beendet werden, wodurch die rechte Seite der Zuweisung ausgegeben wird.

Mehrfache Zuweisungen

Die Syntax einer mehrfachen Zuweisung lautet

    >{x,y,...}=expression

Dies ist nur in solchen Fällen sinnvoll, wo expression für eine Funktion mit mehreren Rückgabewerten steht. Weist man das Ergebnis eines solchen Ausdrucks einer Einzelvariablen zu, so wird nur der erste Wert verwendet.

Variablen

Die einfachsten Ausdrücke sind Variablen. Ihr Wert ist der Wert der Variablen und ihr Typ ist der Typ der Variablen. Ist eine Variable undefiniert hält die Interpretation des Ausdrucks mit einer Fehlermeldung an.

Grundlegende konstante Ausdrücke sind Zahlen. Sie werden in der gewöhnlichen Form 100, 100.0, 1e2, oder 1.0e+2 eingegeben. Der kleine Buchstabe "e" deutet den Exponenten zur Basis 10 an. Der Anhang "i" verweist auf Vielfache der komplexen Einheit "i". "1+1i" ist tatsächlich die Summe von 1 und 1i, also die geeignete Art komplexe Zahlen einzugeben.

Die Eingabe einer Matrix erfolgt in eckigen Klammern "[" und "]" und zwar Zeile für Zeile. Die Spalten werden durch "," voneinander getrennt und die Zeilen durch ";". Die Zeilen müssen nicht in voller Länge eingegeben werden. Zum Beispiel ist

    >A=[1,2,3;4,5;6]

äquivalent zu

    >A=[1,2,3;4,5,0;6,0,0]

Die Matrix ist reell, solange alle Elemente reell sind, anderenfalls wird sie komplex. Ist ein Element der Matrix ein Intervall, so wird die ganze Matrix zu einer Intervallmatrix.

Ist eine Zeile kürzer als andere, so wird sie mit Nullen aufgefüllt. Eine Matrix-Konstante kann sich über mehrere Eingabezeilen erstrecken.

Man kann auch eine Matrix des Typs (1,n) als Teil einer Zeile in einer anderen Matrix verwenden, wie in

    >x=[1,2,3,4]
    >A=[7,x]

A besteht dann aus den Elementen [7,1,2,3,4].

Strings

String-Konstanten sind in Anführungsstrichen eingeschlossen, wie in

    >string="This is a text"

oder in zwei einfachen Anführungsstrichen, damit auch normale Anführungsstriche in Strings verwendet werden können.

    >string=''This is a "text"''

Ein einzelnes Zeichen mit dem ASCII-Code n kann durch

    >char(n)

erzeugt werden.

Untermatrizen

Eine Untermatrize ist eine Matrix, die sich durch die Elemente einer anderen Matrix definiert. Das einfachste Beispiel ist ein Element einer Matrix

    >A[1,1]

dies ist das Element in der ersten Zeile und der ersten Spalte der Matrix A.

Lassen Sie uns annehmen, A sei eine Matrix und r und c seien Vektoren.Dann ergibt A[r,c] eine Matrix, die aus den Zeilen r[1],r[2],... besteht und von diesen Zeilen sind nur die Spalten c[1],c[2],... belegt. Ein Beispiel

    >A[[1,2],[1,2]]

ist die linke obere Untermatrix des Typs (2,2) von A. Falls eine Zeile oder Spalte nicht existiert, so wird sie einfach vernachlässigt. Ist also A eine Matrix des Typs (4,4), dann ergibt A[[4,7],[4,7]] den Wert von A[4,4]. Etwas speziell ist A[i], was entweder die i-te Zeile von A ist oder, falls A ein Vektor des Typs (1,n) ist, das i-te Element, d.h. A[1,i].

Ein ":" bezeichnet alle Zeilen oder Spalten; d.h. A[:,1] ist die erste Spalte von A und A[:,:] ist A selbst. Ein anderes Beispiel

    >v=[-1,-2,-3,-4,-5]; v[[5,4,3,2,1,1]]

ergibt den Vektor [-5,-4,-3,-2,-1,-1]. Ist A eine Matrix des Typs (4,4), dann ergibt A[[2,1]] eine Matrix des Typs (2,4), die in ihrer ersten Zeile aus der zweiten Zeile von A besteht. Beachten Sie, dass sich auch Matrizen des Typs (0,n) oder (n,0) ergeben könnten.

Untermatrizen können Werte zugewiesen werden. Folglich ist

    >A[1,1]=4.5

eine korrekte Anweisung. Falls die Untermatrix mehr als ein Element hat, dann muss der Wert entweder ebenfalls eine Matrix der selben Größe sein oder ein Skalar. D.h.

    >A[1:2,:]=0

setzt die beiden ersten Zeilen von A auf 0. Wird eine Untermatrix komplex, so wird die gesamte Matrix komplex. Ist v eine Matrix des Typs (1,n) oder (n,1), d.h. ein Vektor, dann ist v[1] das erste Element von v; d.h.

    >v=[1.5,-2,0,4.8]; v[3]

ist Null.

Aus Gründen der Kompatibilität können die eckige Klammern durch runde ersetzt werde. Deshalb ist A(1,1) dasselbe wie A[1,1]. Aber A[1,1] ist schneller. Gibt es außerdem eine Funktion A, dann bedeutet A(1,1) einen Funktionsaufruf von A.

A{i} ist das i-te Element der Matrix A, als wäre die Matrix des Typs (m,n) stattdessen ein Vektor der Länge m*n. Dies ist nützlich, damit Funktionen mit Matrizen arbeiten können. Tatsächlich ist es die schnellste Möglichkeit auf ein Element einer Matrix zuzugreifen. Das funktioniert auch, falls die Matrix zu klein oder eine reelle oder komplexe Skalarvariable ist. Das Ergebnis ist dann das letzte Element von A.

Der : Operator

Der Operator ":" dient zum einfachen Erzeugen von Vektoren. Deshalb erzeugt

    >1:10

den Vektor[1,2,3,4,5,6,7,8,9,10]. Auch eine Schrittweite kann vorgegeben werden wie zum Beispiel mit

    >5:-1.5:1

was [5,3.5,2] ergibt. Aus numerischen Gründen kann man nicht erwarten, mit 1 genau 00.11 zu treffen. Deshalb benutzt das Programm intern epsilon, um das Erzeugen des Vektors zu beenden, so dass 00.11 das verlangte Ergebnis bringt. Das interne epsilon ist so voreingestellt, dass auch

    >0:0.0001:1

korrekt arbeitet.

Matrix-Ausdrücke

Ist A ein Matrix-Ausdruck (ein Ausdruck vom Typ matrix), dann ist A' die Transponierte von A.

Der Binäroperator "|" speichert eine Matrix seitwärts einer anderen; d.h., wenn A eine Matrix des Typs (m,n) ist und B eine Matrix des Typs (m,k), dann ergibt A|B eine Matrix des Typs (m,n+k), die aus A links von B besteht. Analog dazu ergibt A_B eine Matrix mit A oberhalb von B. Diese Operatoren arbeiten auch mit Zahlen, die wie Matrizen des Typs (1,1) behandelt werden. Sie arbeiten sogar, wenn A eine Matrix des Typs (n,0) oder (0,n) ist.

Die mathematischen Operatoren +,-,* und / arbeiten für Zahlen wie gewöhnlich. Für Matrizen arbeiten sie elementweise. Matrizen müssen natürlich nicht unbedingt die gleichen Größen haben. Deshalb gibt es einige spezielle Regeln.

Die gleichen Regeln gelten natürlich auch für alle anderen Operanden und Funktionen mit zwei Parametern. Der Grund für diese Regeln wird später ersichtlich werden. Wichtig ist hier, dass man auf einfache Art Tabellen von Funktionen statt Tabellen von Parametern erzeugen kann. Nur ein Beispiel ist die Tabelle

    >(1:10)*(1:10)'   

die alle Produkte i*j enthält.

Natürlich negiert -A alle Elemente von A. EULER kennt die Regel "*" und "/" vor "+" und "-" zu berechnen. Man kann aus Kompatibilitätsgründen auch ".*" oder "./" schreiben. Falls A nicht vom gleichen Typ ist wie B und weder A noch B eine Matrix des Typs (1,1) oder eine Zahl ist, dann führt A+B zu einem Fehler.

Beachten Sie bitte, dass das Matrizenprodukt mit "A.B" berechnet wird.

Natürlich kann man auch die runden Klammern ( und ) zum gruppieren verwenden, wie in

    >(1+5)*(6+7^(1+3))

Der Exponentialoperator kann als "^" oder "**" geschrieben werden (oder ".^"). Potenzen werden wie alle anderen Operatoren elementweise berechnet. Zum Beispiel

    >[1,2,3]^2

ergibt [1,4,9]. Die Potenz kann auch negativ sein; d.h. die Integer-Potenz aller Zahlen wird definiert. Die Inverse einer Matrix wird mit inv(A) berechnet, nicht mit "A^-1"! Beachten Sie, dass "^" Vorrang hat, so dass

    >-2^2

-4 ergibt.

Vergleiche von Werten können mit > , >= , < , <= , != (ungleich) oder == (gleich) durchgeführt werden. Sie ergeben 1 oder 0, wobei 1 als TRUE (wahr) gilt. Es sei nochmals betont, dass diese Operatoren elementweise arbeiten; d.h.

    >[1,2,3,4]>2

ergibt [0,0,1,1].

    >!A

(not A) ist eine Matrix, die 1 für alle Elemente enthält, die Null waren und eine 0 für alle Elemente, die ungleich Null waren.

    >A && B

ist eine Matrix, die 1 für alle Elemente enthält, die in korresponierenden Elementen von A und B Werte ungleich Null enthalten.

    >A || B

ist 1 falls das korresponierende Element von A oder B ungleich Null ist.

    >any(A)

ergibt 1, wenn jedes Element von A ungleich Null ist.

Man kann die Dimension einer Matrix mit

    >B=redim(A,[n,m])

oder

    >B=redim(A,n,m)

ändern. Dies kopiert den Inhalt von A nach B, wobei weitere Elemente mit 0 belegt werden. Eine Matrix wird Zeile für Zeile gespeichert.

Erzeugen von Matrizen

Es gibt verschiedene Build-In-Funktionen, die Matrizen erzeugen. Die elementarste sind zeros([m,n]) und ones([m,n]), die auch zeros(m,n) und ones(m,n) geschrieben werden können. Sie produzieren eine Matrix des Typs (m,n) mit m Zeilen und n Spalten, die mit Null oder Eins gefüllt sind. Beachten Sie, dass man auch Matrizen des Typs (m,0) und (0,n) erzeugen kann. So ist

    >zeros[0,5]_v_v                                                  

eine korrekte Anweisung, wenn v ein Vektor des Typs (1,5) ist.

Matrix-Funktionen

    >size(A)

gibt die Größe der Matrix A als Vektor des Typs (m,n) zurück. Es ist auch möglich, der Funktion size mehrere Argumente mitzugeben. Dann ergibt

    >size(A,B,...)

die Größe der größten Matrix von A, B,... Allerdings müssen Matrizen alle die gleiche Größe haben, sofern nicht ihre Größe (1,1) ist. Die Bedeutung dieses Features wird später noch erläutert werden.

    >cols(A)
    >rows(A)

geben die Anzahl der Spalten bzw. Zeilen der Matrix A zurück.

    >length(A)

liefert das Maximum der Anzahl von Spalten und Zeilen. Etwas allgemeiner ist

    >matrix([m,n],x)

oder matrix(m,n,x), die eine Matrix des Typs (m,n), gefüllt mit x zurückliefern. Dabei kann x reell oder komplex sein.

    >diag([m,n],k,v)

erzeugt eine Matrix des Typs (m,n), die mit dem Vektor v an ihrer k-ten Diagonale gefüllt ist und sonst nur Null enthält. Falls der Vektor v nicht lang genug ist, wird das letzte Element von v auch für den Rest der Diagonale genommen. Die 0-te Diagonale ist die Hauptdiagonale, die erste die Diagonale rechts davon und die -1-te die Diagonale unterhalb der Hauptdiagonalen. Deshalb erzeugt

    >diag([5,5],0,1)

eine Einheitsmatrix des Typs (5,5). Dasselbe kann mit der Funktion

    >id(5)

erreicht werden. Man kann auch diag(m,n,k,v) schreiben.

    >diag(A,k)

ist ein Vektor, der aus der k-ten Diagonale von A besteht.

    >dup(v,m)

dupliziert den Vektor v des Typs (1,n) m mal, so dass eine Matrix des Typs (m,n) entsteht, die in jeder Zeile v enthält. Ist v ein Vektor des Typs (m,1) dann wird v in die n Spalten der Matrix (m,n) dupliziert. dup funktioniert auch dann, wenn v eine Zahl ist. Dann wird ein Spaltenvektor erzeugt.

    >B=band(A,i,j)

setzt alle Elemente A[i,j] einer Matrix des Typs (m,n) auf 0, sofern nicht m <= i-j <= n ist. So erzeugt zum Beispiel

    >band(A,0,2)                                                                 

eine Bandmatrix mit der Hauptdiagonalen und zwei oberen Nebendiagonalen.

    >B=setdiag(A,n,v)

setzt die n-te Diagonale von A auf v. v kann eine Zahl oder ein Vektor sein.

    >bandmult(A,B)                                       

multipliziert die zwei Matrizen A und B (ähnlich wie A.B), es ist jedoch beträchtlich schneller, falls A und B eine Menge Nullen enthalten.

    >symmult(A,B)

multipliziert die symmetrischen Matrizen A und B und spart dabei die Hälfte der Zeit.

Es gibt die vier praktischen Funktionen shiftleft, shiftright, rotleft, rotright, die die Spalten einer Matrix nach links oder rechts verschieben , wobei shift mit Nullen auffüllt, während rot (rotation) die erste Spalte wieder hinten anfügt und umgekehrt. Zum Beispiel erzeugt

    >shiftleft(1:4)

den Vektor (2,3,4,0) und

    >rotleft(1:4)

den Vektor (2,3,4,1).

Weiterhin gibt es

    >flipx(A)

das die Spalten der Matrix vertauscht, so dass die letzte zur ersten wird und die erste zur letzten.

    >flipy(A)

macht analog das gleiche für Zeilen.