O-grande
# O-grande

La notazione matematica O-grande è utilizzata per descrivere il comportamento asintotico delle funzioni. Il suo obiettivo è quello di caratterizzare il comportamento di una funzione per argomenti elevati in modo semplice ma rigoroso, al fine di poter confrontare il comportamento di più funzioni fra loro. Più precisamente, è usata per descrivere un limite asintotico superiore per la magnitudine di una funzione rispetto ad un'altra, che solitamente ha una forma più semplice. Ha due aree principali di applicazione: in matematica, è solitamente usata per caratterizzare il resto del troncamento di una serie infinita, in particolare di una serie asintotica, mentre in informatica risulta utile nell'analisi della complessità degli algoritmi.

Nell'uso informale, la notazione O è comunemente impiegata per descrivere un limite asintotico stretto, ma i limiti asintotici stretti sono più formalmente e propriamente denotati dalla lettera Θ (Theta grande).

## Storia

Questa notazione è stata introdotta per la prima volta dal teorico dei numeri tedesco Paul Bachmann nel 1894, nel secondo volume del libro Analytische Zahlentheorie ("Teoria analitica dei numeri"), il cui primo volume (che ancora non conteneva la notazione O-grande) uscì nel 1892. La notazione divenne popolare grazie al lavoro di un altro teorico dei numeri tedesco, Edmund Landau, ragione per cui oggi è alcune volte chiamata simbolo di Landau. La O-grande, che sta per "dell'ordine di", era in origine una omicron maiuscola; oggi è anche usata la lettera maiuscola O, ma mai la cifra zero.

## Uso

Ci sono due utilizzi per questa notazione, che sono formalmente vicini ma chiaramente differenti: asintoti infiniti e asintoti infinitesimali. Questa distinzione è solo applicativa e non di principio. Tuttavia, la definizione formale di "O-grande" è la stessa in entrambi i casi, con la sola differenza del valore a cui tende il limite della funzione a cui si intende applicare la "O-grande".

### Comportamento asintotico all'infinito

La notazione O-grande risulta utile nell'analisi dell'efficienza degli algoritmi. Per esempio, supponiamo di aver ricavato che il tempo (o il numero di passi) che sono necessari a completare un problema di dimensione n sia T(n) = 4n² - 2n + 2.

Per grandi valori di n, il termine n² diventerà preponderante rispetto agli altri, che potranno non essere considerati; per esempio, per n pari a 500, il termine 4n² sarà pari a 1000 volte il termine 2n, e l'ignorare quest'ultimo sarà, nella maggior parte dei casi, un'approssimazione tollerabile.

Inoltre, anche i coefficienti diventano irrilevanti se compariamo l'espressione precedente ad una di ordine superiore, come una contenente un termine n³ oppure $2^n.$ Se anche T(n) = 1.000.000n², se U(n) = n³, U(n) sarà comunque maggiore di T(n) per n maggiore di 1.000.000 (T(1.000.000) = 1.000.000³ = U(1.000.000)).

La notazione O-grande riesce ad esprimere proprio questo concetto: scriveremo

    $T(n)\in O(n^{2})$

e diremo che l'algoritmo ha una complessità in tempo dell'ordine di $n^2.$

### O-grande e infinitesimi

La notazione O-grande può anche essere usata per descrivere il termine di errore in una approssimazione di una funzione. Per esempio,

    $e^{x}=1+x+{\frac {x^{2}}{2}}+O(x^{3})\qquad {\text{per }}x\to 0$

esprime il fatto che la differenza $e^{x}-\left(1+x+{\frac {x^{2}}{2}}\right)$ è più piccola in valore assoluto di qualche costante positiva moltiplicata per $|x|^{3}$ quando $x$ è sufficientemente vicino a 0.

## Definizione formale

Si supponga che $f(x)$ e $g(x)$ siano due funzioni definite su qualche sottoinsieme dei numeri reali. Diciamo che

    $f(x)\in O(g(x))$ per $x\to \infty$

se e solo se

    $\exists x_{0}\in \mathbb {R} ,c>0:|f(x)|\leq c|g(x)|,\quad \forall x>x_{0}.$

La notazione può anche essere usata per descrivere il comportamento di $f$ nell'intorno di un numero reale $a$: diciamo che

    $f(x)\in O(g(x))$ per $x\to a$

se e solo se

    $\exists \delta >0\;\exists c>0:|f(x)|\leq c|g(x)|{\text{ per }}|x-a|<\delta .$

Se $g(x)$ è non nulla per valori di $x$ sufficientemente vicini ad $a$, entrambe queste definizioni possono essere unificate utilizzando il limite superiore:

    $f(x)\in O(g(x)){\text{ per }}x\to a$

se e solo se

    $\limsup _{x\to a}\left|{\frac {f(x)}{g(x)}}\right|<\infty .$

Nella matematica, i comportamenti asintotici tendenti a $\infty$ e ad $a$ sono entrambi considerati. Nella teoria della complessità computazionale, sono usati solamente quelli tendenti ad infinito; inoltre, sono considerate solo funzioni sempre positive, per cui il valore assoluto può essere omesso.

## Esempio

Si considerino i due polinomi

    $f(x)=6x^{4}-2x^{3}+5,$
    $g(x)=x^{4}.$

Allora

    $f(x)\in O(g(x)){\text{ per }}x\rightarrow +\infty .$

Dimostrazione:

Mostriamo che $|f(x)|\leq C|g(x)|$ per ogni $x>1,$ dove $C$ è una costante che determineremo più avanti.

Supponiamo $x>1$. Dalla disuguaglianza triangolare si ottiene che

    $|f(x)|=|6x^{4}-2x^{3}+5|\leq |6x^{4}|+|-2x^{3}|+|5|=6x^{4}+2x^{3}+5.$

Nell'ultimo passaggio, la sostituzione $|-2x^{3}|=2x^{3}$ è giustificata dal fatto che $x>1>0.$

Osserviamo che per $x>1$ valgono le disuguaglianze $1<x^{3}<x^{4}$ e $5<5x^{4}$. Da queste otteniamo che

    $|f(x)|\leq 6x^{4}+2x^{4}+5x^{4}=13x^{4},$

e quindi

    $|f(x)|\leq 13|g(x)|.$

Prendendo $C=13$ si ottiene la tesi.

## Questioni di notazione

L'affermazione "$f(x)$ è dell'ordine di $g(x)$" è spesso scritta come "$f(x)=O(g(x))$". Questo è un abuso di notazione: non stiamo realmente affermando l'uguaglianza fra due funzioni, in quanto $O(g(x))$ non rappresenta una singola funzione ma una classe di funzioni. Sarebbe più corretto scrivere "$f(x)\in O(g(x))$", come visto in precedenza.

A volte si scrive anche "$O(f(x))=O(g(x))$" per indicare che $O(f(x))\subseteq O(g(x))$. Anche questo è un abuso di notazione: quella indicata nella prima espressione non è una vera uguaglianza, in quanto non è simmetrica. Per esempio, con questa notazione abbiamo

    $O(x)=O(x^{2})\quad {\text{ per }}x\rightarrow +\infty ,$

ma

    $O(x^{2})\neq O(x)\quad {\text{ per }}x\rightarrow +\infty ,$

in quanto la funzione $f(x)=x^{2}$ è $O(x^{2})$ ma non $O(x)$ per $x$ che tende a infinito.

In un uso più complesso, $O(\cdot )$ può apparire in posti diversi di una equazione, anche più volte in ciascun membro. Per esempio, le seguenti affermazioni sono vere per $n\to \infty$

    $(n+1)^{2}=n^{2}+O(n)$
    $(n+O(n^{1/2}))(n+O(\log \,n))^{2}=n^{3}+O(n^{5/2})$
    $n^{O(1)}=O(e^{n}).$

Il significato di queste affermazioni è il seguente: per una qualsiasi funzione che soddisfa ciascuno degli O-grande del membro sinistro, esiste qualche funzione che soddisfa ciascuno degli O-grande presenti nel membro destro, in maniera che sostituendo queste funzioni nell'equazione rende i membri uguali. Per esempio, la terza equazione significa: "Per ogni funzione f(n)∈O(1)" c'è una qualche funzione $g(n)∈O(e^n)$ tale che $n^{f(n)}=g(n)."$ In termini di insiemi, il significato è che la classe di funzioni rappresentata dal membro sinistro è un sottoinsieme della classe di funzioni rappresentata dal membro destro.

## Ordini di funzioni fra i più comuni

Segue una lista di classi di funzioni comunemente incontrate nell'analisi di algoritmi. Tutte queste vanno considerate per $n$ che tende all'infinito. Le funzioni sono elencate per magnitudine crescente (in termini insiemistici, ogni classe di funzioni elencata è un sovrainsieme delle precedenti). Nel seguito, $c$ indica una costante arbitraria.

| Notazione | Nome | Esempio |
| - | - | - |
| $O(1)$ | costante | Determinare se un numero è pari o dispari |
| $O(\log ^{*}(n))$ | logaritmica iterata | L'algoritmo di ricerca di Hopcroft e Ullman su un insieme disgiunto (un tipo di struttura dati) |
| $O(\log(n))$ | logaritmica | Cercare un elemento in una lista ordinata tramite l'algoritmo della ricerca binaria |
| $O((\log(n))^{c})$ | polilogaritmica | Decidere se $n$ è primo tramite il test AKS di primalità |
| $O(n)$ | lineare | Cercare un elemento in una lista non ordinata |
| $O(n\log(n))$ | loglineare | Ordinare una lista tramite heap sort |
| $O(n^{2})$ | quadratica | Ordinare una lista tramite insertion sort |
| $O(n^{c})$ | polinomiale | Cercare il cammino più breve su di un grafo orientato e pesato tramite l'algoritmo di Floyd-Warshall |
| $O(c^{n})$ | esponenziale, alcune volte chiamata geometrica | Trovare la soluzione esatta al problema del commesso viaggiatore (sotto l'ipotesi che P ≠ NP) |
| $O(n!)$ | fattoriale | Un qualsiasi problema NP-completo tramite un algoritmo che cerca la soluzione con un metodo forza bruta |

## Altre notazioni associate

O-grande è la notazione asintotica più comunemente usata per confrontare le funzioni. Insieme ad altre notazioni correlate forma la famiglia delle notazioni di Bachmann – Landau.

### Notazione o-piccolo

Intuitivamente, l'affermazione "$f(x)$ è $o(g(x))$" (letto "$f(x)$ è o-piccolo di $g(x)$") significa che $g(x)$ cresce molto più velocemente di $f(x).$ Sia $f$ una funzione a valori reali o complessi e $g$ una funzione a valori reali, entrambe definite su un sottoinsieme illimitato dei numeri reali positivi, in modo che $g(x)$ sia strettamente positiva per tutti i valori abbastanza grandi di $x.$ Scriviamo

    $f(x)=o(g(x)){\text{ per }}x\to \infty$

se per ogni $\varepsilon$ reale positivo esiste $N$ tale che

    $|f(x)|\leq \varepsilon g(x),\quad {\text{ per ogni }}x\geq N.$

Ad esempio, otteniamo

    $2x=o(x^{2})$

e

    $1/x=o(1).$

La differenza tra la precedente definizione per la notazione O-grande e questa definizione di o-piccolo, è che mentre la prima deve essere vera per almeno una costante $M,$ la seconda deve valere per ogni costante positiva $\varepsilon ,$ per quanto piccola. In questo modo, la notazione o-piccolo è "più forte" della corrispondente notazione O-grande: ogni funzione che è o-piccolo di $g$ è anche O-grande di $g,$ ma non tutte le funzioni che sono O-grande di $g$ sono o-piccolo di $g.$ Ad esempio, $2x^{2}=O(x^{2})$ ma $2x^{2}\neq o(x^{2}).$

Se $g(x)$ è diverso da zero, o almeno diventa diverso da zero da un certo punto in poi, la relazione $f(x)=o(g(x))$ è equivalente a

    $\lim _{x\to +\infty }{\frac {f(x)}{g(x)}}=0,$

che è il modo in cui Landau ha originariamente definito la notazione o-piccolo.

La notazione o-piccolo soddisfa le seguenti proprietà:

* se $c$ è una costante diversa da zero e $f=o(g),$ allora $c\cdot f=o(g);$
* se $f=o(F)$ e $g=o(G),$ allora $f\cdot g=o(F\cdot G);$
* se $f=o(g)$ e $g=o(h),$ allora $f=o(h),$ cioè $o(o(h))=o(h).$
