A == 0 è davvero migliore di ~ A?

Introduzione alla configurazione del problema

Stavo facendo alcuni benchmark che coinvolgono – ~A e A==0 per un double array with no NaNs , entrambi convertono A in un array logico dove tutti gli zeros sono convertiti in valori true e il resto sono impostati come valori false .

Per il benchmarking, ho utilizzato tre serie di dati di input:

  • Dati da molto piccoli a piccoli – 15:5:100
  • Dati di piccole e medie dimensioni 50:40:1000
  • Dati di dimensioni medio-grandi – 200:400:3800

L’input viene creato con A = round(rand(N)*20) , dove N è il parametro preso dall’array delle dimensioni. Quindi, N varierebbe da 15 to 100 with stepsize of 5 per il primo set e allo stesso modo per il secondo e il terzo set. Si noti che sto definendo il datasize come N, quindi il numero di elementi sarebbe datasize ^ 2 o N ^ 2.

Codice di riferimento

 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 

risultati

inserisci la descrizione dell'immagine qui

inserisci la descrizione dell'immagine qui

inserisci la descrizione dell'immagine qui

Finalmente le domande

Si può vedere come A==0 comporta meglio di ~A su tutti i dati. Quindi ecco alcune osservazioni e domande correlate a fianco –

  1. A==0 ha un operatore relazionale e un operando, mentre ~A ha un solo operatore relazionale. Entrambi producono array logici e accettano entrambi i double array. In effetti, A==0 funzionerebbe anche con i NaNs , dove ~A non lo farebbe. Quindi, perché è ancora ~A almeno non buono come A==0 in quanto A==0 sta facendo più lavoro o mi manca qualcosa qui?

  2. C’è un calo particolare del tempo trascorso con A==0 e quindi un aumento delle prestazioni a N = 320 , cioè a 102400 elementi per A. Ho osservato questo attraverso molte esecuzioni con quella dimensione su due sistemi diversi a cui ho accesso. Quindi cosa sta succedendo lì?

Questa non è una risposta rigorosa, ma piuttosto il mio contributo alla discussione

Ho usato il profiler per indagare su una versione leggermente modificata del tuo codice:

 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 

Ho usato i seguenti flag di profiler (come da serie di post di Profiler su Profiler ):

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

Ed ecco un estratto dai risultati del profiler ( link all’immagine più grande ): Uscita del profiler

Sembra che la variante == allochi un po ‘di memoria aggiuntiva che gli consenta di far funzionare la sua magia ….

Riguardo alla tua domanda 2 : Prima di rimuovere la conservazione di timeall , ho provato a tracciare gli stessi grafici che hai fatto in Excel. Non ho osservato il comportamento che hai menzionato per N = 320 . Ho il sospetto che questo possa avere qualcosa a che fare con i wrapper aggiuntivi (ad es. I manici di funzione) che stai usando nel tuo codice.


Ho pensato di albind la documentazione disponibile per le funzioni discusse per una rapida consultazione.

La documentazione per ~ (\ 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 documentazione per == (\ 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. 

Inoltre non è strettamente una risposta, ma voglio aggiungere alla discussione. Forse si riduce al tuo timeit funzione.

Ho provato la funzione di Dev-iL. Ho profilato e ottenuto gli stessi risultati: EQ sembra essere più veloce di NOT e EQ sembra allocare un po ‘più di memoria rispetto a NOT . Sembra logico che se l’operatore EQ stia allocando più memoria, aumentando la dimensione dell’array, aumenterebbe anche quella di memoria. Sospettosamente, non è così!

Sono andato avanti e cancellato tutto inutile e ripetuto il ciclo per N=1000 iterazioni. Il profiler sembrava essere ancora d’accordo sul fatto che l’ EQ fosse più veloce di NOT . Ma non ero convinto.

Poi ho fatto rimuovere l’aspetto strano [~] = ~A e [~] = A == 0 per qualcosa di più umano che assomiglia a tmp1 = ~A e tmp2 = A == 0 e voilà! I runtime sono quasi uguali.

risultati del profiler

Quindi la mia ipotesi è che tu stia facendo qualcosa di simile nella tua funzione timeid . Vale la pena notare che l’assegnazione [~] rallenta entrambe le funzioni, ma NOT sembra essere più influenzata EQ .

Ora la grande domanda: perché l’operatore [~] rallenta le funzioni? Non lo so. Forse solo Mathworks può rispondere a questo. È ansible aprire un ticket nella pagina Web di Mathworks.

Risposta parziale : hanno quasi lo stesso tempo di esecuzione, anche per i grandi array (il più grande array che ho provato è 10K).

Parte senza risposta : perché [~] assegnazione rallenta il codice. Perché NOT è più influenzato EQ .

Il mio codice:

 clear all clear classs 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