如何在MATLAB中有效地实现向量的规范化?相关的内置函数吗?

时间:2022-09-11 19:26:18

I normalize a vector V in MATLAB as following:

在MATLAB中,我将向量V标准化如下:

normalized_V = V/norm(V);

however, is it the most elegant (efficient) way to normalize a vector in MATLAB?

然而,它是在MATLAB中使向量标准化的最优雅(有效)方法吗?

6 个解决方案

#1


39  

The original code you suggest is the best way.

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

Matlab is extremely good at vectorized operations such as this, at least for large vectors.

Matlab非常擅长矢量化操作,至少对于大向量是这样的。

The built-in norm function is very fast. Here are some timing results:

内置的标准函数非常快。以下是一些计时结果:

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 is calculated a second time here just to make sure there are no important cache penalties on the first call.

V1是第二次计算,以确保在第一次调用时没有重要的缓存惩罚。

Timing information here was produced with R2008a x64 on Windows.

这里的计时信息是用R2008a x64在Windows上生成的。


EDIT:

编辑:

Revised answer based on gnovice's suggestions (see comments). Matrix math (barely) wins:

根据g初学者的建议修改答案(参见注释)。矩阵数学(几乎)赢得:

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, the difference between "norm(V)" and "sqrt(V'*V)" is small enough that for most programs, it's best to go with the one that's more clear. To me, "norm(V)" is clearer and easier to read, but "sqrt(V'*V)" is still idiomatic in Matlab.

IMHO,“norm(V)”和“sqrt(V'*V)”之间的区别非常小,对于大多数程序来说,最好使用更清晰的程序。对我来说,“norm(V)”更清晰,更容易阅读,但是“sqrt(V'*V)”在Matlab中仍然是惯用的。

#2


15  

I don't know any MATLAB and I've never used it, but it seems to me you are dividing. Why? Something like this will be much faster:

我不知道有没有MATLAB,我也没用过,但在我看来,你是在分裂。为什么?像这样的东西会快得多:

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

#3


9  

The only problem you would run into is if the norm of V is zero (or very close to it). This could give you Inf or NaN when you divide, along with a divide-by-zero warning. If you don't care about getting an Inf or NaN, you can just turn the warning on and off using WARNING:

你遇到的唯一问题是,如果V的范数是零(或非常接近)。这可能会给你带来Inf或NaN,当你分开的时候,加上一个零分的警告。如果你不关心如何获得Inf或NaN,你可以使用警告来打开和关闭警告:

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

If you don't want any Inf or NaN values, you have to check the size of the norm first:

如果您不想要任何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

If I need it in a program, I usually put the above code in my own function, usually called unit (since it basically turns a vector into a unit vector pointing in the same direction).

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

#4


3  

I took Mr. Fooz's code and also added Arlen's solution too and here are the timings that I've gotten for Octave:

我拿了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

Then, because of something I'm currently looking at, I tested out this code for ensuring that each row sums to 1:

然后,由于我正在查看的一些东西,我测试了这个代码,以确保每一行的总和为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

#5


2  

By the rational of making everything multiplication I add the entry at the end of the list

通过把所有的东西都做乘法,我在列表的末尾添加了条目。

    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

#6


0  

Fastest by far (time is in comparison to 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

#1


39  

The original code you suggest is the best way.

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

Matlab is extremely good at vectorized operations such as this, at least for large vectors.

Matlab非常擅长矢量化操作,至少对于大向量是这样的。

The built-in norm function is very fast. Here are some timing results:

内置的标准函数非常快。以下是一些计时结果:

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 is calculated a second time here just to make sure there are no important cache penalties on the first call.

V1是第二次计算,以确保在第一次调用时没有重要的缓存惩罚。

Timing information here was produced with R2008a x64 on Windows.

这里的计时信息是用R2008a x64在Windows上生成的。


EDIT:

编辑:

Revised answer based on gnovice's suggestions (see comments). Matrix math (barely) wins:

根据g初学者的建议修改答案(参见注释)。矩阵数学(几乎)赢得:

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, the difference between "norm(V)" and "sqrt(V'*V)" is small enough that for most programs, it's best to go with the one that's more clear. To me, "norm(V)" is clearer and easier to read, but "sqrt(V'*V)" is still idiomatic in Matlab.

IMHO,“norm(V)”和“sqrt(V'*V)”之间的区别非常小,对于大多数程序来说,最好使用更清晰的程序。对我来说,“norm(V)”更清晰,更容易阅读,但是“sqrt(V'*V)”在Matlab中仍然是惯用的。

#2


15  

I don't know any MATLAB and I've never used it, but it seems to me you are dividing. Why? Something like this will be much faster:

我不知道有没有MATLAB,我也没用过,但在我看来,你是在分裂。为什么?像这样的东西会快得多:

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

#3


9  

The only problem you would run into is if the norm of V is zero (or very close to it). This could give you Inf or NaN when you divide, along with a divide-by-zero warning. If you don't care about getting an Inf or NaN, you can just turn the warning on and off using WARNING:

你遇到的唯一问题是,如果V的范数是零(或非常接近)。这可能会给你带来Inf或NaN,当你分开的时候,加上一个零分的警告。如果你不关心如何获得Inf或NaN,你可以使用警告来打开和关闭警告:

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

If you don't want any Inf or NaN values, you have to check the size of the norm first:

如果您不想要任何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

If I need it in a program, I usually put the above code in my own function, usually called unit (since it basically turns a vector into a unit vector pointing in the same direction).

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

#4


3  

I took Mr. Fooz's code and also added Arlen's solution too and here are the timings that I've gotten for Octave:

我拿了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

Then, because of something I'm currently looking at, I tested out this code for ensuring that each row sums to 1:

然后,由于我正在查看的一些东西,我测试了这个代码,以确保每一行的总和为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

#5


2  

By the rational of making everything multiplication I add the entry at the end of the list

通过把所有的东西都做乘法,我在列表的末尾添加了条目。

    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

#6


0  

Fastest by far (time is in comparison to 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