Sembra come se Mathworks presenta particolari piazze con carter nella sua funzione di potenza (purtroppo, è tutto integrato a sorgente chiuso che non possiamo vedere). Nei miei test su R2013b, sembra che .^
, power
e realpow
utilizzino lo stesso algoritmo. Per le piazze, credo che abbiano un case speciale per essere x.*x
.
1.0x (4.4ms): @()x.^2
1.0x (4.4ms): @()power(x,2)
1.0x (4.5ms): @()x.*x
1.0x (4.5ms): @()realpow(x,2)
6.1x (27.1ms): @()exp(2*log(x))
Per i cubi, la storia è diversa. Non sono più in scatola speciale. Anche in questo caso, .^
, power
e realpow
tutti sono simili, ma molto più lento questa volta: salto
1.0x (4.5ms): @()x.*x.*x
1.0x (4.6ms): @()x.*x.^2
5.9x (26.9ms): @()exp(3*log(x))
13.8x (62.3ms): @()power(x,3)
14.0x (63.2ms): @()x.^3
14.1x (63.7ms): @()realpow(x,3)
Let fino al 16 potere di vedere come questi algoritmi scala:
1.0x (8.1ms): @()x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x
2.2x (17.4ms): @()x.^2.^2.^2.^2
3.5x (27.9ms): @()exp(16*log(x))
7.9x (63.8ms): @()power(x,16)
7.9x (63.9ms): @()realpow(x,16)
8.3x (66.9ms): @()x.^16
Quindi: .^
, power
e realpow
vengono eseguiti tutti in un tempo costante rispetto all'esponente, a meno che non sia stato creato un involucro speciale (anche il formato -1 è stato classificato come speciale). L'uso del trucco exp(n*log(x))
è anche un tempo costante per quanto riguarda l'esponente e più veloce. L'unico risultato non capisco perché la quadratura ripetuta sia più lenta della moltiplicazione.
Come previsto, l'aumento delle dimensioni di x
di un fattore di 100 aumenta il tempo in modo simile per tutti gli algoritmi.
Quindi, morale della storia? Quando si utilizzano esponenti interi scalari, eseguire sempre la moltiplicazione. C'è un sacco di intelligenza in power
e amici (l'esponente può essere a virgola mobile, vettoriale, ecc.). Le uniche eccezioni sono dove Mathworks ha fatto l'ottimizzazione per te. Nel 2013b, sembra essere x^2
e x^(-1)
. Spero che aggiungeranno di più con il passare del tempo. Ma, in generale, l'esponenziazione è difficile e la moltiplicazione è facile. Nel codice sensibile alle prestazioni, non penso che tu possa sbagliare digitando sempre x.*x.*x.*x
. (Naturalmente, nel tuo caso, seguire il consiglio Luis` e fare uso dei risultati intermedi all'interno di ogni termine!)
function powerTest(x)
f{1} = @() x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x.*x;
f{2} = @() x.^2.^2.^2.^2;
f{3} = @() exp(16.*log(x));
f{4} = @() x.^16;
f{5} = @() power(x,16);
f{6} = @() realpow(x,16);
for i = 1:length(f)
t(i) = timeit(f{i});
end
[t,idxs] = sort(t);
fcns = f(idxs);
for i = 1:length(fcns)
fprintf('%.1fx (%.1fms):\t%s\n',t(i)/t(1),t(i)*1e3,func2str(fcns{i}));
end
L'ottimizzazione che è presumibilmente fatta su 'x. * X. * X. * X' si comporta stranamente. Ho provato 'x. *. X. * .... * X' con numeri variabili di" x "da 2 a 8, e il tempo è più o meno linearmente crescente. Mi sarei aspettato urti; ad esempio il caso "8" (=> 'x.^2.^2.^2': tre operazioni di alimentazione) dovrebbe richiedere meno tempo di" 7 "(=> più operazioni di alimentazione) –
@LuisMendo Non so come verificare, ma potrei immaginare che faccia solo 1 passo (nessuna ottimizzazione nidificata). Per 7 si ridurrebbe quindi a qualcosa del tipo: 'x.^2 * x.^2 * x.^2. * x' che non sarebbe più lento di' x.^2 * x.^2 * x.^2 . * x.^2' per 8. Se fare 8 era più veloce di fare 7 in questo modo, probabilmente Mathworks avrebbe impiantato questo tipo di ottimizzazione nella funzione di potenza. –
Sì, questa potrebbe essere la spiegazione: nessuna nidificazione –