Qual è il modo più efficiente per scrivere loop 'for' in Matlab?


12

Ho letto che se, ad esempio, ho un doppio forciclo che corre sopra gli indici di una matrice, quindi mettere la colonna che esegue l'indice nel ciclo esterno è più efficiente. Per esempio:

a=zeros(1000);
for j=1:1000
 for i=1:1000
  a(i,j)=1;
 end
end

Qual è il modo più efficiente per codificarlo se ho tre o più forloop?

Per esempio:

a=zeros(100,100,100);
for j=1:100
 for i=1:100
  for k=1:100
   a(i,j,k)=1;
  end
 end
end

4
Fori loop sono molto lenti in MATLAB. Dovresti evitare cicli espliciti in MATLAB quando possibile. Invece, di solito un problema può essere espresso in termini di operazioni matrice / vettoriale. Questo è il modo MATLABic. Ci sono anche molte funzioni integrate per inizializzare le matrici, ecc. Ad esempio, esiste una funzione, ones () , che imposta tutti gli elementi di una matrice su 1 (per estensione, su qualsiasi valore per moltiplicazione (uno scalare moltiplicato per la matrice di tutti)). Funziona anche su array 3D (che a mio avviso copre l'esempio qui).
Peter Mortensen,

3
@PeterMortensen In base a quale fattore (approssimativamente) l'efficienza dei loop in Matlab è inferiore rispetto a C e Python? E perché? Inoltre, l'efficienza degli anelli in Matlab non è migliorata negli ultimi anni?
TensoR,

3
@PeterMortensen "di solito un problema può essere espresso in termini di operazioni a matrice / vettoriale" - per determinati valori di "solito", sì. L'IMO è più preciso nel dire che le persone che lavorano in Matlab e simili hanno una cultura pluridecennale nell'ignorare tutte le cose che non si possono fare con le operazioni matrice / vettoriale, al punto che tutto sembra un chiodo per quel martello . E non dovremmo semplicemente dire "perché i loop in Matlab sono lenti", ma "Matlab è lento" (sembra solo essere collegato a una veloce libreria di primitivi di Los Angeles scritta in C e Fortran).
lasciato circa il

5
L'esecuzione di per loop è controversa: matlabtips.com/matlab-is-no-longer-slow-at-for-loops
ohreally

@leftaroundabout True. Preoccuparsi della velocità in un linguaggio interpretato (o semi-interpretato) è un'indicazione abbastanza chiara di avere un problema XY in cui la soluzione effettiva è "non usare questo linguaggio". L'eccezione ovviamente è se stai usando la generazione del codice in Simulink, ma la domanda è cosa C costruisce il generatore di codice e quanto sia efficiente.
Graham,

Risposte:


18

Risposta breve, vuoi avere l'indice più a sinistra sul ciclo più interno. Nel tuo esempio, gli indici di loop andrebbero k, j, i e gli indici di array sarebbero i, j, k. Ciò ha a che fare con il modo in cui MATLAB memorizza le diverse dimensioni in memoria. Per di più, vedi il n. 13 di questo post reddit .


2
Oppure usa le funzioni integrate () .
Peter Mortensen,

5
L'esempio di @Peter OP è quasi certamente solo un esempio giocattolo di un ciclo for che fa qualcosa e non il caso d'uso reale.
Matt,

@Matt Hai ragione.
TensoR,

11

Una risposta un po 'più lunga che spiega perché è più efficiente far variare più rapidamente l'indice più a sinistra. Ci sono due cose chiave che devi capire.

In primo luogo, MATLAB (e Fortran, ma non C e la maggior parte degli altri linguaggi di programmazione) memorizza gli array in memoria in "ordine maggiore di colonna". ad es. se A è una matrice 2 per 3 per 10, le voci verranno memorizzate nell'ordine

A (1,1,1)

A (2,1,1)

A (1,2,1)

A (2,2,1)

A (1,3,1)

A (2,3,1)

A (1,1,2)

A (2,1,2)

...

A (2,3,10)

Questa scelta di ordine maggiore di colonna è arbitraria, potremmo semplicemente adottare una convenzione di "ordine maggiore di riga", e in effetti è ciò che viene fatto in C e in altri linguaggi di programmazione.

La seconda cosa importante che devi capire è che i moderni processori non accedono alla memoria una posizione alla volta, ma piuttosto caricano e memorizzano "linee di cache" di 64 o addirittura 128 byte contigui (8 o 16 numeri in virgola mobile a precisione doppia) alla volta dalla memoria. Questi blocchi di dati vengono temporaneamente archiviati in una cache di memoria veloce e riscritti secondo necessità. (In pratica l'architettura della cache è ora piuttosto complicata con fino a 3 o 4 livelli di memoria cache, ma l'idea di base può essere spiegata con una cache a un livello del tipo che i computer avevano ai miei tempi più giovani.)

Supponiamo ora che sia un array con 10.000 righe e colonne e che sto eseguendo il ciclo su tutte le voci. A

Se i loop sono nidificati in modo tale che il loop più interno aggiorni il pedice di riga, si accederà alle voci dell'array nell'ordine A (1,1), A (2,1), A (3,1), ... Quando si accede alla prima voce A (1,1), il sistema porterà una cache contenente A (1,1), A (2,1), ..., A (8,1) nella cache dalla memoria principale . Le successive 8 iterazioni del ciclo più interno funzionano su questi dati senza ulteriori trasferimenti di memoria principale.

Se in alternativa, strutturiamo i loop in modo che l'indice di colonna vari nel ciclo più interno, si accederà alle voci di A nell'ordine A (1,1), A (1,2), A (1,3 ), ... In questo caso, il primo accesso porterebbe A (1,1), A (2,1), ..., A (8,1) nella cache dalla memoria principale, ma 7/8 di queste voci non sarebbero state utilizzate. L'accesso ad A (1,2) nella seconda iterazione porterebbe quindi ulteriori 8 voci dalla memoria principale e così via. Quando il codice inizia a funzionare sulla riga 2 della matrice, la voce A (2,1) potrebbe essere eliminata dalla cache per lasciare spazio ad altri dati necessari. Di conseguenza, il codice sta generando 8 volte il traffico necessario.

Alcuni compilatori ottimizzati sono in grado di ristrutturare automaticamente i loop per evitare questo problema.

Molti algoritmi di algebra lineare numerica per la moltiplicazione e la fattorizzazione delle matrici possono essere ottimizzati per funzionare in modo efficiente con lo schema di ordinamento riga maggiore o colonna maggiore in base al linguaggio di programmazione. In questo modo nel modo sbagliato può avere un impatto negativo significativo sulle prestazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.