Dal momento che non vi piacciono i loop, che ne dici di funzioni ricorsive?
iif = @(varargin) varargin{2 * find([varargin{1:2:end}], 1, 'first')}();
[email protected](v,gcdr) iif(length(v)==1,v, ...
v(1)==1,1, ...
length(v)==2,@()gcd(v(1),v(2)), ...
true,@()gcdr([gcd(v(1),v(2)),v(3:end)],gcdr));
[email protected](v)gcdrec(v(:)',gcdrec);
A=[0,0,0; 2,4,2;-2,0,8];
divisor=mygcd(A);
A=A/divisor;
La prima funzione iif
definiranno un costrutto condizionale linea. Ciò consente di definire una funzione ricorsiva, gcdrec
, per trovare il massimo comun divisore dell'array. Questo iif
funziona in questo modo: verifica se il primo argomento è true
, se lo è, quindi restituisce il secondo argomento. In caso contrario, verifica il terzo argomento e, se ètrue
, restituisce il quarto e così via. È necessario proteggere le funzioni ricorsive e talvolta altre quantità che appaiono al suo interno con @()
, altrimenti è possibile ottenere errori.
Utilizzando iif
la funzione ricorsiva gcdrec
funziona così:
- se il vettore di ingresso è uno scalare, lo ritorna in
- altro se il primo componente del vettore è 1, non c'è alcuna possibilità di recuperare , quindi restituisce 1 (permette un rapido ritorno per grandi matrici)
- altrimenti se il vettore di ingresso è di lunghezza 2, restituisce il massimo comun divisore tramite
gcd
- altrimenti si definisce con un vettore accorciato , in cui i primi due elementi sono sostituiti con il loro massimo comun divisore.
La funzione mygcd
è solo un front-end per comodità.
Dovrebbe essere abbastanza veloce, e suppongo che solo la profondità di ricorsione potrebbe essere un problema per problemi molto grandi. Ho effettuato un rapido controllo dei tempi per confrontare con la versione loop di @Adriaan, utilizzando A=randi(100,N,N)-50
, con N=100
, N=1000
e N=5000
e tic
/toc
.
N=100
:
- annodare 0,008 secondi
- ricorsive 0,002 secondi
N=1000
:
- loop 0,46 secondi
- ricorsive 0,04 secondi
N=5000
:
- looping 11,8 secondi
- ricorsive 0,6 secondi
Aggiornamento: cosa interessante è che l'unica ragione per cui non ho scattare il ricorsione limit (che è di default 500) è che i miei dati non avevano un divisore comune. L'impostazione di una matrice casuale e il raddoppio determineranno il raggiungimento del limite di ricorsione già per N=100
. Quindi per le matrici di grandi dimensioni questo non funzionerà. Poi di nuovo, per le piccole matrici @ la soluzione di Adriaan è perfettamente a posto.
Ho anche cercato di riscrivere alla metà del vettore di ingresso in ogni passo ricorsivo: questo infatti risolve il problema del limite di ricorsione, ma è più lente (2 secondi per N=100
, 261 secondi per N=1000
). Potrebbe esserci una via di mezzo da qualche parte, dove la dimensione della matrice è grande (ish) e il runtime non è poi così male, ma non l'ho ancora trovato.
si desidera solo il codice per la divisione, non trovare il minimo comun divisore, giusto? – Max
@Max Beh, ad essere onesti, trovare il divisore comune più basso sarebbe ottimo – dnTosh
Potrebbe voler cambiare il titolo della domanda, perché la risposta a questa domanda è 'A/a'. –