首页 文章

为什么在Matlab . *运算符在某些情况下比标量更快?

提问于
浏览
5

请考虑以下代码:

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

3 回答

  • 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(对这个答案和问题的评论)和@LuisMendoin chat)的反馈,只是为了阐述我的无知:

    如果 clogical

    • c*3.56 是一个比 c.*3.56 (有任何标量)慢的整数因子(线程数?),但如果 cuint8double 则不是

    • 同样适用于矢量,而不仅仅是方形矩阵

    如上所述on a MATLAB product page

    使用重新设计的MATLAB®执行引擎更快地运行程序 . 改进的体系结构使用所有MATLAB代码的即时(JIT)编译和单个执行路径 . 该引擎提供了改进的语言质量,并为未来的增强提供了平台 . 具体的性能改进包括:...元素智能数学运算许多元素数学运算的执行得到优化 . 这些操作是对数组的逐元素算术运算,如下所示:>> b =((a 1) . * a)./(5-a);

    但是,看看 .** 的文档,我看不出有关该问题的太多信息 . array vs matrix operations关于数组操作的注释,如 .*

    如果一个操作数是标量而另一个不是标量,则MATLAB将标量应用于另一个操作数的每个元素 . 此属性称为标量扩展,因为标量扩展为与另一个输入大小相同的数组,然后操作将像通常使用两个数组一样执行 .

    doc of the matrix product *

    如果至少有一个输入是标量,那么A * B相当于A. * B并且是可交换的 .

    如我们所见, A*BA.*B 的等价性是有争议的 . 嗯,它们在数学上是等价的,但是有些奇怪的事情正在发生 .

    由于上面的注释,以及只有 logical 数组出现性能差异这一事实,我认为这是一个未记录的功能 . 我和 logical 只相关,每个只占1个字节,但加速并没有显示 uint8 数组 . 我建议,由于 logical 实际上只包含一位信息,因此可以进行一些内部优化 . 这仍然无法解释为什么 mtimes 确实与 times vs mtimes 的内部运作无关 .

    有一件事是肯定的: times 对于标量操作数实际上并没有回归 mtimes (也许它应该?) . 由于在R2012b中缺少整体效果,我相信上面提到的新执行引擎的优化数组操作分别处理逻辑数组,允许加速 scalar.*logical_array 的特殊情况,但 mtimes 缺少相同的优化 .

  • 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
    

    其中 ab 由上面的代码定义,并且 d 为了解释而留作未知值,接下来 .

    当乘以矩阵时,第一矩阵中的列数需要与第二矩阵中的行数匹配 . c 将是1000x1000矩阵,对,所以 d 要么需要1000列(例如 size(d,2)==1000 ),要么需要是标量 . 在第二种情况下, d 必须是标量(否则将抛出错误) .

    另外,在进行乘法时,可能会有一些额外的准备(不多,但有些),因为您可以为最终产品中的每个位置正确获得总和 . 在这里,我们知道 d==2 并且它是一个标量,因此乘法可以在适当的位置完成 . 但是,我们知道因为我们看到了它 . 我不认为乘法算法在这里作为一个角落案例 - 看到 d 是一个标量值 . 如果是,它将/应该只调用 *. 例程 . 而且,也许这就是正在发生的事情,我们只是获得了一些级别的堆栈开销 . 当然是非官方的 .

  • -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))
    

相关问题