
Matrici e vettori in MQL5
Le raccolte di dati ordinati, in cui tutti gli elementi hanno lo stesso tipo, vengono generalmente gestite tramite Array, in cui ogni elemento può essere accessibile tramite il suo indice. Gli array sono ampiamente utilizzati nella risoluzione di vari problemi di algebra lineare, nelle attività di modellazione matematica, nell'apprendimento automatico, ecc. In termini generali, la soluzione di tali problemi si basa su operazioni matematiche che utilizzano matrici e vettori, con i quali è possibile scrivere in modo compatto trasformazioni molto complesse sotto forma di semplici formule. La programmazione di tali operazioni richiede una buona conoscenza della matematica insieme alla capacità di scrivere complessi cicli annidati. Il debug e la correzione dei bug in tali programmi possono essere piuttosto impegnativi.
Utilizzando tipi di dati speciali 'matrix' e 'vector', è possibile creare il codice, il quale è molto vicino alla notazione matematica evitando la necessità di creare cicli annidati o di tenere conto della corretta indicizzazione degli array nei calcoli. In questo articolo vedremo come creare, inizializzare e utilizzare gli oggetti matrix e vector in MQL5.
Tipo "vector"
Vector è un array monodimensionale di tipo double. Sui vettori sono definite le seguenti operazioni: addizione e moltiplicazione, nonché la norma per ottenere la lunghezza o il modulo del vettore. In programmazione, i vettori sono solitamente rappresentati da array di elementi omogenei, sui quali non possono essere definite operazioni vettoriali regolari, cioè gli array non possono essere sommati o moltiplicati, e non hanno norma.
In matematica, i vettori possono essere rappresentati come vettori riga, cioè un array costituito da una riga e n colonne, e come vettori stringa, cioè una matrice composta da una colonna e n righe. In MQL5, il tipo 'vettore' non ha sottotipi di riga e colonna, quindi il programmatore deve capire quale tipo di vettore viene utilizzato in una particolare operazione.
Utilizzare i seguenti metodi predefiniti per creare e inizializzare i vettori.
Metodi | Analogo NumPy | Descrizione |
---|---|---|
void vector.Init( ulong dimensione); | Crea un vettore della lunghezza specificata, in cui i valori non sono definiti | |
static vector vector::Ones(ulong dimensione); | ones | Crea un vettore della lunghezza specificata, riempito con uno |
static vector vector::Zeros(ulong dimensione); | zeros | Crea un vettore della lunghezza specificata, riempito con zeri |
static vector vector::Full(ulong dimensione,double valore); | full | Crea un vettore della lunghezza specificata, riempito con il valore specificato |
operator= | Restituisce una copia del vettore | |
void vector.Resize(const vettore v); | Ridimensiona un vettore aggiungendo nuovi valori alla fine |
Esempi di creazione di vettori:
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] */
Il metodo Init() può essere utilizzato non solo per allocare memoria per il vettore, ma anche per inizializzare elementi vettoriali con valori utilizzando una funzione. In questo caso, la dimensione del vettore viene passata a Init come primo parametro e il nome della funzione viene passato come secondo. Se la funzione contiene parametri, questi parametri devono essere specificati subito dopo il nome della funzione, separati da una virgola.
La funzione stessa deve contenere un riferimento al vettore che le viene passato come primo parametro. Il vettore non deve essere passato durante la chiamata Init. Osserviamo l'operazione del metodo usando la funzione Arange come esempio. Questa funzione simula numpy.arange.
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 */
La funzione Arange ha due parametri opzionali, "start" e "stop". Quindi, un'altra possibile chiamata di Init(7,Arange,10) e il relativo risultato sono i seguenti:
//+------------------------------------------------------------------+ //| 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 */
Operazioni con vettori
Le normali operazioni di addizione, sottrazione, moltiplicazione e divisione utilizzando uno scalare possono essere eseguite sui vettori.
//+------------------------------------------------------------------+ //| 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] */ //+------------------------------------------------------------------+
I vettori supportano a livello di elementi operazioni di addizione, sottrazione, moltiplicazione e divisione di due vettori della stessa dimensione.
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] */
Per questo tipo di dati sono definite quattro operazioni di prodotto.
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]] */
Come puoi vedere dall'esempio, il metodo Outer restituisce una matrice nella quale il numero di righe e colonne corrisponde alle dimensioni dei vettori moltiplicati. Dot e MatMul funzionano nello stesso modo.
Norma vettoriale
La norma del vettore e della matrice rappresenta la lunghezza del vettore (magnitudine) e il valore assoluto. Tre sono i possibili modi per calcolare la norma di un vettore e sono elencati in ENUM_VECTOR_NORM.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 */
Usando la norma, puoi misurare la distanza tra due vettori:
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 */
Tipo "matrix"
Il vettore è uno speciale contenitore di una matrice, che in realtà è un array bidimensionale di tipo double. Pertanto, una matrice può essere considerata come un array di vettori della stessa dimensione. Il numero di righe della matrice corrisponde al numero di vettori, mentre il numero di colonne è uguale alla lunghezza del vettore.
Le operazioni di addizione e moltiplicazione sono disponibili anche per le matrici. I linguaggi di programmazione convenzionali utilizzano gli array per rappresentare le matrici. Tuttavia, gli array regolari non possono essere aggiunti o moltiplicati tra loro e non hanno la norma. La matematica considera molti tipi diversi di matrici. Ad esempio, matrici identità, simmetriche, antisimmetriche, matrici triangolari superiori e inferiori e altri tipi.
Una matrice può essere creata e inizializzata utilizzando metodi integrati simili ai metodi vettoriali.
Metodo | Metodo analogo in NumPy | Descrizione |
---|---|---|
void static matrix.Eye(const int righe, const int colonne, const int ndiag=0) | Costruisce una matrice con numeri uno su una diagonale specificata e zeri altrove | |
void matrix.Identity() | Riempie una matrice con numeri uno sulla diagonale principale e zeri altrove | |
void static matix.Ones(const int righe, const int colonne) | Costruisce una nuova matrice in base al numero di righe e colonne, riempita con numeri uno | |
void static matix.Zeros(const int righe, const int colonne) | Costruisce una nuova matrice in base al numero di righe e colonne, riempita con zeri | |
void static matrix.Tri(const int righe, const int colonne, const int ndiag=0) | tri | Costruisce una matrice con numeri uno su una diagonale specificata e sotto di essa e zeri altrove |
void matrix.Diag(const vettore v, const int ndiag=0) | diag | Estrae una diagonale o costruisce una matrice diagonale |
void matrix.Full(const int righe, const int colonne, const valore scalare) | Costruisce una nuova matrice in base al numero di righe e colonne, riempita con un valore scalare | |
void matrix.Fill(const valore scalare) | Riempie la matrice con il valore specificato |
Esempi di costruzione e riempimento di matrici:
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]] */
L'esempio seguente mostra come utilizzare le funzioni personalizzate durante il riempimento delle matrici:
//+------------------------------------------------------------------+ //| 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]] */
Una matrice può essere costruita senza inizializzazione del valore in due modi:
//--- create a matrix of a given 'rows x cols' size matrix m(3, 3); // ------ equivalent matrix m; m.Resize(3, 3);
Norma matriciale
I nove modi per calcolare una norma matriciale sono elencati in ENUM_MATRIX_NORM.
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 */
Operazioni con matrici e vettori
Le matrici forniscono metodi speciali per risolvere problemi matematici:
- Trasposizione
- Addizione, sottrazione, moltiplicazione e divisione di matrici per elementi
- Addizione, sottrazione, moltiplicazione e divisione di elementi di matrice per uno scalare
- Prodotto di matrici e vettori con il metodo MatMul (prodotto di matrice)
- Inner()
- Outer()
- Kron()
- Inv() — inversa di una matrice
- Solve() — risolve un sistema di equazioni lineari
- LstSq() — Restituisce la soluzione ai minimi quadrati di equazioni algebriche lineari (per matrici non quadrate o degenerate)
- PInv() — matrice dei minimi quadrati pseudo-inversa
- Operazioni con colonne, righe e diagonali
Decomposizione della matrice:
Metodo | Metodo analogo in NumPy | Descrizione |
---|---|---|
bool matrix.Cholesky(matrice& L) | cholesky | Calcola la decomposizione di Cholesky |
bool matrix.QR(matrice& Q, matrice& R) | qr | Calcola la decomposizione QR |
bool matrix.SVD(matrice& U, matrice& V, vettore& valori_singolari) | Calcola la decomposizione SVD | |
bool matrix.Eig(matrice& autovettori, vettore& autovalori) | Calcola gli autovalori e i giusti autovettori di una matrice quadrata | |
bool matrix.EigVals(vettore& autovalori) | Calcola gli autovalori di una matrice generale | |
bool matrix.LU(matrice& L, matrice& U) |
| Implementa una decomposizione LU di una matrice: il prodotto di una matrice triangolare inferiore e di una matrice triangolare superiore |
bool matrice.LUP(matrice& L, matrice& U, matrice& P) |
| Implementa una decomposizione LUP con pivoting parziale, che è una fattorizzazione LU con una permutazione di righe: PA = LU |
Prodotto di matrici e vettori
MatMul() è definito per calcolare il prodotto matriciale di matrici e vettori. Questo metodo è spesso utilizzato per risolvere vari problemi matematici. Le seguenti due opzioni sono possibili quando si moltiplicano una matrice e un vettore:
- Il vettore orizzontale a sinistra viene moltiplicato per la matrice a destra; la lunghezza del vettore è uguale al numero di colonne della matrice;
- La matrice a sinistra viene moltiplicata per il vettore verticale a destra; il numero delle colonne della matrice è uguale alla lunghezza del vettore.
Se la lunghezza del vettore non è uguale al numero di colonne nella matrice, verrà generato un errore di esecuzione critico.
Per moltiplicare due matrici, la loro forma dovrebbe essere la seguente: A[M,N] * B[N,K] = C[M,K], cioè il numero di colonne della matrice di sinistra deve essere uguale al numero di righe della matrice di destra. Se le dimensioni non sono coerenti, il risultato è una matrice vuota. Esaminiamo tutte le varianti di prodotto di matrice con esempi.
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]] */
Per una migliore comprensione di come i tipi matrix e vector sono disposti , questi esempi mostrano come è possibile utilizzare le matrici al posto dei vettori. Significa che i vettori possono essere rappresentati come matrici.
Numeri complessi di tipo 'complex'
struct complex { double real; // real part double imag; // imaginary part };Il tipo 'complex' può essere passato per valore, come un parametro per le funzioni MQL5 (a differenza delle strutture ordinarie, che sono passate solo per riferimento). Per le funzioni importate da DLL, il tipo "complex" deve essere passato solo per riferimento.
Il suffisso 'i' è usato per descrivere costanti complex:
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 numberPer i numeri complex sono disponibili solo operazioni semplici: =, +, -, *, /, +=, -=, *=, /=, ==, !=.
Presto verrà aggiunto il supporto per ulteriori funzioni matematiche, consentendo il calcolo del valore assoluto, seno, coseno e altri.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/9805





- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso