请考虑以下命令:
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
,那么当您从{1}开始向后计数时,如果再次从{1}再次开始,则从1开始,依此类推,直到您计算为止到A
的值。对于A
,这应该以相同的方式工作,因此计数将被颠倒。
示例:
如果c(i)
和c(i)<1
,则在此命令后A = 10
应该是7。
如果c(i) = 17
和c(i)
,则在此命令后A = 10
应该是2。
如果c(i) = -8
和c(i)
,则在此命令后A = 10
应该是3。
动机:此命令是我所拥有的模拟模型的一部分,目前它是其中最慢的部分。这个特定的行在模型的每个实现中被称为数百万(!)次,并且有很多,所以任何改进都会有所帮助。顺便说一下,c(i) = 213
的典型大小约为10K-1。
p.s。:如果您对标题有更好的建议,我会很乐意改变它,我找不到一个好的。
答案 0 :(得分:4)
您不需要在此处实际执行任何逻辑索引,因为c > A | c < 1
不会触及mod
排除的任何值,并且通过一切可能会更快到mod
,而不是进行比较和索引,以确定要传递给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