1 / 100

RICORSIONE & ITERAZIONE

m, se m=n. MCD(m, n) =. MCD(m-n, n), se m>n. MCD(m, n-m), se m<n. RICORSIONE & ITERAZIONE. Riconsideriamo l’esempio del Massimo Comun Divisore visto tempo addietro:. RICORSIONE & ITERAZIONE. Questo esempio era stato trasposto nella funzione seguente: int mcd(int m, int n){

reuben
Download Presentation

RICORSIONE & ITERAZIONE

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. m, se m=n MCD(m, n) = MCD(m-n, n), se m>n MCD(m, n-m), se m<n RICORSIONE & ITERAZIONE Riconsideriamo l’esempio del Massimo Comun Divisore visto tempo addietro:

  2. RICORSIONE & ITERAZIONE Questo esempio era stato trasposto nella funzione seguente: int mcd(int m, int n){ return (m==n) : m ? (m>n) ? mcd(m-n, n) : mcd(m, n-m); } L’esempio era particolare perché il risultato veniva sintetizzato in avanti, anziché all’in-dietro come nei processi ricorsivi.

  3. RICORSIONE & ITERAZIONE • Ogni processo computazionale che computi“in avanti”, per accumulo, costituisce una ITERAZIONEossia è unprocesso computazionale iterativo. • Ogni soluzione sintatticamente ricorsivache dia luogo a unprocesso computazio-nale iterativo costituisce una ricorsione solo apparente:una ricorsione tail.

  4. RICORSIONE & ITERAZIONE La caratteristica fondamentale di un processo computazionale ITERATIVO è che a ogni passo è disponibile un risultato parziale • dopo k passi, si ha a disposizione il risultato parziale relativo al caso k • questo non è vero nei processi computazionali ricorsivi,in cui nulla è disponibile finché non si è disgregato il problema fino al caso elementare.

  5. IL RAGIONAMENTO ITERATIVO • Si basa sulla disponibilità di una variabile, detta accumulatore, destinata a esprimere in ogni istante la soluzione corrente • Si imposta identificando quell’operazione di modifica dell’accumulatoreche lo porta a esprimere, dal valore relativo al passo k, il valore relativo al passo k+1.

  6. ESEMPIO: CALCOLO DEL FATTORIALE Definizione: n! = 1 * 2 * 3 *… * n Detto vk = 1 * 2 * 3 *… * k: 1! = v1 = 1 (k+1)! = vk+1 = (k+1) * vkper k1 n! = vn per k=n

  7. ESEMPIO: CALCOLO DEL FATTORIALE int fact(int n){ return factIter(n,1,1); } int factIter(int n, int v, int k){ return (k==n) ? v : factIter(n, (k+1)*v, k+1); }

  8. INVARIANTI Un invariante di programmaè una relazione sempre vera in un dato punto del program- ma. Esempio: double power(double b, int k){ return (k<=0) ? 1 : powerIt(b,k,b,1); } Invariante di programma:è sempre vero che qui k>0

  9. INVARIANTI DI CICLO Un invariante di cicloè una relazione sem- pre vera, in un dato punto del programma, a ogni iterazione. • Identificare un invariante di ciclo è una forma di progetto. • Invarianti diversi suggeriscono di norma algoritmi diversi, che quasi sempre hanno diversa efficienza.

  10. PROBLEMA: CALCOLO DI bk Un approccio iterativo Posto bk = vk, si può scrivere: b0= v0= 1 per i=0 bi = vi= b * bi-1 = b * vi-1per i>0 in particolare: bk = vk per i=k Un possibile invariante:bk = vi * bk-i

  11. PROBLEMA: CALCOLO DI bk Perché bk = bk-i *vi è un invariante? Al generico passo 0<i<k, bk = vi* bk-i Moltiplicando e dividendo per b: bk = (vi*b) *bk-i-1 =vi+1* bk-(i+1) che è l’invariante al passo (i+1)-esimo. In particolare: • per i=0, bk = v0* bk = bkpurché v0 =1 • per i=k, bk = vk* b0 = vk condizione iniziale

  12. PROBLEMA: CALCOLO DI bk Come usarlo per progettare l’algoritmo? • inizialmente, v = v0 =1 • a ogni passo si deve trasformare l’invariantebk = vi* bk-inella formabk =vi+1* bk-(i+1) che deve assumere al passo successivo • ciò si ottiene ponendo, a ogni passo v’ = b * v i’ = i + 1

  13. CALCOLO DI bk : L’INVARIANTE double powerIt(double b, int k, double v, int i){ return (i==k) ? v :powerIt(b,k,v*b,i+1); } double power(double b, int k){ return (k==0) ? 1 : powerIt(b,k,1,0); } i’ = i+1 V’ = Vi+1= Vi* b V0=1 i=0

  14. PROGETTARE bk PER INVARIANTI Partendo da relazioni diverse si ottengono approcci diversi, con diversa efficienza. Un diverso invariante: • k=0  b0 = 1 • k>0 k pari bk = (b2) k/2 k dispari bk = b * bk-1 b*b: non richiede disaper fare potenze richiede di saper fare un prodotto

  15. PROGETTARE bk PER INVARIANTI Come usarlo per progettare l’algoritmo? • a ogni passo si deve riscriverebkin una delle due forme date • ciò si ottiene ponendo, a ogni passo • se k è pari: b’ = b * b k’ = k/2 • se k è dispari: b’ = b k’ = k-1e moltiplicando per b richiede una operazione dopo la fasedi modifica di b e k  soluzione ricorsiva

  16. PROGETTARE bk PER INVARIANTI boolean odd(int n){return n%2==1; } double pow(double b, int k){ return (k==0) ? 1 : odd(k) ? pow(b, k-1)* b: pow(b*b, k/2); } ricorsionenon-tail (Complessità dell’ordine di log2 k)

  17. PROGETTARE bk PER INVARIANTI UN APPROCCIO ITERATIVO Un ulteriore invariante:bk = t * vn • k=0  n=0, t=1 bk = t * v0 = 1 • k>0 • se n è pari: bk = t * (v2) n/2 • se n è dispari: bk = t * v * vn-1

  18. PROGETTARE bk PER INVARIANTI Progetto dell’algoritmo: • a ogni passo si deve trasformare l’invariantebk = t * vnin una delle due forme date • ciò si ottiene ponendo: • se n è pari  n’ = n/2,t’ = t,v’ = v2 • se n è dispari  n’ = n-1,t’ = t*v,v’ = v Interessante: b e k in realtà non si usano!

  19. PROGETTARE bk PER INVARIANTI boolean odd(int n){return n%2==1;} double powIt(double b, int k, double t, double v, int n){ return (n==0) ? t : odd(n) ? powIt(b,k,t*v,v,n-1) : powIt(b,k,t,v*v,n/2); } Come previsto, b e knon servono!Quindi li possiamo togliere…!!

  20. PROGETTARE bk PER INVARIANTI boolean odd(int n){return n%2==1;} double powIt(double t, double v, int n){ return (n==0) ? t : odd(n) ? powIt(t*v, v, n-1) : powIt(t, v*v, n/2); } double power(double b, int k){ return (k==0) ? 1 : powIt(1,b,k); }

  21. ESERCIZIO: MOLTIPLICAZIONE Obiettivo: calcolare p = x* y Sfruttiamo l’invariante: y = Q * B + R dove • B è un intero positivo • Q (quoziente) = y/B • R (resto) = y%B

  22. ESERCIZIO: MOLTIPLICAZIONE Obiettivo: calcolare p = x* y Sostituendo: p = x * y= x*(Q * B + R)= = x * (B * (y/B))+x*(y%B) Caso particolare: y=0 p = x * y= x*0= 0

  23. ESERCIZIO: MOLTIPLICAZIONE Approccio ricorsivo: si applica direttamente la relazione trovatap = x*B * (y/B) ) + x*(y%B) Ad esempio, scegliendo B=2: int MulNatR(int x, int y){ return (y==0) ? 0 : MulNatR(x*2, y/2) + x*(y%2); } Occorre fare un’operazione dopo la chiamata ricorsiva  ricorsione non-tail

  24. ESERCIZIO: MOLTIPLICAZIONE Approccio ricorsivo: si applica direttamente la relazione trovatap = x*B * (y/B) ) + x*(y%B) Ad esempio, scegliendo B=2: int MulNatR(int x, int y){ return (y==0) ? 0 : MulNatR(x*2, y/2) + x*(y%2); } Operazione primitiva che suppo-niamo di saper già fare (è una moltiplicazione per 0 o per 1) Operazioni primitive che supponiamo di sa-per già fare (moltiplicazione/divisione per 2)

  25. ESERCIZIO: MOLTIPLICAZIONE Verso un approccio iterativo Cerchiamo un invariante di ciclo p = x * y + z Ponendo y=Q*B+Re trasformando: p = (x*B) * Q + (x*R + z) = x’ * y’ + z’ dove si è posto y’ = Q = y/B,x’ = x*B,z’ = z + x*R Caso particolare: y=0  p = z

  26. ESERCIZIO: MOLTIPLICAZIONE Invariante di ciclo: p = x * y + z Trasformazione: p = x’ * y’ + z’ y’ = Q = y/B,x’ = x*B,z’ = z + x*R int MulNatIt(int x, int y, int z){ return(y==0) ? z : MulNatIt(x*2, y/2, z+x*(y%2)); } Operazioni primitive: supponiamo di saper giàmoltiplicare, dividere e modulare per 2.

  27. ESERCIZIO: MOLTIPLICAZIONE Perché supponiamo di saper già moltiplicare, e dividere per 2 (trovando anche il resto) ? Perché l’elaboratore è intrinsecamente capace di farlonella propria ALU: • moltiplicazione per 2 = shift a sinistra (<<) • divisione per 2 = shift a destra (>>) • moltiplicazione per (y%2) = 0, se y è pari (y%2 vale 0) y, se y dispari (y%2 vale 1)

  28. ESERCIZIO: MOLTIPLICAZIONE Il codice finale che ne risulta: int MulNatIt(int x, int y, int z){ return (y==0) ? z : odd(y): MulNatIt(x<<1, y>>1, z+x) : MulNatIt(x<<1, y>>1, z); } boolean odd(int n){return n%2==1;} y%2 = 1 x/2 y/2 y%2 = 0

  29. UNA RIFLESSIONE DI FONDO • L’impostazione funzionale è sempre costruttiva. Ma si può sempre solo creare? • Perché creare una versione nuova di un accumulatore ad ogni passo, quando l’elaboratore di Von Neumann permette la modificadel contenuto di una cella di memoria?

  30. UNA PROPOSTA • È possibile riusare una stessa area datisenza bisogno di crearne una nuova ad ogni passo computazionale? • Ci sono controindicazioni?

  31. VARIABILI NEI LINGUAGGI IMPERATIVI Una variabilein un linguaggio imperativo • non è solo un sinonimo per un datocome in matematica • è un’astrazione della cella di memoria • associata a due diverse informazioni: • il contenuto (R-value) • l’indirizzo a cui si trova (L-value) 3.22 a x

  32. ESPRESSIONI CON EFFETTI COLLATERALI • Le espressioni che contengono variabili, oltre a denotare un valore,possono a volte comportare effetti collaterali sulle variabili coinvolte. • Un effetto collaterale è una modifica del valore della variabile (R-value) causato da particolari operatori: • operatore di assegnamento • operatori di incremento e decremento

  33. ASSEGNAMENTO • L’assegnamento è un particolare tipo di espressione • come tale denota comunque un valore!! con un effetto collaterale:quello di cambiare il valore della variabile. • Sintassi variabile = espressione • Esempi di espressioni di assegnamento: j = 0 k = j + 1

  34. ASSEGNAMENTO L’espressione di assegnamento variabile = espressione • denota il valore dell’ espressione • ma cambia anche il valore della variabile: il nuovo valore della variabile è quello denotato dalla espressione.

  35. ESEMPIO Se k valeva 2, l’espressione k = 7 • denota il valore 7 • e cambia il valore di k,che d’ora in poi vale 7 (non più 2)

  36. ESEMPIO Se k valeva 2, l’espressione j = k+1 • denota il valore 3 • e cambia il valore di j,che d’ora in poi vale 3 (qualunque valore avesse prima) L’assegnamento è distruttivo

  37. ESPRESSIONI DI ASSEGNAMENTO Il valore denotato dall’espressione di assegnamento può essere usato in altre espressioni.Ad esempio, 3 + (k=7) • denota il valore 10 • e cambia in 7 il valore di k

  38. ASSEGNAMENTO & VARIABILI Una variabilein una espressione di assegnamento: • è intepretata come il suo R-value, se compare a destra del simbolo = • è intepretata come il suo L-value, se compare a sinistra del simbolo = 3.22 a x

  39. ESEMPIO Se x valeva 2, l’espressione x = x + 1 • denota il valore 3 • e cambia in 3 il valore di x • il simbolo x a destra dell’operatore = denota il valore attuale (R-value) di x, cioè 2 • il simbolo x a sinistra dell’operatore = denota la cella di memoria associata a x (L-value), a cui viene assegnato il valore dell’espressione di destra (3) • l’espressione nel suo complesso denota il valore della variabile dopo la modifica, cioè 3.

  40. ASSEGNAMENTO: ASSOCIATIVITÀ • Come tutti gli operatori, anche l’operatore di assegnamento deve avere una sua associatività k = j = 1 Prima k=j, o prima j=1 ? • l’operatore di assegnamento è associativo a destra: ciò consente espressioni di assegnamento multiplo

  41. ASSEGNAMENTO: ASSOCIATIVITÀ Esempi k = j = 1interpretato come k = (j = 1) i = j = k = 0interpretato come i = (j = (k=0)) i = k + 5 = 6NO: k+5 non ha un L-value! Nota: anche volendo, sarebbe stato impossibile farlo associativo a sinistra, in quanto ciò avrebbe reso molte espressioni prive di significato. Ad esempio: k = j = 2 interpretato come (k=j) = 2 ??? Equivarrebbe a scrivere 1 = 2 !!!!

  42. INCREMENTO (++) E DECREMENTO (--) Gli operatori di incremento e decremento sono usabili in due modi • come pre-operatori: ++v • come post-operatori: v++ primaincremento, poiuso primauso, poiincremento

  43. ESEMPI int i, j, k = 5; i = ++k /* i vale 6, k vale 6 */ i = k++ /* i vale 5, k vale 6 */ int i=4, j, k = 5; j = i + k++; /* j vale 9, k vale 6 */ j = ++k - k++; /* in cerca di guai! */

  44. ATTENZIONE…!! int k = 6; j = ++k - k++; /* in cerca di guai! */ Detti x = ++k e y = k++, • è certo che l’espressione venga valutata come j = x - y (da sinistra a destra) • è certo che alla fine k valga 8 • ma non si sa se venga calcolato prima x o prima y,e qui la cosa fa molta differenza! • se prima x, poi y  j = 7 - 7 = 0 • se prima y, poi x  j = 8 - 6 = 2

  45. UN ESEMPIO Ad esempio, se c vale 20, l’espressione vale 68... main() { int f, c = 20; f = 32 + c * 9 / 5; } L’espressionef = 32 + c * 9 / 5 • recupera l’ R-value della variabile c • calcola il corrispondente valore Fahrenheit e lo assegna alla variabile f (interpretata come L-value effetto collaterale) • scarta il valore denotato dall’espressione di assegnamento (che non viene più utilizzato) … quindi a f viene asse-gnato il valore 68. L’espressione f=68 denotaancora 68, che però vienescartato.

  46. ISTRUZIONI • Le istruzioni esprimono azioni che, una volta eseguite, comportano una modifica permanente dello stato interno del pro-gramma o del mondo circostante. • Le strutture di controllo permettono di aggregare istruzioni semplici in istruzioni più complesse.

  47. ISTRUZIONI • Una istruzione C è espressa dalle seguenti produzioni: <istruzione> ::= <istruzione-semplice> <istruzione> ::= <istruzione-di-controllo> <istruzione-semplice> ::= <espressione>; • Quindi, qualsiasi espressione seguita da un punto e virgola è una istruzione semplice.

  48. ESEMPI DI ISTRUZIONI SEMPLICI x = 0; y = 1; /* due istruzioni */ x = 0, y = 1; /* una istruzione */ k++; 3; /* non fa nulla */ ; /* istruz. vuota*/

  49. ISTRUZIONI DI CONTROLLO Una istruzione di controllo può essere: • una istruzione composta (blocco) • una istruzione condizionale (selezione) • una istruzione di iterazione(ciclo) come specificato dalla produzione: < istruzione-di-controllo > ::=<blocco> | <selezione> | <iterazione>

  50. ISTRUZIONI DI CONTROLLO Le istruzione di controllo sono alla base della programmazione strutturata(Dijkstra, 1969). Concetti chiave: • concatenazioneocomposizione • selezione o istruzione condizionaleramifica il flusso di controllo in base al valore vero o falso di una espressione (“condizione di scelta”) • ripetizione o iterazioneesegue ripetutamente un’istruzione finché rimane vera una espressione (“condizionedi iterazione”)

More Related