Tempo di computazione (Running Time) di programmi Misure del tempo: metodi principali 1. Benchmarking 2. Analisi Benchmarking: usato per confrontare programmi. Si cerca una collezione di input che sia rappresentativa dell’insieme dei possibili dati reali. Il giudizio di confronto viene espresso sugli input scelti. Es. • • • per algoritmi di sorting si può scegliere la collezione: prime 20 cifre p codici postali italiani numeri telefonici di Roma Tempo di computazione (Running Time) di programmi ANALISI: analizza il r.t. di un dato programma Si raggruppano input per dimensione (es. ordinamento: dimensione= numero elementi da ordinare, sisteme di n equazioni in n incognite: dimensione=n) Running time: funzione T(n), con n=dimensione input, che rappresenta il numero di “unità di tempo” usate dall’algoritmo Unità di tempo varia: es. numero di istruzioni semplici in linguaggio usato (C). Tempo effettivo dipende da vari paramentri: velocità del processore usato, compilatore,…. Tempo di computazione (Running Time) di programmi Worst case (caso peggiore): su diversi input di stessa dimensione n si possono avere r.t. differenti T(n)=worst case r.t. = max tempo su qualsiasi input di dimentsione n Es. cerca min A[0..n-1] (dimensione=n) 1. small=0; 2. for(j=1; j<n; j++) 3. if(A[j]<A[small]) 4. small=j; | | | | | Linea 1. 2. 3. 4. | | | | | Numero operazioni 1 1 + n + (n-1) =2n n-1 n-1 (worst case) TOTALE: 1+2n+2(n-1)=4n-1 T(n)=4n-1 Tempo di computazione (Running Time) di programmi Confronto di r.t. Dato un problema consideriamo 2 algoritmi A e B con r.t. T’(n) e T’’(n) T’(n)=100n T’’(n)=2n2 T’’(n) T’(n) n n<50, T’’(n) < T’(n) n>50, T’’(n) > T’(n) n=100, T’’(n) = 2 T’(n) n=1000, T’’(n) = 20 T’(n) Tempo di computazione (Running Time) di programmi T’(n)=100n T’’(n)=2n2 Unità di tempo= 1ms (millisec) 1000 operazioni/sec sec (1000ms) | max n per A | (100n=1000*sec) 1 10 100 1000 | | | | 10 100 1000 10000 | max n per B | | | | | | | | | | ( 2n2=1000*sec) 22 70 223 707 | Se calcolatori diventano 100 volte più veloci (unità di tempo =1/100 di ms 100.000 operazioni/sec) In 10 sec A passa da n=100 ad n=10000 (*100) B passa da n=70 ad n=707 (*10) Notazione O-grande e r.t. approssimato Dato un programma ed un input r.t. dipende ancora da 1. Calcolatore usato (velocità di esecuzione istruzioni) 2. Compilatore (numero istruzioni macchina/istruzione C) Quindi non ha senso parlare di tempo in sec per analizzare un algoritmo. Per nascondere effetti di 1. e 2. si usa la notazione O-grande (big-Oh) che ignora le costanti Es. 4m-1=O(m) (ignorando la costante moltiplicativa 4 e quella additiva 1) Notazione O-grande e r.t. approssimato Un r.t. T(n) si assume essere definito solo per n>0 e che T(n)>0 per ogni n. Definizione Dati il r.t. T(n) ed una funzione f(n), definita per ogni intero n>0, T(n)=O(f(n)) Esistono n0>0 e c>0 tali che per ogni n>n0 risulta T(n)<cf(n) N.B. Notazione Asintotica (vale per n ‘’grande’’) Notazione O-grande e r.t. approssimato Definizione Dati il r.t. T(n) ed una funzione f(n), definita per ogni intero n>0, T(n)=O(f(n)) Esistono n0>0 e c>0 tali che per ogni n>n0 risulta T(n)<cf(n) Es. Dato T(0)=0 e T(n)=(n+1)*(n+2), n>0 mostriamo che T(n)= O(n2). (cioè f(n)=n2) Prendiamo n0=1, c=6: T(n) =(n+1)(n+2)=n2+3n+2 <n2+3n2+2n2 (per n>1, n0=1<n<n2) =6n2=c n2= c f(n) Notazione O-grande e r.t. approssimato Costanti non hanno valore T(n)=O(d T(n)), per ogni costante d Infatti: siano n0=0, c=1/d. Si ha T(n)=(1/d) d T(n)= c (d T(n)) Notazione O-grande e r.t. approssimato Low-order terms non hanno valore Dato il polinomio T(n)=aknk+ak-1nk-1+…+a1n+a0, con ak>0 risulta T(n)=O(nk) Prova: Siano n0 1, k a c i 0 , ai 0 i k Si ha (nota ai c per ogni 0 i k ) T (n) ai n i i 0 k k a n i k i a n i i 0 , ai 0 (essendo 1 n) i 0 , ai 0 nk k k k a n c cn . i i 0 , ai 0 Notazione O-grande e r.t. approssimato Low-order terms non hanno valore Dato il polinomio T(n)=aknk+ak-1nk-1+…+a1n+a0, con ak>0 risulta T(n)=O(nk) Es. T(n) 10 n 5 3n 3 - 2n 2 1 n0 1, c k a i 0 , ai 0 i 10 3 1 14 T(n) 10 n 5 3n 3 - 2n 2 1 10 n 5 3n 3 1 10 n 5 3n 5 n 5 14n 5 cn 5 Notazione O-grande e r.t. approssimato La funzione g(n) cresce più rapidament e di h(n) se h( n) lim 0 n g ( n ) Tasso di crescita Ha valore solo il termine che cresce più rapidamente. Se g(n) cresce più rap. di h(n) g(n)+h(n)=O(g(n)) Es. T(n)=2n+n3=O(2n), infatti n3 lim n 0 n 2 Verificarlo in modo diretto esibendo le costanti n0 e c Notazione O-grande e r.t. approssimato Transitività Se f(n)=O(g(n)) e g(n)=O(h(n)) allora f(n)=O(h(n)) f(n)=O(g(n)) Esistono c’, n’ tali che f(n) < c’ g(n) per ogni n>n’ g(n)=O(h(n)) Esistono c’’, n’’ tali che g(n) < c’’ h(n) per ogni n>n’’ Quindi, prendiamo n0=max { n’,n’’ } e c=c’c’’ Per n>n0 f(n) < c’ g(n) < c’ (c’’ h(n)) = c h(n) Notazione O-grande e r.t. approssimato Si vuole come O-grande la funzione con il minimo tasso di crescita!!! Es. f(n)=12n +3, si ha f(n)=O(n) risulta anche f(n)=O(n2), f(n)=O(n3), f(n)=O(2n), …. ma non è quello che vogliamo. Notazione O-grande e r.t. approssimato Esercizio.Mostrare che g(n)+f(n)=O(max{f(n),g(n)}) Esercizio.Mostrare che se T(n)=O(f(n)) e S(n)=O(g(n)) allora T(n)S(n)=O(f(n)g(n)) Running Time di programmi Trova f(n) tale che T(n)=O(f(n)) Istruzioni semplici (assegnamento, confronto,…) tempo costante O(1) Cicli for: for (i=1,i<=n,i++) I 1. se I=operazione semplice risulta O(n) 2. Se I ha r.t. O(f(n)) risulta O(nf(n)) es. for(i=1,i<=n,i++) A[i]=1 T(n)=O(n) for(i=1,i<=n,i++) for(j=1,j<=n,i++) A[i]=A[i]+A[j] T(n)=O(n*n) =O(n2) Running Time di programmi If (C) I else I’: (normalmente C è O(1)) 1. se I,I’ sono istruzioni semplici O(1) 2. se I ha r.t. O(f(n)) e I’ ha r.t. O(g(n)) O(max (f(n), g(n)) es. if (A[0]=0) for(i=1,i<=n,i++) A[i]=1; else for(i=1,i<=n,i++) for(j=1,j<=n,i++) A[i]=A[i]+A[j] T(n)=O(max (n, n2)) =O(n2) Running Time di programmi Cicli while e do while: simili al ciclo for (non conosciamo esplicitamente il numero di iterazioni) es. Dato un array A di n elementi i=0; while (x<>A[i] && i<n) i=i+1; (caso peggiore: n iterazioni) T(n)=nO(1)=O(n) Running Time di programmi Sequenze di istruzioni: si devono sommare i tempi delle singole istruzioni. Si usa la regola della somma. Date {I1; I2; . . . Im;} con O(f1) O(f2) . . . O(fm) Risulta O(f1(n)) + O(f2(n))+…+ O(fm(n))= O(fi(n)) fj(n)=O(fi(n)) per ogni j diverso da i. Running Time di programmi Chiamate a funzioni: si deve sommare il tempo della funzione chiamata. (se A chiama B: si calcola il r.t. di B e si somma al r.t. delle altre istruzioni di A) Chiamate ricorsive: determiniamo T(n) in modo induttivo 1. Tempo di una chiamata che non usa ricorsione = t (=O(1)) 2. Si esprime T(n) in termini del tempo T(n’) della chiamata ricorsiva Running Time di programmi Chiamate ricorsive: determiniamo T(n) in modo induttivo 1. Tempo di una chiamata che non usa ricorsione=t (=O(1)) 2. Si esprime T(n) in termini del tempo T(n’) della chiamata ricorsiva Es. int fact(int n) { if (n<=1) return 1; else return n*fact(n-1)} T(1)=t T(n)=T(n-1)+c Running Time di programmi Es. int fact(int n) { if (n<=1) return 1; else return n*fact(n-1)} T(1)=t T(n)=c+ T(n-1) Vogliamo il valore di T(n) (non dipendente da T(n’)) Abbiamo T(n)=c+ T(n-1) =c+ c+ T(n-2)= 2c +T(n-2) Running Time di programmi Es. int fact(int n) { if (n<=1) return 1; else return n*fact(n-1)} T(1)=t T(n)=c+ T(n-1) Abbiamo T(n)=c+T(n-1) =c+ c+ T(n-2)= 2c +T(n-2) =2c +c +T(n-3)=3c +T(n-3) Running Time di programmi Es. int fact(int n) { if (n<=1) return 1; else return n*fact(n-1)} T(1)=t T(n)=c+ T(n-1) Abbiamo T(n)=c+T(n-1) =c+ c+ T(n-2)= 2c +T(n-2) =2c +c +T(n-3)=3c +T(n-3) … =ic +T(n-i) (per i=n-1) =(n-1)c+T(1) =(n-1)c+t= O(n) Running Time di programmi Esercizio. Dimostrare per induzione su n che la relazione di ricorrenza T(1)=t T(n)=c+ T(n-1) ha come soluzione T(n)=(n-1)c + t Base n=1. T(1)=t=(1-1)c+t. OK. Passo. Sia n> 1. Assumiamo T(n)=(n-1)c + t. Consideriamo T(n+1) T(n+1)=c + T(n) (per definizione) =c + (n-1)c + t (per i.i.) = nc +t Running Time di programmi Esercizio. Considerare la relazione di ricorrenza T(0)=T(1)= 1 T(n)=2 T(n-2) 1. Determinare T(2), T(3), T(4), T(5): T(2)=2, T(3)=2, T(4)=4, T(5)=4 1. Determinare T(n) in termini di T(n-4): T(n)=4 T(n-4) 2. Determinare T(n) in termini di T(n-6): T(n)=8 T(n-6) 3. 4. se se Determinare T(n) in termini di T(n-2i): T(n)=2i T(n-2i) Determinare T(n): n pari, i=n/2, T(n-2i)=T(0) T(n)=2n/2T(0)=2n/2 n disp., i=(n-1)/2, T(n-2i)=T(1) T(n)=2(n-1)/2T(1) =2(n-1)/2 Soluzioni Relazioni di ricorrenza 1. T(1)=a T(n)= b+T(n-1), n>1 2. T(k)=a T(n)=T(n-1)+g(n) T(n)=(n-1)b+a T(n)=a + g(k+1)+…+g(n) T(n) = g(n)+T(n-1) = g(n)+g(n-1)+T(n-2)=… … = g(n)+g(n-1)+…+g(k+1)+T(k) 3. T(1)=1 T(n)=T(n-1)+n (g(i)=i) T(n)=1 + 2+…+n=n(n+1)/2 Soluzioni Relazioni di ricorrenza 4. T(1)=a T(n)=2T(n/2)+g(n) T ( n) log2 n 1 n ) an 2 g ( 2j j j 0 T (n) g (n) 2T (n / 2) g (n) 2 g (n / 2) 4T (n / 4) ... i 1 i 1 g (n) 2 g (n / 2) ... 2 T (n / 2 ) 2 T (n / 2 ) i i 2 g( i j 0 log2 n 1 n i 1 2i ) 2 T (n / 2 ) [Per i log n-1, 2 j n ) an 2 g ( 2j j 0 i 1 i i 1 n] Soluzioni Relazioni di ricorrenza 4. T(1)=a T(n)=2T(n/2)+g T ( n) log2 n 1 j 2 g an j 0 g log2 n 1 2 j an j 0 g 2log2 n an gn an (a g )n Soluzioni Relazioni di ricorrenza 4. T(1)=a T(n)=2T(n/2)+n T ( n) log2 n 1 2 (n / 2 ) an j j 0 log2 n 1 n an j 0 n(log 2 n) an O(n(log 2 n)) j