Giustificazione per trascurare i fattori costanti in Big O


20

Molte volte se le complessità hanno costanti come 3n, trascuriamo questa costante e diciamo O (n) e non O (3n). Non riesco a capire come possiamo trascurare questo cambiamento di tre volte? Alcune cose variano 3 volte più rapidamente di altre! Perché trascuriamo questo fatto?


La semantica di "can" è importante. In pratica, di solito non possiamo trascurare tali cambiamenti, ma ciò (vale a dire la descrizione delle prestazioni degli algoritmi nel mondo reale) non è ciò per cui la notazione di Landau è fatta. Formalismi più precise fanno esistere.
Raffaello

Risposte:


22

Per razionalizzare il modo in cui le notazioni asintotiche ignorano i fattori costanti, di solito la penso in questo modo: la complessità asintotica non è per confrontare le prestazioni di algoritmi diversi, è per capire come le prestazioni dei singoli algoritmi si ridimensionano rispetto alla dimensione dell'input.

Ad esempio, diciamo che una funzione che esegue 3n passaggi è O(n) , poiché, in termini approssimativi, per input abbastanza grandi, il raddoppio della dimensione dell'input non supererà il doppio del numero di passaggi effettuati. Allo stesso modo, O(n2) significa che il raddoppio della dimensione di input quadruplicherà al massimo il numero di passi, e O(logn) significa che il raddoppio della dimensione di input aumenterà il numero di passi al massimo di alcune costanti.

È uno strumento per dire quali algoritmi si adattano meglio, non quali sono assolutamente più veloci.


11

Innanzitutto, come hanno già spiegato altre risposte, , o per dirla in parole, una funzione è O ( 3 n ) se e solo se è O ( n ) n . Ora scegli C 1O(3n)=O(n)O(3n)O(n) . significa che esiste un punto N e un fattore C 3 tale che per tutti n N , f ( n ) C 33f=O(3n)NC3nNf(n)C33n : per tutti n N , f ( n ) C 1n , quindi f = O ( n ) . La prova del contrario è simile.C1=3C3nNf(n)C1nf=O(n)

Passiamo ora al motivo per cui questo è lo strumento giusto. Osservare che quando misuriamo la complessità di un algoritmo, non diamo un'unità. Non contiamo i secondi o le istruzioni della macchina: contiamo alcuni passaggi elementari non specificati che richiedono ciascuno un tempo limitato. Lo facciamo perché l'esecuzione dello stesso algoritmo su una macchina diversa cambierebbe il tempo necessario per istruzione - moltiplicare la frequenza di clock per e il tempo di esecuzione passa da f ( n ) a f ( n ) / 33f(n)f(n)/3. Se implementiamo lo stesso algoritmo in un linguaggio diverso o su un sistema diverso, il tempo impiegato da ogni passaggio elementare potrebbe essere diverso, ma anche questo è troppo dettaglio: non ci preoccupiamo quasi mai di tali differenze.

Quando ti preoccupi di tempi precisi, la complessità asintotica non è rilevante: la complessità asintotica ti dice cosa succede per dimensioni di input molto grandi, che possono essere o meno le dimensioni di input effettive con cui hai a che fare.


Si noti inoltre che Sedgewick nei suoi sostenitori di "Un'introduzione all'analisi degli algoritmi" usa o(g)come misura giusta, cioè ha come modo di descrivere i tempi di esecuzione (sempre in termini di operazioni elementari dominanti se lo si desidera, ma includendo il fattore costante che disturba OP). limng(n)T(n)=1
vonbrand,

2
@vonbrand Sedgewick lo dice davvero? La definizione abituale di è che lim n ( T (T(n)o(g(n) (cioè, la frazione al contrario e il limite è zero, non unità)limn(T(n)/g(n))=0
David Richerby,

3

Richiama la definizione di Big-O:

se esiste c >f(n)O(g(n)) tale che f ( n ) c g ( n ) per tutto n .c>0f(n)cg(n)n

In base a questa definizione, abbiamo che per ogni costante ddnO(n)d . Lo scopo della notazione è esattamente quello di semplificare le espressioni in questo modo. In effetti, 3 n cresce 3 volte più velocemente di n , ma sono entrambi lineari. Che ciò sia giustificato o meno, dipende dal contesto. Ma se accetti di usare la notazione O , allora per definizione vale.O3nnO


2
Questo fornisce una grande spiegazione di Big-O, ma nessuna spiegazione sul perché utilizziamo questa definizione.
jmite,

Come ho scritto, lo scopo è semplificare la nostra vita. Sia perché non conosciamo il costo esatto di un'operazione atomica, sia perché ci preoccupiamo della notazione asintotica. Non trovo il PERCHÉ un'interessante domanda matematica, ma piuttosto filosofica. Potremmo tecnicamente farne a meno. Renderebbe le cose davvero brutte e difficili con cui lavorare.
Shaull,

3

La notazione O grande è un mezzo privo di unità per misurare la variazione delle prestazioni, quindi impermeabile ai costi relativi delle primitive computazionali.

In poche parole: la notazione O grande è un tipo di misura relativa senza unità (al contrario della misurazione assoluta). Può solo misurare la variazione delle prestazioni, non le prestazioni assolute, per le quali le costanti contano molto. Il vantaggio è che ciò lo rende ampiamente indipendente dall'implementazione, consentendo un'analisi più semplice che può ignorare i costi relativi delle operazioni elementari, purché tali costi abbiano limiti superiori e inferiori fissi positivi. Ma la conseguenza è che i fattori costanti sono insignificanti . Tuttavia, anche per lo scopo previsto, l' analisi della complessità asintotica può essere messa in discussione per altri motivi e deve essere considerata con cura. Ad esempio, la dimensione di input non elaborata potrebbe non essere il parametro giusto da considerare.

Una prima osservazione è che la tua domanda non è affermata in modo abbastanza accurato. Quando trascuri la costante in 3 n , c'è effettivamente un "cambiamento di tre volte", ma entrambi variano alla stessa velocità e non puoi affermare che "[una] cosa varia 3 volte più rapidamente delle altre".33n

Un buon motivo per ignorare la costante nella notazione di Landau è che non abbiamo unità su cui contare. Quando qualcuno afferma che A vive due volte più lontano di te rispetto a B, questo ha significato indipendentemente da qualsiasi unità. Possiamo essere d'accordo anche se misurate le distanze in pollici mentre lo faccio in anni luce. Ma la misurazione della distanza assoluta richiede unità specifiche e la sua formulazione numerica dipende dall'unità scelta.

Il tempo effettivo impiegato da un algoritmo dipende dal tempo di esecuzione delle operazioni elementari, che dipende molto dalla macchina. Potresti contare il numero di operazioni elementari, ma non c'è motivo di credere che tutte prendano lo stesso tempo, ed è sempre possibile comporre più operazioni in una singola operazione, o al contrario scomporre un'operazione in operazioni più piccole, in modo che il numero delle operazioni non è veramente significativo, a meno che non si sia d'accordo su una macchina virtuale di riferimento. Essere indipendenti dal riferimento è un vantaggio.

Un'altra visione del vantaggio dell'approccio è che tutto ciò che ti interessa nell'analisi è contare il numero di operazioni elementari, purché il loro costo abbia un limite superiore e un limite inferiore positivo. Non devi preoccuparti dei costi individuali.

Tuttavia, il prezzo da pagare per quel vantaggio è che la valutazione del costo di calcolo viene fornita con unità non specificata e il tempo di calcolo, ad esempio, potrebbe essere di nanosecondi o millenni - non proviamo nemmeno a saperlo. In altre parole, i fattori costanti sono insignificanti, poiché la modifica delle unità è inseparabile dalla modifica del fattore costante e non vengono utilizzate unità di riferimento.

Come notato da Patrick87 , questo è sufficiente per capire come un algoritmo si ridimensiona rispetto alla dimensione dell'input, ma non fornirà una misura assoluta delle prestazioni, a meno di fare affidamento su un'unità di riferimento. Non è possibile eseguire una macchina astratta di riferimento comune quando si desidera effettivamente confrontare le prestazioni di algoritmi distinti, ma è più difficile assicurarsi che il confronto non sia distorto dai dettagli di realizzazione. Nella complessità asintotica, questo rischio è evitato perché si confronta l'algoritmo con se stesso.

Comunque, solo un programmatore ingenuo farebbe affidamento esclusivamente sulla complessità asintotica per scegliere un algoritmo. Esistono molti altri criteri, tra cui la costante indicibile e il costo effettivo delle operazioni elementari. Inoltre, la complessità del caso peggiore può essere un indicatore scarso, perché la fonte della complessità del caso peggiore può verificarsi raramente e su frammenti dell'input abbastanza piccoli da avere un impatto limitato. Ad esempio i parser generali per Tree Adjoining Grammars hanno una complessità teorica e sono abbastanza utilizzabili nella pratica. Il caso peggiore che conosco è l' inferenza di tipo polimorfico di Damas-Hindley-MilnerO(n6)algoritmo utilizzato per ML, che presenta una complessità esponenziale nel caso peggiore. Ma ciò non sembra disturbare gli utenti ML, né impedire la scrittura di programmi molto grandi in ML. C'è più della costante che conta. In realtà, l'analisi asintotica mette in relazione una misura del costo di un calcolo con una misura della complessità dell'input. Ma la dimensione grezza potrebbe non essere la misura giusta.

La complessità è come la decidibilità, può essere teoricamente negativa, ma può essere irrilevante per la maggior parte dello spazio dati ... a volte. L'analisi della complessità asintotica è uno strumento valido e ben progettato, con i suoi vantaggi e i suoi limiti, come tutti gli strumenti. Con o senza esplicitare la costante, che può essere insignificante, è necessario usare il giudizio.


2

Le altre risposte forniscono eccellenti spiegazioni del perché, secondo la definizione di Big-O, .O(n)=O(3n)

Per quanto riguarda il motivo per cui lo facciamo effettivamente in CS, è così che abbiamo una descrizione compatta dell'efficienza di un algoritmo. Ad esempio, potrebbe esserci un algoritmo che ha un'istruzione if, in cui un ramo esegue istruzioni e l'altro esegue 3 n istruzioni. Ciò significa che il numero esatto cambia per ogni input, anche per input della stessa lunghezza. Potremmo trovare un numero per ogni input, ma l'uso della notazione big-O ci dà una misura della complessità temporale che vale per TUTTI gli input.n3n

Questo è molto più utile per indovinare quanto velocemente sarà un algoritmo. Altrimenti, dovremmo considerare un'enorme funzione a tratti, che sarebbe molto difficile da capire.

L'altro motivo principale è che queste misurazioni sono indipendenti dall'hardware. Compilatori e architetture diverse cambieranno lo stesso codice in set di istruzioni molto diversi. Tuttavia, se sappiamo che il numero di istruzioni è lineare, esponenziale, ecc., Allora abbiamo un'idea della velocità degli algoritmi che tiene, indipendentemente dal computer reale su cui lo compiliamo o eseguiamo.


1

significa lim sup n f ( n )f(n)=O(g(n)).lim supnf(n)g(n)<+

Se questo è vero per , questo vale anche per g ( n ) = 3 n , e viceversa.g(n)=ng(n)=3n

Allo stesso modo, . Qui l'uguaglianza significa che f appartiene a LHS se appartiene a RHS. Il segno = qui è un grave abuso di notazione che odio personalmente, perché è confuso.O(n2)=O(.00005321n2+1000000000n+1046803)f=


2
=O(...)

fO(g)fO(nn2)f(x)=h(x)xx=n=

f(n)f

Di solito lo faccio anche io, sapendo che si tratta anche di un abuso della notazione;)
yo

-1

Lascia che ti spieghi semplicemente. Prendiamo n = 100000. Ora, che cos'è 3n? È 300000 ( Sì, è 3 volte di n ) Ma cos'è n ^ 2 ? 10000000000 . ( è 1 piega lakh di n ) .. Confronta n ^ 2 con n. 3 è trascurabile se confrontato con 1 lakh. quindi, possiamo rimuoverlo.

Pensa se n è qualche miliardo o trilione. In questo caso, ancora una volta confronteremo 3 con alcuni miliardi o trilioni. Ora sai perché possiamo trascurare 3.


2
Tre anni sono ancora più lunghi di un anno.
Yuval Filmus,

Non vedo come questo risponda alla domanda in alcun modo utile. Certamente non aggiunge nulla alle risposte esistenti, vecchie di anni.
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.