2009-06-30 78 views

risposta

39

Il codice originale che suggerisci è il modo migliore.

Matlab è estremamente valido per operazioni vettorializzate come questa, almeno per i vettori di grandi dimensioni.

La funzione di norma incorporata è molto veloce. Qui ci sono alcuni risultati di cronometraggio:

V = rand(10000000,1); 
% Run once 
tic; V1=V/norm(V); toc   % result: 0.228273s 
tic; V2=V/sqrt(sum(V.*V)); toc % result: 0.325161s 
tic; V1=V/norm(V); toc   % result: 0.218892s 

V1 è determinato un seconda volta qui solo per assicurarsi che non vi siano importanti sanzioni della cache alla prima chiamata.

Le informazioni di sincronizzazione sono state prodotte con R2008a x64 su Windows.


EDIT:

risposta riveduta sulla base dei suggerimenti di gnovice (vedi commenti). Matrix matematica (a malapena) conquista:

clc; clear all; 
V = rand(1024*1024*32,1); 
N = 10; 
tic; for i=1:N, V1 = V/norm(V);   end; toc % 6.3 s 
tic; for i=1:N, V2 = V/sqrt(sum(V.*V)); end; toc % 9.3 s 
tic; for i=1:N, V3 = V/sqrt(V'*V);  end; toc % 6.2 s *** 
tic; for i=1:N, V4 = V/sqrt(sum(V.^2)); end; toc % 9.2 s 
tic; for i=1:N, V1=V/norm(V);   end; toc % 6.4 s 

IMHO, la differenza tra "norma (V)" e "sqrt (V '* V)" è abbastanza piccolo che per la maggior parte dei programmi, è meglio andare con quello questo è più chiaro. Per me "norm (V)" è più chiaro e più facile da leggere, ma "sqrt (V '* V)" è ancora idiomatico in Matlab.

+1

Solo per curiosità, quanto veloci sarebbero questi ?: V3 = V/sqrt (V '* V); V4 = V/sqrt (somma (V.^2)); – gnovice

+2

Sono d'accordo sul fatto che la norma (V) è la risposta più diretta, dal momento che c'è poco guadagno di velocità con sqrt (V '* V). L'accelerazione sarebbe ancora meno significativa per il tipico vettore a tre elementi che V di solito è la maggior parte delle volte che uso la norma. – gnovice

+2

@gnovice: sorprendentemente, per vettori a 3 vettori, la norma è circa 3 volte più veloce di sqrt (V '* V). Mi chiedo se MathWorks stia utilizzando alcuni trucchi SSE per i vettori di piccole dimensioni (anche se mi aspetterei che funzionino anche per quelli di grandi dimensioni). –

9

L'unico problema che potresti incontrare è se la norma di V è zero (o molto vicino ad essa). Questo potrebbe darti Inf o NaN quando dividi, insieme a un avviso di divisione per zero. Se non si cura di ottenere un Inf o NaN, si può solo accendere l'avvertimento e si accende con WARNING:

oldState = warning('off','MATLAB:divideByZero'); % Return previous state then 
                % turn off DBZ warning 
uV = V/norm(V); 
warning(oldState); % Restore previous state 

Se non si vuole alcuna Inf o NaN valori, si deve controllare la dimensione della norma prima:

normV = norm(V); 
if normV > 0, % Or some other threshold, like EPS 
    uV = V/normV; 
else, 
    uV = V; % Do nothing since it's basically 0 
end 

Se ho bisogno di un programma, di solito messo il codice di cui sopra nella mia propria funzione, di solito chiamato unità (poiché in pratica trasforma un vettore in un vettore unitario che punta nella stessa direzione).

15

Non conosco MATLAB e non l'ho mai usato, ma mi sembra che tu stia dividendo. Perché? Qualcosa di simile sarà molto più veloce:

d = 1/norm(V) 
V1 = V * d 
+0

E questo dà un altro 30% di accelerazione in Octave. Ben chiazzato – twerdster

+0

Perché è più veloce? Stai ancora dividendo 1. – jnovacho

+2

@jnovacho è più veloce perché stai facendo solo una divisione e la moltiplicazione 'n', dove' n' è la lunghezza del tuo vettore. Altrimenti, faresti divisioni "n". La divisione è più costosa della moltiplicazione. – Arlen

3

Ho preso Mr.il codice di Fooz ed anche ha aggiunto la soluzione di Arlen troppo e qui ci sono i tempi che ho ottenuto per l'ottava:

clc; clear all; 
V = rand(1024*1024*32,1); 
N = 10; 
tic; for i=1:N, V1 = V/norm(V);   end; toc % 7.0 s 
tic; for i=1:N, V2 = V/sqrt(sum(V.*V)); end; toc % 6.4 s 
tic; for i=1:N, V3 = V/sqrt(V'*V);  end; toc % 5.5 s 
tic; for i=1:N, V4 = V/sqrt(sum(V.^2)); end; toc % 6.6 s 
tic; for i=1:N, V1 = V/norm(V);   end; toc % 7.1 s 
tic; for i=1:N, d = 1/norm(V); V1 = V*d;end; toc % 4.7 s 

Poi, a causa di qualcosa Attualmente sto guardando, ho provato questo codice per far sì che ogni riga somme a 1:

clc; clear all; 
m = 2048; 
V = rand(m); 
N = 100; 
tic; for i=1:N, V1 = V ./ (sum(V,2)*ones(1,m));    end; toc % 8.2 s 
tic; for i=1:N, V2 = bsxfun(@rdivide, V, sum(V,2));   end; toc % 5.8 s 
tic; for i=1:N, V3 = bsxfun(@rdivide, V, V*ones(m,1));   end; toc % 5.7 s 
tic; for i=1:N, V4 = V ./ (V*ones(m,m));      end; toc % 77.5 s 
tic; for i=1:N, d = 1./sum(V,2);V5 = bsxfun(@times, V, d);  end; toc % 2.83 s 
tic; for i=1:N, d = 1./(V*ones(m,1));V6 = bsxfun(@times, V, d);end; toc % 2.75 s 
tic; for i=1:N, V1 = V ./ (sum(V,2)*ones(1,m));    end; toc % 8.2 s 
2

Entro la razionale di fare tutto ciò moltiplicazione aggiungo l'entrata alla fine della lista

clc; clear all; 
    V = rand(1024*1024*32,1); 
    N = 10; 
    tic; for i=1:N, V1 = V/norm(V);   end; toc % 4.5 s 
    tic; for i=1:N, V2 = V/sqrt(sum(V.*V)); end; toc % 7.5 s 
    tic; for i=1:N, V3 = V/sqrt(V'*V);  end; toc % 4.9 s 
    tic; for i=1:N, V4 = V/sqrt(sum(V.^2)); end; toc % 6.8 s 
    tic; for i=1:N, V1 = V/norm(V);   end; toc % 4.7 s 
    tic; for i=1:N, d = 1/norm(V); V1 = V*d;end; toc % 4.9 s 
    tic; for i=1:N, d = norm(V)^-1; V1 = V*d;end;toc % 4.4 s 
0

più veloce in assoluto (il tempo è in confronto a Jacobs):

clc; clear all; 
V = rand(1024*1024*32,1); 
N = 10; 
tic; 
for i=1:N, 
    d = 1/sqrt(V(1)*V(1)+V(2)*V(2)+V(3)*V(3)); 
    V1 = V*d; 
end; 
toc % 1.5s 
Problemi correlati