Я нормализую вектор V в MATLAB следующим образом:
normalized_V = V/norm(V);
однако, является ли он самым элегантным (эффективным) способом нормализации вектора в MATLAB?
Я нормализую вектор V в MATLAB следующим образом:
normalized_V = V/norm(V);
однако, является ли он самым элегантным (эффективным) способом нормализации вектора в MATLAB?
Исходный код, который вы предлагаете, является лучшим способом.
Matlab чрезвычайно хорош в векторизованных операциях, таких как это, по крайней мере для больших векторов.
Встроенная нормальная функция выполняется очень быстро. Вот некоторые результаты синхронизации:
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 вычисляется во второй раз здесь, чтобы убедиться, что при первом вызове нет важных штрафов за кеш.
Информация о синхронизации здесь была выпущена с R2008a x64 в Windows.
EDIT:
Пересмотренный ответ на основе предложений gnovice (см. комментарии). Матричная математика (едва) выигрывает:
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, разница между "norm (V)" и "sqrt (V '* V)" достаточно мала, что для большинства программ лучше всего пойти с тем, что более понятно. Для меня "норма (V)" более понятна и легче читать, но "sqrt (V '* V)" все еще идиоматична в Matlab.
Я не знаю ни одного MATLAB, и я никогда не использовал его, но мне кажется, что вы делите. Зачем? Что-то вроде этого будет намного быстрее:
d = 1/norm(V)
V1 = V * d
Единственная проблема, с которой вы столкнулись, - это норма нуля V равна нулю (или очень близко к ней). Это может дать вам Inf или NaN, когда вы разделите вместе с предупреждением о делении на ноль. Если вы не хотите получать Inf или NaN, вы можете включить или выключить предупреждение, используя WARNING:
oldState = warning('off','MATLAB:divideByZero'); % Return previous state then
% turn off DBZ warning
uV = V/norm(V);
warning(oldState); % Restore previous state
Если вам не нужны значения Inf или NaN, сначала необходимо проверить размер нормы:
normV = norm(V);
if normV > 0, % Or some other threshold, like EPS
uV = V/normV;
else,
uV = V; % Do nothing since it basically 0
end
Если мне это нужно в программе, я обычно помещаю вышеуказанный код в свою собственную функцию, обычно называемую unit (так как она в основном превращает вектор в единичный вектор, указывающий в том же направлении).
Я взял код г-на Фуза, а также добавил решение Арлена, и вот тайминги, которые я получил для 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
Затем, из-за того, что я сейчас просматриваю, я тестировал этот код для обеспечения того, чтобы каждая строка суммировалась до 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
Рационально сделать все умножение, я добавляю запись в конце списка
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
Самый быстрый (время по сравнению с Джейкобсом):
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