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

Je normaliser un vecteur V dans MATLAB comme suit:

normalized_V = V/norm(V); 

Cependant, est-ce le moyen le plus élégant (efficace) de normaliser un vecteur dans MATLAB?

Le code original que vous proposez est le meilleur moyen.

Matlab est extrêmement performant dans les opérations vectorisées comme celle-ci, du moins pour les gros vecteurs.

La fonction de norme intégrée est très rapide. Voici quelques résultats temporels:

 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é une seconde fois ici pour s’assurer qu’il n’y a pas de pénalités importantes en cache lors du premier appel.

Les informations de synchronisation ici ont été produites avec R2008a x64 sous Windows.


MODIFIER:

Réponse révisée basée sur les suggestions de gnovice (voir commentaires). Masortingx math (à 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 suffisamment petite pour que pour la plupart des programmes, il est préférable de choisir celui qui est plus clair. Pour moi, “norm (V)” est plus clair et plus facile à lire, mais “sqrt (V ‘* V)” est toujours idiomatique dans Matlab.

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

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

Le seul problème que vous rencontrerez est si la norme de V est zéro (ou très proche). Cela pourrait vous donner Inf ou NaN lorsque vous divisez, avec un avertissement de division par zéro. Si vous ne vous souciez pas d’obtenir un Inf ou NaN , vous pouvez simplement activer et désactiver l’avertissement en utilisant 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 valeurs Inf ou NaN , vous devez d’abord vérifier la taille de la norme:

 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, je mets généralement le code ci-dessus dans ma propre fonction, généralement appelée unité (car il transforme fondamentalement un vecteur en un vecteur unitaire orienté dans la même direction).

J’ai pris le code de M. Fooz et aussi ajouté la solution d’Arlen et voici les horaires 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 

Puis, à cause de quelque chose que je suis en train de regarder, j’ai testé ce code pour garantir que chaque ligne représente 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 

Par la rationalité de tout faire 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 

Le plus rapide de loin (le temps est en comparaison avec 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