如何有效地在MATLAB中规范化矢量?任何相关的内置功能?

时间:2009-06-30 00:53:14

标签: matlab vector performance

我在MATLAB中将向量V规范化为如下:

normalized_V = V/norm(V);

然而,它是在MATLAB中规范化矢量的最优雅(有效)方法吗?

6 个答案:

答案 0 :(得分:41)

您建议的原始代码是最好的方法。

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只是为了确保第一次呼叫没有重要的缓存惩罚。

此处的时序信息是在Windows上使用R2008a x64生成的。


修改

根据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

恕我直言,“norm(V)”和“sqrt(V'* V)”之间的差异足够小,对于大多数程序来说,最好选择更清晰的程序。对我来说,“norm(V)”更清晰,更容易阅读,但“sqrt(V'* V)”在Matlab中仍然是惯用的。

答案 1 :(得分:16)

我不知道任何MATLAB,我从来没有使用它,但在我看来,你正在分裂。为什么?这样的事情会快得多:

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

答案 2 :(得分:9)

你遇到的唯一问题是 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's basically 0
end

如果我在程序中需要它,我通常会将上面的代码放在我自己的函数中,通常称为 unit (因为它基本上将向量转换为指向同一方向的单位向量)。

答案 3 :(得分:4)

我接受了Fooz先生的代码,并且还添加了Arlen的解决方案,以下是我为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

答案 4 :(得分:3)

通过实现所有乘法的合理性,我在列表的末尾添加了条目

    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

答案 5 :(得分:0)

目前为止最快(时间与雅各布相比):

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