Perché utilizzare i confronti anziché il runtime per confrontare due algoritmi?


19

Noto che in alcuni articoli di ricerca CS, per confrontare l'efficienza di due algoritmi, viene utilizzato il numero totale di confronto chiave negli algoritmi anziché i tempi di calcolo reali. Perché non possiamo confrontare quale è meglio eseguendo entrambi i programmi e contando il tempo totale necessario per eseguire gli algoritmi?


Benvenuto! Spero che molti di questi documenti non utilizzino i runtime. So che alcuni lo fanno, specialmente nelle comunità più applicate e quando i sistemi considerati sono molto complessi.
Raffaello

Risposte:


14

Questo è in realtà un problema profondo che ha delle risposte metodiche e pragmatiche. Presumo che tu voglia sapere qualcosa sugli algoritmi a portata di mano. Se vuoi sapere quale algoritmo funziona meglio su una determinata macchina su determinati input, vai avanti e misura i tempi di esecuzione. Se si desidera confrontare la qualità di un compilatore per un determinato algoritmo, procedere e misurare i tempi di esecuzione. Per imparare qualcosa sull'algoritmo, non farlo.

Consentitemi innanzitutto di spiegare alcune ragioni per cui l'utilizzo dei runtime non è una buona idea.

  1. I
    runtime generati misurati usando una lingua e un compilatore su una macchina hanno poco significato se si cambia un componente. Anche implementazioni leggermente diverse dello stesso algoritmo possono funzionare in modo diverso perché si attiva una certa opimizzazione del compilatore nel caso ma non nell'altro.
  2. Previsione
    Quindi hai un paio di runtime per alcuni input. Che cosa dice questo sul tempo di esecuzione di qualche altro input? In generale, niente.
  3. Significato
    Di solito, non comparerai tutti gli input (di una certa dimensione), in modo da limitare immediatamente la tua capacità di confrontare gli algoritmi: forse il tuo set di test ha innescato il caso peggiore in uno e il caso migliore nell'altro algoritmo? O forse i tuoi input erano troppo piccoli per mostrare il comportamento in fase di esecuzione .
  4. Misurazione
    tempi di esecuzione di misura bene non è banale. C'è un JIT? C'è stata contesa, cioè stai contando il tempo in cui l'algoritmo non è stato eseguito? Riesci a riprodurre esattamente lo stesso stato macchina per un'altra corsa (dell'altro algoritmo), in particolare processi e cache simultanei? Come viene gestita la latenza della memoria?

Spero che questi ti abbiano convinto che i tempi di esecuzione sono una misura orribile per confrontare gli algoritmi e che è necessario un metodo generale e astratto per indagare il tempo di esecuzione degli algoritmi.

Passiamo alla seconda parte della domanda. Perché utilizziamo confronti o operazioni elementari simili?

  1. Tracciabilità analitica
    Supponendo che tu voglia fare un'analisi formale, devi essere in grado di farlo. Il conteggio delle singole affermazioni è molto tecnico, a volte persino difficile; alcune persone lo fanno comunque (es. Knuth). Contare solo alcune affermazioni - quelle che dominano il runtime - è più facile. Per lo stesso motivo, spesso "solo" investigiamo (limiti superiori su) il runtime nel caso peggiore.

  2. Dominanza
    L'operazione selezionata domina il runtime. Ciò non significa che contribuisca al maggior tempo di esecuzione - i confronti chiaramente no, ad esempio in Quicksort durante l'ordinamento di numeri interi di dimensioni di parole. Ma vengono eseguiti il più spesso , quindi contandoli conti la frequenza con cui vengono eseguite le parti più eseguite dell'algoritmo. Di conseguenza, il runtime asintotico è proporzionale al numero di operazioni elementari dominanti. Questo è il motivo per cui ci sentiamo a nostro agio nell'utilizzare la notazione Landau e la parola "runtime" anche se contiamo solo i confronti.

Si noti che può essere utile contare più di un'operazione. Ad esempio, alcune varianti di Quicksort richiedono più confronti ma meno scambi di altre (in media).

Per quello che vale, dopo aver fatto tutta la teoria che potresti voler rivedere i tempi di esecuzione per verificare che le previsioni fatte dalla tua teoria siano valide. Se non lo sono, la tua teoria non è utile (in pratica) e deve essere estesa. La gerarchia della memoria è una delle prime cose che ti rendi conto è importante ma manca nelle analisi di base.


1
Tieni presente che anche l'analisi formale ha i suoi limiti. Ad esempio, il caso medio per distribuzioni di input non uniformi è spesso intrattabile.
Raffaello

10

Questo perché il tempo totale di esecuzione degli algoritmi dipende dall'hardware in cui viene eseguito insieme ad altri fattori. Non è affidabile confrontare due algoritmi se uno è in esecuzione su un Pentium 4 e l'altro su un Core i7. Non solo, ma supponiamo che tu abbia eseguito entrambi sullo stesso computer. Cosa c'è da dire che entrambi hanno la stessa quantità di tempo del processore? Cosa succede se qualche altro processo ha una priorità più alta rispetto a quella degli algoritmi?

Per ovviare a questo, ci separiamo da questo tempo complessivo per il completamento e confrontiamo invece in base alla scala dell'algoritmo. Potresti aver notato notazioni come O (1) o O (n ^ 2) nei documenti di ricerca. Ciò può richiedere un po 'di più leggendo, se siete interessati vedere notazione O-grande .


1
Inoltre il tempo di esecuzione effettivo dipende dalle dimensioni e dal contenuto dell'input effettivo utilizzato per eseguire gli algoritmi!
Tsuyoshi Ito,

7

Poiché le altre risposte spiegano perché analizziamo il runtime in termini di numero di operazioni elementari, lasciatemi offrire un paio di ragioni per cui i confronti sono la giusta metrica di molti (non tutti) algoritmi di ordinamento:

  • per molti algoritmi di ordinamento il numero di confronti domina il tempo di esecuzione, vale a dire almeno tanti confronti vengono eseguiti come qualsiasi altra operazione elementare
  • i confronti sono un'operazione costosa ; pensa a come viene implementata una routine di ordinamento in libreria: alla funzione di ordinamento viene passata una matrice di elementi e un puntatore a una funzione che confronta due elementi; in generale, chiamare e attendere l'esecuzione della funzione di confronto è più costoso delle operazioni "interne"; poiché questa funzione è fornita dall'utente, è più difficile ottimizzarla
  • (questo può o non può essere un buon motivo per alcuni) possiamo dire qualcosa di interessante sul numero di confronti che sono sufficienti e necessari per ordinare una sequenza; sappiamo come farlo nel peggiore dei casi e in media per varie distribuzioni, anche come progettare un algoritmo che converge in modo ottimale quando viene eseguito su elementi campionati da una distribuzione sconosciuta ( algoritmi di auto-miglioramento ); sappiamo come fare questo quando alcuni confronti vengono dati gratuitamente ( ordinamento con informazioni parziali )

1) "almeno tanti confronti vengono eseguiti come qualsiasi altra operazione elementare" - solo fino a un fattore costante. 2) "i confronti sono un'operazione costosa" - che presuppone un'impostazione generica. Per l'ordinamento dei numeri interi (che di solito viene analizzato), gli swap sono in genere più costosi.
Raffaello

sicuro. op sembrava essere confuso sull'analisi degli algoritmi in generale, non voleva portare fattori costanti. spero che dalla descrizione sia chiaro il fatto che sto parlando di un'impostazione generica - la routine di ordinamento in una libreria standard non è l'ordinamento intero
Sasho Nikolov,

inoltre i documenti che op ha visto non riguardano sicuramente algoritmi di ordinamento di numeri interi specializzati, nessuno conta il numero di confronti
Sasho Nikolov,

@Raphael L'ordinamento di piccoli numeri interi non è un problema comune nella pratica. Scommetto che la maggior parte degli ordinamenti che si verificano nel mondo è su stringhe (di una certa lunghezza o altro ). Anche per l'ordinamento di numeri interi, non sono sicuro che sia accurato che gli swap siano più costosi: la ramificazione è un'operazione relativamente costosa su un moderno processore di fascia alta, visto che la previsione del ramo sarebbe per lo più inutile durante l'ordinamento.
Gilles 'SO- smetti di essere malvagio' il

@Gilles Di per sé, gli swap sono più costosi dei confronti interi rispetto a qualsiasi piattaforma che conosca. I costi "secondari" come ad esempio le previsioni errate delle filiali sono sicuramente un fattore, il cui impatto è oggetto di ricerche in corso. (Per quanto riguarda l'uso nella pratica, non posso rilasciare una dichiarazione qualificata. Tuttavia, osservo che i manutentori di librerie standard continuano a migliorare gli algoritmi di ordinamento che usano per i tipi di dati primitivi, quindi presumo che vedano un sacco di (ab) uso.)
Raffaello
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.