arrays - escape - ¿Es A== 0 realmente mejor que ~ A?
split shopify liquid (2)
Introducción a la configuración del problema
Estaba haciendo algunos puntos de referencia que implican ~A
y A==0
para una double array with no NaNs
, que convierten a A
en una matriz lógica donde todos los zeros
se convierten en valores true
y el resto se establecen como valores false
.
Para la evaluación comparativa, he utilizado tres conjuntos de datos de entrada:
- Datos de tamaño pequeño a pequeño:
15:5:100
- Datos de tamaño pequeño a mediano:
50:40:1000
- Datos de tamaño mediano a grande -
200:400:3800
La entrada se crea con A = round(rand(N)*20)
, donde N es el parámetro tomado de la matriz de tamaños. Por lo tanto, N
podría variar de 15 to 100 with stepsize of 5
para el primer conjunto y de manera similar para el segundo y tercer conjunto. Tenga en cuenta que estoy definiendo Datasize como N, por lo tanto, la cantidad de elementos sería Datasize ^ 2 o N ^ 2.
Código de Benchmarking
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
Resultados
Finalmente las preguntas
Uno puede ver cómo A==0
tiene un rendimiento mejor que ~A
en todos los tamaños de datos. Aquí hay algunas observaciones y preguntas relacionadas junto con ellos:
A==0
tiene un operador relacional y un operando, mientras que~A
tiene solo un operador relacional. Ambos producen arreglos lógicos y ambos aceptan arreglos dobles. De hecho,A==0
también funcionaría conNaNs
, mientras que~A
no lo hará. Entonces, ¿por qué sigue siendo~A
al menos no tan bueno comoA==0
ya que parece queA==0
está haciendo más trabajo o me falta algo aquí?Hay una gota peculiar de tiempo transcurrido con
A==0
y, por tanto, un mayor rendimiento enN = 320
, es decir,102400
elementos para A. He observado esto en muchas ejecuciones con ese tamaño en dos sistemas diferentes a los que tengo acceso. Entonces, ¿qué está pasando allí?
También no es estrictamente una respuesta, pero quiero agregar a la discusión. Tal vez se reduce a su tiempo de función.
Probé la función de Dev-iL. He creado un perfil y obtuve los mismos resultados: el EQ
parece ser más rápido que el NOT
y el EQ
parece asignar un poco más de memoria que NOT
. Parecía lógico que si el operador de EQ
está asignando más memoria, entonces, a medida que aumentamos el tamaño de la matriz, la asignación de memoria también aumentaría. Sospechosamente, ¡no es así!
Continué y eliminé todo lo innecesario y repetí el ciclo para N=1000
iteraciones. El generador de perfiles parecía estar de acuerdo en que EQ
es más rápido que NOT
. Pero no estaba convencido.
Lo siguiente que hice fue eliminar el extraño aspecto [~] = ~A
y [~] = A == 0
para algo más humano como tmp1 = ~A
y tmp2 = A == 0
y voilà! Los tiempos de ejecución son casi iguales.
Así que supongo que estás haciendo algo similar dentro de tu función timeid
. Vale la pena notar que la asignación [~]
ralentiza ambas funciones, pero NOT
parece ser más afectada que EQ
.
Ahora la gran pregunta: ¿por qué el operador [~]
frena las funciones? No lo sé. Quizás solo Mathworks pueda responder eso. Puede abrir un ticket en la página web de Mathworks.
Respuesta parcial : tienen casi el mismo tiempo de ejecución, incluso para arreglos grandes (la matriz más grande que probé es 10K).
Parte no respondida : por qué [~]
asignación ralentiza el código. Por qué NOT
es más afectado que EQ
Mi código:
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
Esto no es estrictamente una respuesta sino más bien mi contribución a la discusión
profiler
el profiler
de profiler
para investigar una versión ligeramente modificada de tu código:
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
Usé los siguientes indicadores de perfil (según la serie de publicaciones de UndocumentedMatlab sobre Profiler
):
profile(''-memory'',''on'');
profile(''on'',''-detail'',''builtin'');
Y aquí hay un extracto de los resultados del perfilador ( enlace a la imagen más grande ):
Parece que la variante ==
asigna un poquito de memoria adicional que le permite trabajar su magia ...
En relación con su pregunta 2 : antes de eliminar el mantenimiento del timeall
, traté de trazar los mismos gráficos que hizo en Excel. No observé el comportamiento que mencionaste para N = 320
. Sospecho que esto puede tener algo que ver con los contenedores adicionales (es decir, los identificadores de funciones) que está usando en su código.
Pensé en adjuntar la documentación disponible para las funciones discutidas para una referencia rápida.
La documentación para ~
(/ 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.
La documentación para ==
(/ 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.