47 votes

Comment normaliser efficacement un vecteur dans MATLAB? Toute fonction intégrée associée?

Je normalise un vecteur V dans MATLAB comme suit:

 normalized_V = V/norm(V);
 

Cependant, est-ce la manière la plus élégante (efficace) de normaliser un vecteur dans MATLAB?

41voto

Mr Fooz Points 21092

Le code d'origine que vous suggérez est le meilleur moyen.

Matlab est extrêmement bon pour vectorisé opérations comme celle-ci, au moins pour les grands vecteurs.

Intégré dans la norme de la fonction est très rapide. Voici quelques résultats de minutage:

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 est calculé un deuxième temps, ici, juste pour s'assurer que il n'y a pas importante cache des sanctions sur le premier appel.

Des informations de synchronisation ici a été réalisé avec R2008a x64 sur Windows.


EDIT:

Révisé réponse repose sur gnovice suggestions (voir les commentaires). Matrice de mathématiques (à peine) gagne:

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

À mon humble avis, la différence entre "norm(V)" et "sqrt(V'V)" est assez petit pour que pour la plupart des programmes, il est préférable d'aller avec celui qui est plus clair. Pour moi, "norm(V)" est plus clair et plus facile à lire, mais "sqrt(V'V)" est toujours idiomatiques dans Matlab.

16voto

Arlen Points 2967

Je ne connais aucun MATLAB et je ne l'ai jamais utilisé, mais il me semble que vous vous divisez. Pourquoi? Quelque chose comme ça sera beaucoup plus rapide:

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

9voto

gnovice Points 70970

Le seul problème que vous rencontrerez est de savoir si la norme de V est nul (ou très près). Cela pourrait vous donner Inf ou NaN lorsque vous divisez, avec une division par zéro avertissement. Si vous n'avez pas de soins sur l'obtention d'un Inf ou NaN, vous pouvez simplement activer l'avertissement à l'aide d'AVERTISSEMENT:

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

Si vous ne voulez pas de Inf ou NaN valeurs, vous devez vérifier la taille de la norme en premier:

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 j'en ai besoin dans un programme, j'ai l'habitude de mettre le code ci-dessus dans mon propre fonction, appelée généralement de l'unité (car il s'avère en fait un vecteur en un vecteur unitaire pointant dans la même direction).

4voto

Jacob Eggers Points 5452

J'ai pris le code de M. Fooz et également ajouté la solution d'Arlen. Voici les temps que j'ai obtenus pour 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
 

Ensuite, à cause de quelque chose que je suis en train de regarder, j'ai testé ce code pour vérifier que chaque rangée vaut 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
 

3voto

Scott Teuscher Points 11

Par le rationnel de tout multiplier j'ajoute l'entrée à la fin de la liste

     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
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X