Matrizen und Vektoren in MQL5
Kollektionen von geordneten Daten, bei denen alle Elemente den gleichen Typ haben, werden normalerweise über Arrays verwaltet, bei denen auf jedes Element über seinen Index zugegriffen werden kann. Arrays werden häufig bei der Lösung verschiedener Probleme der linearen Algebra, bei mathematischen Modellierungsaufgaben, beim maschinellen Lernen usw. verwendet. Im Allgemeinen basiert die Lösung solcher Probleme auf mathematischen Operationen mit Matrizen und Vektoren, mit denen sehr komplexe Transformationen kompakt in Form einfacher Formeln geschrieben werden können. Die Programmierung solcher Operationen erfordert gute mathematische Kenntnisse und die Fähigkeit, komplexe verschachtelte Schleifen zu schreiben. Die Fehlersuche und -behebung in solchen Programmen kann recht anspruchsvoll sein.
Durch die Verwendung der speziellen Datentypen 'matrix' und 'vector' ist es möglich, einen Code zu erstellen, der der mathematischen Notation sehr nahe kommt, ohne dass man verschachtelte Schleifen erstellen oder auf die korrekte Indizierung von Arrays in Berechnungen achten muss. In diesem Artikel werden wir sehen, wie man Matrix- und Vektor-Objekte in MQL5 erstellt, initialisiert und verwendet.
Typ 'vector'
vector ist ein eindimensionales Array des Typs double. Für Vektoren sind folgende Operationen definiert: Addition und Multiplikation, sowie die Norm zur Ermittlung der Vektorlänge oder des Moduls. In der Programmierung werden Vektoren in der Regel durch Arrays homogener Elemente dargestellt, für die keine regulären Vektoroperationen definiert werden können, d. h. Arrays können nicht addiert oder multipliziert werden, und sie haben keine Norm.
In der Mathematik können Vektoren als Zeilenvektoren, d. h. als ein Array mit einer Zeile und n Spalten, und als Stringvektoren, d. h. als eine Matrix mit einer Spalte und n Zeilen, dargestellt werden. In MQL5 hat der Typ 'vector' keine Zeilen- und Spalten-Subtypen, so dass der Programmierer wissen muss, welcher Vektortyp in einer bestimmten Operation verwendet wird.
Verwenden Sie die folgenden eingebauten Methoden, um Vektoren zu erzeugen und zu initialisieren.
Methoden | NumPy Analogon | Beschreibung |
---|---|---|
void vector.Init( ulong size); | Erzeugt einen Vektor der angegebenen Länge mit undefinierten Werten | |
static vector vector::Ones(ulong size); | ones | Erzeugt einen Vektor der angegebenen Länge, der mit Einsen gefüllt ist. |
static vector vector::Zeros(ulong size); | zeros | Erzeugt einen Vektor der angegebenen Länge, der mit Nullen gefüllt ist. |
static vector vector::Full(ulong size,double value); | full | Erzeugt einen Vektor der angegebenen Länge, gefüllt mit dem angegebenen Wert. |
Operator = | Gibt eine Kopie des Vektors zurück | |
void vector.Resize(const vector v); | Ändert die Größe eines Vektors, indem neue Werte am Ende hinzugefügt werden. |
Beispiele für die Erstellung von Vektoren:
void OnStart() { //--- vector initialization examples vector v; v.Init(7); Print("v = ", v); vector v1=vector::Ones(5); Print("v1 = ", v1); vector v2=vector::Zeros(3); Print("v2 = ", v2); vector v3=vector::Full(6, 2.5); Print("v3 = ", v3); vector v4{1, 2, 3}; Print("v4 = ", v4); v4.Resize(5); Print("after Resize(5) v4 = ", v4); vector v5=v4; Print("v5 = ", v5); v4.Fill(7); Print("v4 = ", v4, " v5 =",v5); } /* Execution result v = [4,5,6,8,10,12,12] v1 = [1,1,1,1,1] v2 = [0,0,0] v3 = [2.5,2.5,2.5,2.5,2.5,2.5] v4 = [1,2,3] after Resize(5) v4 = [1,2,3,7,7] v5 = [1,2,3,7,7] v4 = [7,7,7,7,7] v5 =[1,2,3,7,7] */
Die Methode Init() kann nicht nur verwendet werden, um Speicher für den Vektor zuzuweisen, sondern auch, um Vektorelemente mithilfe einer Funktion mit Werten zu initialisieren. In diesem Fall wird die Vektorgröße als erster Parameter und der Funktionsname als zweiter Parameter an Init übergeben. Wenn die Funktion Parameter enthält, sollten diese unmittelbar nach dem Funktionsnamen angegeben werden, getrennt durch ein Komma.
Die Funktion selbst muss einen Verweis auf den Vektor enthalten, der als erster Parameter an die Funktion übergeben wird. Der Vektor sollte beim Aufruf von Init nicht übergeben werden. Schauen wir uns die Arbeitsweise der Methode am Beispiel der Funktion Arange an. Diese Funktion ahmt numpy.arange nach.
void OnStart() { //--- vector v; v.Init(7,Arange,10,0,0.5); // 3 parameters are passed with Arange call Print("v = ", v); Print("v.size = ",v.Size()); } //+------------------------------------------------------------------+ //| Values are generated within the half-open interval [start, stop)| //+------------------------------------------------------------------+ void Arange(vector& v, double stop, double start = 0, double step = 1) // the function has 4 parameters { if(start >= stop) { PrintFormat("%s wrong parameters! start=%G stop=%G", __FILE__,start, stop); return; } //--- int size = (int)((stop - start) / step); v.Resize(size); double value = start; for(ulong i = 0; i < v.Size(); i++) { v[i] = value; value += step; } } /* Execution result v = [0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5] v.size = 20 */
Die Funktion Arange hat zwei optionale Parameter, "start" und "stop". Daher wären ein weiterer, möglicher Aufruf von Init(7,Arange,10) und das entsprechende Ergebnis wie folgt:
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- vector v; v.Init(7,Arange,10); Print("v = ", v); Print("v.size = ",v.Size()); } ... /* v = [0,1,2,3,4,5,6,7,8,9] v.size = 10 */
Operationen mit Vektoren
Die üblichen Operationen wie Addition, Subtraktion, Multiplikation und Division mit einem Skalar können mit Vektoren durchgeführt werden.
//+------------------------------------------------------------------+ //| vector2_article.mq5 | //| Copyright 2021, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- vector v= {1, 2, 3, 4, 5}; Print("Examples without saving vector changes"); Print("v = ", v); Print("v+5 = ", v+5); Print("v-Pi= ", v-M_PI); Print("v*2.0= ", v*2); Print("v/3.0= ", v/3.0); Print("Save all vector changes"); Print("v = ", v); Print("v+5 = ", v=v+5); Print("v-Pi= ", v=v-M_PI); Print("v*2.0= ", v= v*2); Print("v/3.0= ", v= v/3.0); } /* Execution result Examples without saving vector changes v = [1,2,3,4,5] v+5 = [6,7,8,9,10] v-Pi= [-2.141592653589793,-1.141592653589793,-0.1415926535897931,0.8584073464102069,1.858407346410207] v*2.0= [2,4,6,8,10] v/3.0= [0.3333333333333333,0.6666666666666666,1,1.333333333333333,1.666666666666667] Save all vector changes v = [1,2,3,4,5] v+5 = [6,7,8,9,10] v-Pi= [2.858407346410207,3.858407346410207,4.858407346410207,5.858407346410207,6.858407346410207] v*2.0= [5.716814692820414,7.716814692820414,9.716814692820414,11.71681469282041,13.71681469282041] v/3.0= [1.905604897606805,2.572271564273471,3.238938230940138,3.905604897606805,4.572271564273471] */ //+------------------------------------------------------------------+
Vektoren unterstützen elementweise Operationen wie Addition, Subtraktion, Multiplikation und Division von zwei gleich großen Vektoren.
void OnStart() { //--- vector a = {1, 2, 3}; vector b = {2, 4, 6}; Print("a + b = ", a + b); Print("a - b = ", a - b); Print("a * b = ", a * b); Print("b / a = ", b / a); } /* Execution result a + b = [3,6,9] a - b = [-1,-2,-3] a * b = [2,8,18] b / a = [2,2,2] */
Für diesen Datentyp sind vier Produktoperationen definiert.
void OnStart() { //--- vector a={1, 2, 3}; vector b={4, 5, 6}; Print("a = ", a); Print("b = ", b); Print("1) a.Dot(b) = ", a.Dot(b)); Print("2) a.MatMul(b) = ", a.MatMul(b)); Print("3) a.Kron(b) = ", a.Kron(b)); Print("4) a.Outer(b) = \n", a.Outer(b)); } /* Execution result a = [1,2,3] b = [4,5,6] 1) a.Dot(b) = 32.0 2) a.MatMul(b) = 32.0 3) a.Kron(b) = [[4,5,6,8,10,12,12,15,18]] 4) a.Outer(b) = [[4,5,6] [8,10,12] [12,15,18]] */
Wie Sie aus dem Beispiel ersehen können, gibt die Methode Outer eine Matrix zurück, bei der die Anzahl der Zeilen und Spalten den Größen der multiplizierten Vektoren entspricht. Die Methoden Dot und MatMul arbeiten auf die gleiche Weise.
Vektornorm
Die Norm von Vektoren und Matrizen gibt die Länge (Größe) und den absoluten Wert des Vektors an. Drei mögliche Wege zur Berechnung der Norm eines Vektors sind in ENUM_VECTOR_NORM aufgeführt.void OnStart() { //--- struct str_vector_norm { ENUM_VECTOR_NORM norm; int value; }; str_vector_norm vector_norm[]= { {VECTOR_NORM_INF, 0}, {VECTOR_NORM_MINUS_INF, 0}, {VECTOR_NORM_P, 0}, {VECTOR_NORM_P, 1}, {VECTOR_NORM_P, 2}, {VECTOR_NORM_P, 3}, {VECTOR_NORM_P, 4}, {VECTOR_NORM_P, 5}, {VECTOR_NORM_P, 6}, {VECTOR_NORM_P, 7}, {VECTOR_NORM_P, -1}, {VECTOR_NORM_P, -2}, {VECTOR_NORM_P, -3}, {VECTOR_NORM_P, -4}, {VECTOR_NORM_P, -5}, {VECTOR_NORM_P, -6}, {VECTOR_NORM_P, -7} }; vector v{1, 2, 3, 4, 5, 6, 7}; double norm; Print("v = ", v); //--- for(int i=0; i<ArraySize(vector_norm); i++) { switch(vector_norm[i].norm) { case VECTOR_NORM_INF : norm=v.Norm(VECTOR_NORM_INF); Print("v.Norm(VECTOR_NORM_INF) = ", norm); break; case VECTOR_NORM_MINUS_INF : norm=v.Norm(VECTOR_NORM_MINUS_INF); Print("v.Norm(VECTOR_NORM_MINUS_INF) = ", norm); break; case VECTOR_NORM_P : norm=v.Norm(VECTOR_NORM_P, vector_norm[i].value); PrintFormat("v.Norm(VECTOR_NORM_P,%d) = %G", vector_norm[i].value, norm); } } } /* v = [1,2,3,4,5,6,7] v.Norm(VECTOR_NORM_INF) = 7.0 v.Norm(VECTOR_NORM_MINUS_INF) = 1.0 v.Norm(VECTOR_NORM_P,0) = 7 v.Norm(VECTOR_NORM_P,1) = 28 v.Norm(VECTOR_NORM_P,2) = 11.8322 v.Norm(VECTOR_NORM_P,3) = 9.22087 v.Norm(VECTOR_NORM_P,4) = 8.2693 v.Norm(VECTOR_NORM_P,5) = 7.80735 v.Norm(VECTOR_NORM_P,6) = 7.5473 v.Norm(VECTOR_NORM_P,7) = 7.38704 v.Norm(VECTOR_NORM_P,-1) = 0.385675 v.Norm(VECTOR_NORM_P,-2) = 0.813305 v.Norm(VECTOR_NORM_P,-3) = 0.942818 v.Norm(VECTOR_NORM_P,-4) = 0.980594 v.Norm(VECTOR_NORM_P,-5) = 0.992789 v.Norm(VECTOR_NORM_P,-6) = 0.99714 v.Norm(VECTOR_NORM_P,-7) = 0.998813 */
Mit Hilfe der Norm kann man den Abstand zwischen zwei Vektoren messen:
void OnStart() { //--- vector a{1,2,3}; vector b{2,3,4}; double distance=(b-a).Norm(VECTOR_NORM_P,2); Print("a = ",a); Print("b = ",b); Print("|a-b| = ",distance); } /* Execution result a = [1,2,3] b = [2,3,4] |a-b| = 1.7320508075688772 */
Typ 'Matrix'
Der Vektor ist ein Spezialfall einer Matrix, die eigentlich ein zweidimensionales Feld vom Typ double ist. Eine Matrix kann also als ein Array von gleich großen Vektoren betrachtet werden. Die Anzahl der Zeilen der Matrix entspricht der Anzahl der Vektoren, während die Anzahl der Spalten der Länge der Vektoren entspricht.
Die Operationen der Addition und Multiplikation sind auch für Matrizen verfügbar. Herkömmliche Programmiersprachen verwenden Arrays zur Darstellung von Matrizen. Reguläre Arrays können jedoch nicht miteinander addiert oder multipliziert werden, und sie haben keine Norm. Die Mathematik kennt viele verschiedene Matrixtypen. Zum Beispiel die Identitätsmatrix, symmetrische, schiefsymmetrische, obere und untere Dreiecksmatrizen und andere Typen.
Eine Matrix kann mit integrierten Methoden erstellt und initialisiert werden, ähnlich wie bei Vektormethoden.
Methode | Analoge Methode in NumPy | Beschreibung |
---|---|---|
void static matrix.Eye(const int rows, const int cols, const int ndiag=0) | Konstruiert eine Matrix mit Einsen auf der angegebenen Diagonale und Nullen an allen anderen Stellen. | |
void matrix.Identity() | Füllt eine Matrix mit Einsen auf der Hauptdiagonale und Nullen an allen anderen Stellen. | |
void static matrix.Ones(const int rows, const int cols) | Konstruiert eine neue Matrix mit der Anzahl der Zeilen und Spalten, gefüllt mit Einsen. | |
void static matrix.Zeros(const int rows, const int cols) | Konstruiert eine neue Matrix mit der Anzahl der Zeilen und Spalten, die mit Nullen gefüllt ist. | |
void static matrix.Tri(const int rows, const int cols, const int ndiag=0) | tri | Erzeugt eine Matrix mit Einsen auf der angegebenen Diagonale und darunter und Nullen an allen anderen Stellen. |
void matrix.Diag(const vector v, const int ndiag=0) | diag | Extrahiert eine Diagonale oder konstruiert eine Diagonalmatrix. |
void matrix.Full(const int rows, const int cols, const scalar value) | Konstruiert eine neue Matrix mit der Anzahl der Zeilen und Spalten, gefüllt mit einem Skalarwert. | |
void matrix.Fill(const scalar value) | Füllt die Matrix mit dem angegebenen Wert. |
Beispiele für den Aufbau und das Füllen einer Matrix:
void OnStart() { //--- matrix m{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; Print("m = \n", m); matrix ones=matrix::Ones(4, 4); Print("ones = \n", ones); matrix zeros=matrix::Zeros(4, 4); Print("zeros = \n", zeros); matrix eye=matrix::Eye(4, 4); Print("eye = \n", eye); matrix identity(4, 5); Print("matrix_identity\n", identity); identity.Identity(); Print("matrix_identity\n", identity); matrix tri=matrix::Tri(3, 4); Print("tri = \n", tri); Print("tri.Transpose() = \n", tri.Transpose()); // transpose the matrix matrix diag(5, 5); Print("diag = \n", diag); vector d{1, 2, 3, 4, 5}; diag.Diag(d); Print("diag = \n", diag); // insert values from the vector into the matrix diagonal matrix fill(5, 5); fill.Fill(10); Print("fill = \n", fill); matrix full =matrix::Full(5, 5, 100); Print("full = \n", full); matrix init(5, 7); Print("init = \n", init); m.Init(4, 6); Print("init = \n", init); matrix resize=matrix::Full(2, 2, 5); resize.Resize(5,5); Print("resize = \n", resize); } /* Execution result m = [[1,2,3] [4,5,6] [7,8,9]] ones = [[1,1,1,1] [1,1,1,1] [1,1,1,1] [1,1,1,1]] zeros = [[0,0,0,0] [0,0,0,0] [0,0,0,0] [0,0,0,0]] eye = [[1,0,0,0] [0,1,0,0] [0,0,1,0] [0,0,0,1]] matrix_identity [[1,0,0,0,0] [0,1,0,0,0] [0,0,1,0,0] [0,0,0,1,0]] matrix_identity [[1,0,0,0,0] [0,1,0,0,0] [0,0,1,0,0] [0,0,0,1,0]] tri = [[1,0,0,0] [1,1,0,0] [1,1,1,0]] tri.Transpose() = [[1,1,1] [0,1,1] [0,0,1] [0,0,0]] diag = [[0,0,0,0,0] [0,0,0,0,0] [0,0,0,0,0] [0,0,0,0,0] [0,0,0,0,0]] diag = [[1,0,0,0,0] [0,2,0,0,0] [0,0,3,0,0] [0,0,0,4,0] [0,0,0,0,5]] fill = [[10,10,10,10,10] [10,10,10,10,10] [10,10,10,10,10] [10,10,10,10,10] [10,10,10,10,10]] full = [[100,100,100,100,100] [100,100,100,100,100] [100,100,100,100,100] [100,100,100,100,100] [100,100,100,100,100]] resize = [[5,5,0,0,0] [5,5,0,0,0] [0,0,0,0,0] [0,0,0,0,0] [0,0,0,0,0]] */
Das folgende Beispiel zeigt, wie Sie beim Füllen von Matrizen nutzerdefinierte Funktionen verwenden können:
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- matrix random(4, 5, MatrixRandom); Print("random = \n",random); matrix init(3, 6, MatrixSetValues); Print("init = \n", init); } //+------------------------------------------------------------------+ //| Fills the matrix with random values | //+------------------------------------------------------------------+ void MatrixRandom(matrix& m) { for(ulong r=0; r<m.Rows(); r++) { for(ulong c=0; c<m.Cols(); c++) { m[r][c]=double(MathRand())/32767.; } } } //+------------------------------------------------------------------+ //| Fills the matrix with powers of a number | //+------------------------------------------------------------------+ void MatrixSetValues(matrix& m, double initial=1) { double value=initial; for(ulong r=0; r<m.Rows(); r++) { for(ulong c=0; c<m.Cols(); c++) { m[r][c]=value; value*=2; } } } /* Execution result random = [[0.4200262459181494,0.5014496292001098,0.7520371105075229,0.652058473464156,0.08783227027191992] [0.5991088595233008,0.4311960203863643,0.8718832972197638,0.1350138859218116,0.901882992034669] [0.4964445936460463,0.8354747154148991,0.5258339182714317,0.6055482650227363,0.5952940458388012] [0.3959166234321116,0.8146916104617451,0.2053590502639851,0.2657551805169835,0.3672292245246742]] init = [[1,2,4,8,16,32] [64,128,256,512,1024,2048] [4096,8192,16384,32768,65536,131072]] */
Eine Matrix kann ohne Wertinitialisierung auf zwei Arten konstruiert werden:
//--- create a matrix of a given 'rows x cols' size matrix m(3, 3); // ------ equivalent matrix m; m.Resize(3, 3);
Matrixnorm
Die neun Möglichkeiten zur Berechnung der Norm einer Matrix sind in ENUM_MATRIX_NORM aufgeführt.
void OnStart() { //--- ENUM_MATRIX_NORM matrix_norm[]= {MATRIX_NORM_FROBENIUS, MATRIX_NORM_SPECTRAL, MATRIX_NORM_NUCLEAR, MATRIX_NORM_INF, MATRIX_NORM_MINUS_INF, MATRIX_NORM_P1, MATRIX_NORM_MINUS_P1, MATRIX_NORM_P2, MATRIX_NORM_MINUS_P2 }; matrix m{{1,2,3},{4,5,6},{7,8,9}}; Print("matrix m:\n",m); //--- compute the norm using all ways double norm; for(int i=0; i<ArraySize(matrix_norm); i++) { norm=m.Norm(matrix_norm[i]); PrintFormat("%d. Norm(%s) = %.6f",i+1, EnumToString(matrix_norm[i]),norm); } //--- return; } /* Execution result matrix m: [[1,2,3] [4,5,6] [7,8,9]] 1. Norm(MATRIX_NORM_FROBENIUS) = 16.881943 2. Norm(MATRIX_NORM_SPECTRAL) = 14.790157 3. Norm(MATRIX_NORM_NUCLEAR) = 17.916473 4. Norm(MATRIX_NORM_INF) = 24.000000 5. Norm(MATRIX_NORM_MINUS_INF) = 6.000000 6. Norm(MATRIX_NORM_P1) = 18.000000 7. Norm(MATRIX_NORM_MINUS_P1) = 12.000000 8. Norm(MATRIX_NORM_P2) = 16.848103 9. Norm(MATRIX_NORM_MINUS_P2) = 0.000000 */
Operationen mit Matrizen und Vektoren
Matrizen bieten spezielle Methoden zum Lösen mathematischer Probleme:
- Transposition
- Elementweise Matrixaddition, -subtraktion, -multiplikation und -division
- Addition, Subtraktion, Multiplikation und Division von Matrixelementen durch einen Skalar
- Produkt von Matrizen und Vektoren mit der MatMul-Methode (Matrixprodukt)
- Inner()
- Outer()
- Kron()
- Inv() —Inverse einer Matrix
- Solve() — löst ein System linearer Gleichungen
- LstSq() — gibt die Lösung der kleinsten Quadrate von linearen algebraischen Gleichungen zurück (für nicht quadratische oder entartete Matrizen)
- PInv() — Pseudo-Inverse Kleinste-Quadrate-Matrix
- Operationen mit Spalten, Zeilen und Diagonalen
Matrix-Zerlegung:
Methode | Analoge Methode in NumPy | Beschreibung |
---|---|---|
bool matrix.Cholesky(matrix& L) | cholesky | Berechnet die Cholesky-Zerlegung |
bool matrix.QR(matrix& Q, matrix& R) | qr | Berechnet die QR-Zerlegung |
bool matrix.SVD(matrix& U, matrix& V, vector& singular_values) | Berechnet die SVD-Zerlegung | |
bool matrix.Eig(matrix& eigen_vectors, vector& eigen_values) | Berechnet die Eigenwerte und rechten Eigenvektoren einer quadratischen Matrix | |
bool matrix.EigVals(vector& eigen_values) | Berechnet die Eigenwerte einer allgemeinen Matrix | |
bool matrix.LU(matrix& L, matrix& U) |
| Führt eine LU-Zerlegung einer Matrix durch: das Produkt aus einer unteren Dreiecksmatrix und einer oberen Dreiecksmatrix |
bool matrix.LUP(matrix& L, matrix& U, matrix& P) |
| Implementiert eine LUP-Zerlegung mit partieller Pivotisierung, d.h. eine LU-Faktorisierung mit einer Permutation der Zeilen: PA = LU |
Produkt von Matrizen und Vektoren
MatMul() ist definiert, um das Matrixprodukt von Matrizen und Vektoren zu berechnen. Diese Methode wird häufig bei der Lösung verschiedener mathematischer Probleme verwendet. Bei der Multiplikation einer Matrix und eines Vektors sind die folgenden zwei Optionen möglich:
- Der horizontale Vektor auf der linken Seite wird mit der Matrix auf der rechten Seite multipliziert; die Länge des Vektors ist gleich der Anzahl der Spalten der Matrix;
- Die Matrix auf der linken Seite wird mit dem vertikalen Vektor auf der rechten Seite multipliziert; die Anzahl der Spalten der Matrix ist gleich der Länge des Vektors.
Wenn die Vektorlänge nicht gleich der Anzahl der Spalten der Matrix ist, wird ein kritischer Ausführungsfehler erzeugt.
Um zwei Matrizen zu multiplizieren, sollte ihre Form wie folgt sein: A[M,N] * B[N,K] = C[M,K], d.h. die Anzahl der Spalten in der Matrix auf der linken Seite muss gleich der Anzahl der Zeilen in der Matrix auf der rechten Seite sein. Wenn die Dimensionen nicht konsistent sind, ist das Ergebnis eine leere Matrix. Schauen wir uns alle Varianten des Matrixprodukts anhand von Beispielen an.
void OnStart() { //--- initialize matrices matrix m35, m52; m35.Init(3,5,Arange); m52.Init(5,2,Arange); //--- Print("1. Product of horizontal vector v[3] and matrix m[3,5]"); vector v3 = {1,2,3}; Print("On the left v3 = ",v3); Print("On the right m35 = \n",m35); Print("v3.MatMul(m35) = horizontal vector v[5] \n",v3.MatMul(m35)); //--- show that this is really a horizontal vector Print("\n2. Product of matrix m[1,3] and matrix m[3,5]"); matrix m13; m13.Init(1,3,Arange,1); Print("On the left m13 = \n",m13); Print("On the right m35 = \n",m35); Print("m13.MatMul(m35) = matrix m[1,5] \n",m13.MatMul(m35)); Print("\n3. Product of matrix m[3,5] and vertical vector v[5]"); vector v5 = {1,2,3,4,5}; Print("On the left m35 = \n",m35); Print("On the right v5 = ",v5); Print("m35.MatMul(v5) = vertical vector v[3] \n",m35.MatMul(v5)); //--- show that this is really a vertical vector Print("\n4. Product of matrix m[3,5] and matrix m[5,1]"); matrix m51; m51.Init(5,1,Arange,1); Print("On the left m35 = \n",m35); Print("On the right m51 = \n",m51); Print("m35.MatMul(m51) = matrix v[3] \n",m35.MatMul(m51)); Print("\n5. Product of matrix m[3,5] and matrix m[5,2]"); Print("On the left m35 = \n",m35); Print("On the right m52 = \n",m52); Print("m35.MatMul(m52) = matrix m[3,2] \n",m35.MatMul(m52)); Print("\n6. Product of horizontal vector v[5] and matrix m[5,2]"); Print("On the left v5 = \n",v5); Print("On the right m52 = \n",m52); Print("v5.MatMul(m52) = horizontal vector v[2] \n",v5.MatMul(m52)); Print("\n7. Outer() product of horizontal vector v[5] and vertical vector v[3]"); Print("On the left v5 = \n",v5); Print("On the right v3 = \n",v3); Print("v5.Outer(v3) = matrix m[5,3] \n",v5.Outer(v3)); //--- show that the product of matrices generates the same result Print("\n8. Outer() product of the matrix m[1,5] and matrix m[3,1]"); matrix m15,m31; m15.Init(1,5,Arange,1); m31.Init(3,1,Arange,1); Print("On the left m[1,5] = \n",m15); Print("On the right m31 = \n",m31); Print("m15.Outer(m31) = matrix m[5,3] \n",m15.Outer(m31)); } //+------------------------------------------------------------------+ //| Fill the matrix with increasing values | //+------------------------------------------------------------------+ void Arange(matrix & m, double start = 0, double step = 1) // the function has three parameters { //--- ulong cols = m.Cols(); ulong rows = m.Rows(); double value = start; for(ulong r = 0; r < rows; r++) { for(ulong c = 0; c < cols; c++) { m[r][c] = value; value += step; } } //--- } /* Execution result 1. Product of horizontal vector v[3] and matrix m[3,5] On the left v3 = [1,2,3] On the right m35 = [[0,1,2,3,4] [5,6,7,8,9] [10,11,12,13,14]] v3.MatMul(m35) = horizontal vector v[5] [40,46,52,58,64] 2. Product of matrix m[1,3] and matrix m[3,5] On the left m13 = [[1,2,3]] On the right m35 = [[0,1,2,3,4] [5,6,7,8,9] [10,11,12,13,14]] m13.MatMul(m35) = matrix m[1,5] [[40,46,52,58,64]] 3. Product of matrix m[3,5] and vertical vector v[5] On the left m35 = [[0,1,2,3,4] [5,6,7,8,9] [10,11,12,13,14]] On the right v5 = [1,2,3,4,5] m35.MatMul(v5) = vertical vector v[3] [40,115,190] 4. Product of matrix m[3,5] and matrix m[5,1] On the left m35 = [[0,1,2,3,4] [5,6,7,8,9] [10,11,12,13,14]] On the right m51 = [[1] [2] [3] [4] [5]] m35.MatMul(m51) = matrix v[3] [[40] [115] [190]] 5. Product of matrix m[3,5] and matrix m[5,2] On the left m35 = [[0,1,2,3,4] [5,6,7,8,9] [10,11,12,13,14]] On the right m52 = [[0,1] [2,3] [4,5] [6,7] [8,9]] m35.MatMul(m52) = matrix m[3,2] [[60,70] [160,195] [260,320]] 6. The product of horizontal vector v[5] and matrix m[5,2] On the left v5 = [1,2,3,4,5] On the right m52 = [[0,1] [2,3] [4,5] [6,7] [8,9]] v5.MatMul(m52) = horizontal vector v[2] [80,95] 7. Outer() product of horizontal vector v[5] and vertical vector v[3] On the left v5 = [1,2,3,4,5] On the right v3 = [1,2,3] v5.Outer(v3) = matrix m[5,3] [[1,2,3] [2,4,6] [3,6,9] [4,8,12] [5,10,15]] 8. Outer() product of the matrix m[1,5] and matrix m[3,1] On the left m[1,5] = [[1,2,3,4,5]] On the right m31 = [[1] [2] [3]] m15.Outer(m31) = matrix m[5,3] [[1,2,3] [2,4,6] [3,6,9] [4,8,12] [5,10,15]] */
Zum besseren Verständnis, wie Matrix- und Vektortypen angeordnet sind, zeigen diese Beispiele, wie Matrizen anstelle von Vektoren verwendet werden können. Das bedeutet, dass Vektoren als Matrizen dargestellt werden können.
Komplexe Zahlen vom Typ 'komplex'
struct complex { double real; // real part double imag; // imaginary part };Der Typ 'complex' kann der Parameter als Wert für MQL5-Funktionen übergeben werden (im Gegensatz zu gewöhnlichen Strukturen, die nur als Referenz übergeben werden). Bei Funktionen, die aus DLLs importiert werden, muss der 'komplexe' Typ als Referenz übergeben werden.
Das Suffix 'i' wird verwendet, um komplexe Werte zu beschreiben:
complex square(complex c) { return(c*c); } void OnStart() { Print(square(1+2i)); // a constant is passed as a parameter } // will print "(-3,4)" - a string representation of a complex numberFür komplexe Zahlen gibt es nur einfache Operationen: =, +, -, *, /, +=, -=, *=, /=, ==, !=.
Unterstützung für weitere mathematische Funktionen wird demnächst hinzugefügt, sodass die Berechnung von Absolutwert, Sinus, Kosinus und anderen möglich ist.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/9805
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.