A == 0真的比~A好吗?

时间:2014-08-16 10:22:59

标签: arrays performance matlab benchmarking logical-operators

问题设置简介

我正在为~A做一些涉及 - A==0double array with no NaNs的基准测试,两者都将A转换为逻辑数组,其中所有zeros都是转换为true值并将其余设置为false值。

对于基准测试,我使用了三组输入数据 -

  • 非常小到小型数据 - 15:5:100
  • 中小型数据 - 50:40:1000
  • 中型到大型数据 - 200:400:3800

输入是使用A = round(rand(N)*20)创建的,其中N是从size数组中获取的参数。因此,N与第一组15 to 100 with stepsize of 5不同,第二组和第三组类似。请注意,我将datasize定义为N,因此元素的数量将为datasize ^ 2或N ^ 2.

基准代码

N_arr = 15:5:100; %// for very small to small sized input array
N_arr = 50:40:1000; %// for small to medium sized input array
N_arr = 200:400:3800; %// for medium to large sized input array
timeall = zeros(2,numel(N_arr));
for k1 = 1:numel(N_arr)
    A = round(rand(N_arr(k1))*20);

    f = @() ~A;
    timeall(1,k1) = timeit(f);
    clear f

    f = @() A==0;
    timeall(2,k1) = timeit(f);
    clear f
end

结果

enter image description here

enter image description here

enter image description here

最后问题

可以看到A==0在所有数据中的表现优于~A。所以这里有一些观察和相关问题 -

  1. A==0有一个关系运算符和一个操作数,而~A只有一个关系运算符。两者都产生逻辑数组并且都接受双数组。事实上,A==0也适用于NaNs,而~A则不会。那么,为什么~A仍然A==0至少不如A==0那么好A==0正在做更多的工作,或者我在这里遗漏了什么?

  2. N = 320经过了一段特别的时间,因此102400的性能提高了,即A的{{1}}个元素。我在很多次运行中观察到这一点我可以访问的两个不同系统上的大小。那么那里发生了什么?

2 个答案:

答案 0 :(得分:5)

这不是严格意义上的答案,而是我对讨论的贡献

我使用profiler来调查代码的略微修改版本:

N_arr = 200:400:3800; %// for medium to large sized input array

for k1 = 1:numel(N_arr)

    A = randi(1,N_arr(k1));
    [~]=eq(A,0);
    clear A

    A = randi(1,N_arr(k1));
    [~]=not(A);
    clear A   

end

我使用了以下探查器标记(根据UndocumentedMatlab's series of posts about Profiler):

profile('-memory','on');
profile('on','-detail','builtin');

这是摘要结果(link to the larger image)的摘录: Profiler output

似乎==变体分配了一小部分额外的内存,使它能够发挥其魔力....

关于您的问题2 :在删除保留timeall之前,我尝试绘制您在Excel中执行的相同图表。我没有观察到你为N = 320提到的行为。我怀疑这可能与您在代码中使用的其他包装器(即函数句柄)有关。


我认为我附上了所讨论功能的可用文档以供快速参考。

~(\ MATLAB \ R20 ??? \ toolbox \ matlab \ ops \ not.m)的文档:

%~   Logical NOT.
%   ~A performs a logical NOT of input array A, and returns an array
%   containing elements set to either logical 1 (TRUE) or logical 0 (FALSE).
%   An element of the output array is set to 1 if A contains a zero value
%   element at that same array location.  Otherwise, that element is set to
%   0.
%
%   B = NOT(A) is called for the syntax '~A' when A is an object.
%
%   ~ can also be used to ignore input arguments in a function definition,
%   and output arguments in a function call.  See "help punct"

%   Copyright 1984-2005 The MathWorks, Inc.

==(\ MATLAB \ R20 ??? \ toolbox \ matlab \ ops \ eq.m)的文档:

%==  Equal.
%   A == B does element by element comparisons between A and B
%   and returns a matrix of the same size with elements set to logical 1
%   where the relation is true and elements set to logical 0 where it is
%   not.  A and B must have the same dimensions unless one is a
%   scalar. A scalar can be compared with any size array.
%
%   C = EQ(A,B) is called for the syntax 'A == B' when A or B is an
%   object.

%   Copyright 1984-2005 The MathWorks, Inc.

答案 1 :(得分:0)

也不是严格的答案,但我想补充讨论。也许归结为你的函数timeit

我尝试过Dev-iL的功能。我已经进行了分析并获得了相同的结果:EQ似乎比NOT更快,而EQ似乎分配的内存比NOT略多。似乎合乎逻辑的是,如果EQ运算符分配更多内存,那么随着我们增加数组大小,内存分配也会增加。可疑的是,它没有!

我接着删除了所有不必要的内容并重复了N=1000次迭代的循环。探查者似乎仍然同意EQNOT更快。但我不相信。

接下来,我的目的是删除看起来很奇怪的[~] = ~A[~] = A == 0,以寻找更加人性化的内容,如tmp1 = ~Atmp2 = A == 0,vo!运行时几乎相等。

profiler results

所以我的猜测是你在timeid函数中做了类似的事情。值得注意的是,作业[~]会降低这两项功能,但NOT似乎比EQ更受影响。

现在最大的问题是:为什么运算符[~]会降低函数的速度?我不知道。也许只有Mathworks可以回答这个问题。您可以在Mathworks网页中打开票证。

部分答案:它们的运行时间几乎相同,即使对于大型阵列(我试过的最大阵列是10K)。

未答复的部分:为什么[~]分配会降低代码速度。为什么NOTEQ更受影响。

我的代码:

clear all
clear classes

array_sizes = [1000:1000:10000];
repetitions = 10000;

for i = 1:length(array_sizes)
    A1 = randi([0, 1], array_sizes(i), 1);
    for j = 1:repetitions
        tmp1 = eq(A1, 0);
    end
end

for i = 1:length(array_sizes)
    A2 = randi([0, 1], array_sizes(i), 1);
    for j = 1:repetitions
        tmp2 = not(A2);
    end
end