2009-06-30 16 views

Respuesta

39

El código original que sugiere es la mejor manera.

Matlab es extremadamente bueno en operaciones vectorizadas como esta, al menos para vectores grandes.

La función de norma incorporada es muy rápida. Aquí están algunos resultados de sincronización:

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 se calcula una segunda vez aquí sólo para asegurarse de que no hay sanciones importantes de caché en la primera llamada.

La información de temporización aquí se produjo con R2008a x64 en Windows.


EDIT:

respuesta revisada sobre la base de las sugerencias de gnovice (ver comentarios). matemáticas matriz (apenas) ha sufrido:

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 

en mi humilde opinión, la diferencia entre la "norma (V)" y "sqrt (V '* V)" es lo suficientemente pequeño que para la mayoría de los programas, lo mejor es ir con el eso es más claro Para mí, "norma (V)" es más clara y fácil de leer, pero "sqrt (V '* V)" sigue siendo idiomática en Matlab.

+1

Sólo por curiosidad, ¿qué tan rápido funcionarían estos ?: V3 = V/sqrt (V '* V); V4 = V/sqrt (suma (V.^2)); – gnovice

+2

Acepto que la norma (V) es la respuesta más directa, ya que hay poca ganancia de velocidad con sqrt (V '* V). La aceleración sería aún menos significativa para el vector típico de tres elementos que V suele ser la mayoría de las veces que utilizo la norma. – gnovice

+2

@gnovice: sorprendentemente, para 3 vectores, la norma es aproximadamente 3 veces más rápida que sqrt (V '* V). Me pregunto si MathWorks está utilizando algunos trucos SSE para vectores pequeños (aunque también espero que funcionen para los grandes). –

9

El único problema con el que se encontraría es si la norma de V es cero (o muy similar a ella). Esto podría darle Inf o NaN cuando se divide, junto con una advertencia de dividir por cero. Si no se preocupan por conseguir un Inf o NaN, sólo puede activar el aviso y se apaga con WARNING:

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

si no quieren ninguna Inf o NaN valores, se tienen que comprobar el tamaño de la norma primera:

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 

Si lo necesito en un programa, que suelen poner el código anterior en mi propia función, generalmente llamado unidad (ya que básicamente convierte un vector en un vector unitario que apunta en la misma dirección).

15

No conozco ningún MATLAB y nunca lo he usado, pero me parece que estás dividiéndote. ¿Por qué? Algo así será mucho más rápido:

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

Y eso le da otro 30% de aceleración en Octave. Bien visto – twerdster

+0

¿Por qué es más rápido? Todavía estás dividiendo 1. – jnovacho

+2

@jnovacho es más rápido porque estás haciendo una sola división y una multiplicación 'n', donde' n' es la longitud de tu vector. De lo contrario, estarías haciendo 'n' divisiones. La división es más costosa que la multiplicación. – Arlen

3

Me llevé al Sr.Código de fooz y también añadió una solución de Arlen también y aquí están los tiempos que he conseguido para Octave:

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 

Entonces, debido a algo que actualmente estoy mirando, he probado a cabo este código para asegurar que cada fila sumas 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

por lo racional de hacer todo lo que la multiplicación agrego la entrada al final de la 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

más rápido, con mucho, (el tiempo es en comparación con 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 
Cuestiones relacionadas