为了测量速度上的差异,我们进行了一些测试。这些测试考虑了两种不同的操作:
和四种不同形状要操作的数组:
-
N×N 数组和N×1 数组
-
N×N×N×N 数组和N×1×N 数组
-
N×N 数组和1×N 数组
-
N×N×N×N 数组和1×N×N 数组
对于操作和数组形状的八种组合中的每一种,使用隐式扩展和bsxfun 完成相同的操作。 N 的多个值用于覆盖从小数组到大数组的范围。 timeit 用于可靠计时。
基准测试代码在此答案的末尾给出。它已在 Matlab R2016b、Windows 10、12 GB RAM 上运行。
结果
下图显示了结果。横轴是输出数组的元素个数,比N 更能衡量大小。
还使用逻辑运算(而不是算术)进行了测试。为简洁起见,此处未显示结果,但显示了类似的趋势。
结论
根据图表:
- 结果证实,对于小型数组,隐式扩展更快,并且对于大型数组具有与
bsxfun 相似的速度。
- 至少在考虑的情况下,沿第一个维度或沿其他维度扩展似乎没有太大影响。
- 对于小型阵列,差异可能是十倍或更多。但是请注意,
timeit 对于小尺寸并不准确,因为代码太快了(事实上,它会针对如此小的尺寸发出警告)。
- 当输出的元素数量达到大约
1e5 时,两个速度变得相等。此值可能取决于系统。
由于速度提升仅在数组较小时才显着,在这种情况下任何一种方法都非常快,因此使用隐式扩展或bsxfun 似乎主要是品味、可读性或向后兼容性的问题.
基准代码
clear
% NxN, Nx1, addition / power
N1 = 2.^(4:1:12);
t1_bsxfun_add = NaN(size(N1));
t1_implicit_add = NaN(size(N1));
t1_bsxfun_pow = NaN(size(N1));
t1_implicit_pow = NaN(size(N1));
for k = 1:numel(N1)
N = N1(k);
x = randn(N,N);
y = randn(N,1);
% y = randn(1,N); % use this line or the preceding one
t1_bsxfun_add(k) = timeit(@() bsxfun(@plus, x, y));
t1_implicit_add(k) = timeit(@() x+y);
t1_bsxfun_pow(k) = timeit(@() bsxfun(@power, x, y));
t1_implicit_pow(k) = timeit(@() x.^y);
end
% NxNxNxN, Nx1xN, addition / power
N2 = round(sqrt(N1));
t2_bsxfun_add = NaN(size(N2));
t2_implicit_add = NaN(size(N2));
t2_bsxfun_pow = NaN(size(N2));
t2_implicit_pow = NaN(size(N2));
for k = 1:numel(N1)
N = N2(k);
x = randn(N,N,N,N);
y = randn(N,1,N);
% y = randn(1,N,N); % use this line or the preceding one
t2_bsxfun_add(k) = timeit(@() bsxfun(@plus, x, y));
t2_implicit_add(k) = timeit(@() x+y);
t2_bsxfun_pow(k) = timeit(@() bsxfun(@power, x, y));
t2_implicit_pow(k) = timeit(@() x.^y);
end
% Plots
figure
colors = get(gca,'ColorOrder');
subplot(121)
title('N\times{}N, N\times{}1')
% title('N\times{}N, 1\times{}N') % this or the preceding
set(gca,'XScale', 'log', 'YScale', 'log')
hold on
grid on
loglog(N1.^2, t1_bsxfun_add, 's-', 'color', colors(1,:))
loglog(N1.^2, t1_implicit_add, 's-', 'color', colors(2,:))
loglog(N1.^2, t1_bsxfun_pow, '^-', 'color', colors(1,:))
loglog(N1.^2, t1_implicit_pow, '^-', 'color', colors(2,:))
legend('Addition, bsxfun', 'Addition, implicit', 'Power, bsxfun', 'Power, implicit')
subplot(122)
title('N\times{}N\times{}N{}\times{}N, N\times{}1\times{}N')
% title('N\times{}N\times{}N{}\times{}N, 1\times{}N\times{}N') % this or the preceding
set(gca,'XScale', 'log', 'YScale', 'log')
hold on
grid on
loglog(N2.^4, t2_bsxfun_add, 's-', 'color', colors(1,:))
loglog(N2.^4, t2_implicit_add, 's-', 'color', colors(2,:))
loglog(N2.^4, t2_bsxfun_pow, '^-', 'color', colors(1,:))
loglog(N2.^4, t2_implicit_pow, '^-', 'color', colors(2,:))
legend('Addition, bsxfun', 'Addition, implicit', 'Power, bsxfun', 'Power, implicit')