【问题标题】:How do I make modulo and logical indexing work faster?如何使模数和逻辑索引更快地工作?
【发布时间】:2016-08-02 14:20:32
【问题描述】:

考虑以下命令:

c(c>A | c<1) = mod(c(c>A | c<1),A);

其中c 是列向量,A 是标量。

简而言之:有什么方法可以加快这项工作的速度吗?

解释:

c(i) 表示A-by-A 矩阵中的列号。但是,它的值可能大于A 或小于 1,并且此命令应该以某种“PAC-MAN”的方式修复它。如果c(i) 大于A,那么当您到达A 时从1 开始倒数,如果您再次到达A,则从1 重新开始,依此类推,直到您计数到c(i) 的值。这对于c(i)&lt;1 应该以相同的方式工作,因此计数将被反转。

例子:

  • 如果A = 10c(i) = 17,那么在这个命令之后c(i) 应该是 7。

  • 如果A = 10c(i) = -8,那么在这个命令之后c(i) 应该是 2。

  • 如果A = 10c(i) = 213,那么在这个命令之后c(i) 应该是 3。

动机:这个命令是我拥有的仿真模型的一部分,目前它是其中最慢的部分。这个特定的行在模型的每个实现中被调用了数百万(!)次,并且有很多,所以任何改进都会有所帮助。顺便说一句,c 的典型大小约为 10K×1。

p.s.:如果你对标题有更好的建议,我很乐意更改它,我找不到好的。

【问题讨论】:

    标签: matlab indexing


    【解决方案1】:

    您实际上不需要在此处进行任何逻辑索引,因为c &gt; A | c &lt; 1 排除的任何值都不会被mod 触及,并且将所有内容 传递给@ 可能会更快987654326@ 而不是通过比较和索引来确定要传递给mod 的值。

    c = [17 -8 213, 7];
    
    c = mod(c, A);
    %   7   2   3   7
    

    一般来说,对于需要对函数的输入和输出进行逻辑索引的其他函数,您需要将逻辑数组存储在临时变量中,而不是计算两次:

    touse = c < 1 | c > A;
    c(touse) = mod(c(touse), A);
    

    这是一个快速的小基准,显示了每种方法的相对性能:

    function timemod()
    
        sizes = round(linspace(100, 100000, 10));
    
        [times1, times2, times3] = deal(zeros(numel(sizes), 1));
    
        A = 10;
    
        for k = 1:numel(sizes)
    
            data = round(rand(sizes(k), 1) * A * 100);
            times1(k) = timeit(@()indexing(data, A));
    
            data = round(rand(sizes(k), 1) * A * 100);
            times2(k) = timeit(@()indexing_temp(data, A));
    
            data = round(rand(sizes(k), 1) * A * 100);
            times3(k) = timeit(@()mod(data, A));
        end
    
        figure
        plot(sizes, 1000 * cat(2, times1, times2, times3))
        legend({'Indexing', 'Indexing w/ temp', 'No Indexing'})
    
        xlabel('Number of Elements')
        ylabel('Execution Time (ms)')
    
        fprintf('Indexing:              %0.2f ms\n', mean(times1 * 1000))
        fprintf('Indexing with temp:    %0.2f ms\n', mean(times2 * 1000))
        fprintf('No Indexing or temp:   %0.2f ms\n', mean(times3 * 1000))
    end
    
    function data = indexing(data, A)
        data(data > A | data < 1) = mod(data(data > A | data < 1), A);
    end
    
    function data = indexing_temp(data, A)
        inds = data > A | data < 1;
        data(inds) = mod(data(inds), A);
    end
    

    【讨论】:

    • 这太棒了!非常感谢。我不敢相信我错过了这个选项......现在我会早一点完成我的博士学位;)
    • 您能否在c1 = mod(c,A) 的答案中添加第四个选项(赋值给另一个变量)?在我的机器上是最快的。
    • @EBH 你真的用基准代码测试过这个吗?当您正确地分析它时(使用timeit),与c = mod(c, A) 相比应该没有真正的区别
    • @EBH 时间更准确
    猜你喜欢
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多