请考虑以下代码:
a=rand(10000); b=rand(10000);
tic; 2*(a<b); toc;
tic; 2.*(a<b); toc;
结果是:
Elapsed time is 0.938957 seconds.
Elapsed time is 0.426517 seconds.
为什么第二种情况比第一种情况快两倍?
编辑: 无论你测试它的顺序如何,我都可以用任何大小的矩阵获得相同的结果
(a<b).*3.56 vs (a<b)*3.56
例如,但不是
(a.*b)*2 vs (a.*b).*2
或
(a*b)*2 vs (a*b).*2
似乎存在与逻辑数组的链接,因为我与
具有相同的结果(a&b)*2 vs (a&b).*2
计算机:R2015b,Windows 10 x64
答案 0 :(得分:6)
我建议对性能进行更严格的检查。将测试放在一个命名函数中,让MATLAB优化两段代码,并多次运行两个代码,选择最快的运行时。我的预感是他们应该花费相同的时间,虽然我现在无法检查合理的矩阵大小。这就是我要做的事情:
function product_timing(N)
a=rand(N);
b=rand(N);
tmin=inf;
for k=1:10
tic;
res1=2*(a<b);
t=toc;
if t<tmin
tmin=t;
end
end
disp(tmin);
tmin=inf;
for k=1:10
tic;
res2=2.*(a<b);
t=toc;
if t<tmin
tmin=t;
end
end
在我的R2012b上,两种方法之间似乎没有明显的区别。然而,正如其他人所指出的那样,R2015b及其新的执行引擎完全不同。
虽然我仍然不确定答案,但我要收集@x1hgg1x(对此答案和问题的评论)和@LuisMendo(in chat)的反馈意见,以便详细说明在我的无知上:
c*3.56
是一个整数因子(线程数?),如果c.*3.56
是c
,则比logical
(有任何标量)慢一倍,但如果c
没有1}}是uint8
或double
使用重新设计的MATLAB®执行引擎更快地运行程序。
改进的架构使用所有的即时(JIT)编译 具有单个执行路径的MATLAB代码。引擎提供 提高语言质量,为未来提供平台 增强。
具体的性能改进包括:
...
元素智慧数学运算
优化了许多元素数学运算的执行。这些 操作是对数组的逐元素算术运算 如下:
>> b = ((a+1).*a)./(5-a);
但是,在查看.*
和*
的文档时,我看不到有关该问题的太多信息。来自array vs matrix operations的关于数组操作的注释,例如.*
:
如果一个操作数是标量而另一个不是标量,则适用MATLAB 另一个操作数的每个元素的标量。这个属性是 称为标量扩展,因为标量扩展为数组 与其他输入大小相同,然后操作执行 通常使用两个数组。
如果至少有一个输入是标量,那么A * B相当于A. * B和 是可交换的。
正如我们所见,A*B
和A.*B
的等价是有争议的。嗯,它们在数学上是等价的,但是有些奇怪的事情正在发生。
由于上面的注释,以及仅logical
数组出现性能差异这一事实,我认为这是一个未记录的功能。我认为它与logical
只相关,每个只占1个字节,但加速并不会显示uint8
数组。我建议,由于logical
实际上只包含一位信息,因此可以进行一些内部优化。这仍然无法解释为什么mtimes
没有这样做,而且肯定与times
与mtimes
的内部运作有关。
有一件事是肯定的:times
对于标量操作数实际上并没有回归mtimes
(也许它应该?)。由于在R2012b中缺少整体效果,我相信上面提到的新执行引擎的优化数组操作分别处理逻辑数组,允许加速scalar.*logical_array
的特殊情况,但是缺少相同的优化mtimes
。
答案 1 :(得分:0)
对于背景,*
运算符是矩阵运算符,而*.
是元素运算符(请参阅http://www.mathworks.com/help/matlab/matlab_prog/array-vs-matrix-operations.html)。
在您的测试中,a和b是随机的1000x1000矩阵,它们评估为您想要使用这两种方法进行缩放的逻辑1000x1000矩阵。除了让Mathworks的开发人员告诉我们发生了什么之外,我认为我们只能推测导致差异的原因(并回答你的问题)。
因为,我们不应该推测这些答案,我将在这里正式停止。然而,有趣的是你偶然发现了同样的事情。
所以,非正式地,我怀疑你发现了一些额外的开销MATLAB正在实现处理与*
运算符的矩阵运算,这些运算符在元素运算符中被短路或旁路。
考虑以下
c = a<b;
tic; d*(c); toc; % case 1
tick;d.*(c); toc; % case 2
其中a
和b
由上面的代码定义,为了便于解释,d
保留为未知值,接下来。
当乘以矩阵时,第一个矩阵中的列数需要与第二个矩阵中的行数匹配。 c
将是1000x1000矩阵,对,d
要么需要1000列(例如size(d,2)==1000
),要么需要是标量。在第二种情况下,d
必须是标量(否则将抛出错误)。
此外,在进行乘法时,可能会有一些额外的准备(不多,但有些),因为您可以正确地为最终产品中的每个位置获得总和。在这里,我们知道d==2
并且它是一个标量,因此乘法可以在适当的位置完成。但是,我们知道因为我们看到了它。我不认为乘法算法在这里作为一个极端情况 - 看看d
是一个标量值。如果是,它将/应该只调用*.
例程。而且,也许这就是正在发生的事情,我们只是获得了一些级别的堆栈开销。当然是非官方的。
答案 2 :(得分:-1)
是的,“。*”在2015b上标量和逻辑数组之间的速度更快:
a = rand(10000); b = rand(10000);
timeit(@()2*a)
timeit(@()2.*a)
timeit(@()2.*(a>b))
timeit(@()2*double(a>b))
timeit(@()2*(a>b))