RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m,...

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

Transcript of RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m,...

Page 1: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

RICORSIONE & ITERAZIONE

Riconsideriamo l’esempio del MassimoComun Divisore visto tempo addietro:

m, se m=n

MCD(m, n-m), se m<n

MCD(m, n) = MCD(m-n, n), se m>n

Page 2: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

RICORSIONE & ITERAZIONE

Questo esempio era stato traspostonella 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 risultatoveniva sintetizzato in avanti, anziché all’in-dietro come nei processi ricorsivi.

Page 3: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

RICORSIONE & ITERAZIONE

Ogni processo computazionale che computi “in avanti”, per accumulo, costituisce una ITERAZIONEossia è un processo computazionale iterativo.

Ogni soluzione sintatticamente ricorsiva che dia luogo a un processo computazio-nale iterativo costituisce una ricorsione solo apparente: una ricorsione tail.

Page 4: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

RICORSIONE & ITERAZIONE

La caratteristica fondamentale di unprocesso 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.

Page 5: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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’accumulatore che lo porta a esprimere, dal valore relativo al passo k, il valore relativo al passo k+1.

Page 6: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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) * vk per k1

n! = vn per k=n

Page 7: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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);

}

Page 8: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

INVARIANTI

Un invariante di programma è una relazionesempre 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

Page 9: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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.

Page 10: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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-1 per i>0in particolare:

bk = vk per i=k

Un possibile invariante: bk = vi * bk-i

Page 11: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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 = bk purché v0 =1

• per i=k, bk = vk * b0 = vkcondizione iniziale

Page 12: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

PROBLEMA: CALCOLO DI bk

Come usarlo per progettare l’algoritmo?• inizialmente, v = v0 =1

• a ogni passo si deve trasformare l’invariante bk = vi * bk-i nella formabk = vi+1 * bk-(i+1) che deve assumere al passo successivo

• ciò si ottiene ponendo, a ogni passov’ = b * v i’ = i + 1

Page 13: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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);}

V0=1 i=0

V’ = Vi+1 = Vi* b

i’ = i+1

Page 14: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

PROGETTARE bk PER INVARIANTI

Partendo da relazioni diverse si ottengonoapprocci 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

Page 15: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

PROGETTARE bk PER INVARIANTI

Come usarlo per progettare l’algoritmo?

• a ogni passo si deve riscrivere bk in 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-1

e moltiplicando per brichiede una operazione dopo la fase

di modifica di b e k soluzione ricorsiva

Page 16: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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);

}

ricorsione non-tail

(Complessità dell’ordine di log2 k)

Page 17: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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

Page 18: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

PROGETTARE bk PER INVARIANTI

Progetto dell’algoritmo:• a ogni passo si deve trasformare

l’invariante bk = t * vn in 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!

Page 19: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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 k non servono!Quindi li possiamo togliere…!!

Page 20: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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);}

Page 21: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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

Page 22: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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=0p = x * y = x*0 = 0

Page 23: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO: MOLTIPLICAZIONE

Approccio ricorsivo: si applica direttamente la relazionetrovata p = 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

Page 24: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO: MOLTIPLICAZIONE

Approccio ricorsivo: si applica direttamente la relazionetrovata p = 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)

Page 25: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO: MOLTIPLICAZIONE

Verso un approccio iterativoCerchiamo un invariante di ciclo

p = x * y + zPonendo y=Q*B+R e 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

Page 26: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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.

Page 27: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO: MOLTIPLICAZIONE

Perché supponiamo di saper già moltiplicare,e dividere per 2 (trovando anche il resto) ?

Perché l’elaboratore è intrinsecamente capacedi farlo nella 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)

Page 28: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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

y%2 = 0y/2x/2

Page 29: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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 modifica del contenuto di una cella di memoria?

Page 30: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

UNA PROPOSTA

• È possibile riusare una stessa area dati senza bisogno di crearne una nuova ad ogni passo computazionale?

• Ci sono controindicazioni?

Page 31: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

VARIABILI NEI LINGUAGGI IMPERATIVI

Una variabile in un linguaggio imperativo non è solo un sinonimo per un dato come

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.22x

Page 32: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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

Page 33: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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

Page 34: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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.

Page 35: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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)

Page 36: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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

Page 37: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESPRESSIONI DI ASSEGNAMENTO

Il valore denotato dall’espressione diassegnamento può essere usato in altreespressioni. Ad esempio,

3 + (k=7) denota il valore 10 e cambia in 7 il valore di k

Page 38: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ASSEGNAMENTO & VARIABILI

Una variabile in una espressione diassegnamento: è 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.22x

Page 39: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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.

Page 40: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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

Page 41: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ASSEGNAMENTO: ASSOCIATIVITÀ

Esempi

k = j = 1 interpretato come k = (j = 1)

i = j = k = 0 interpretato come i = (j = (k=0))

i = k + 5 = 6 NO: k+5 non ha un L-value!

Nota: anche volendo, sarebbe stato impossibile farloassociativo a sinistra, in quanto ciò avrebbe resomolte espressioni prive di significato. Ad esempio:

k = j = 2 interpretato come (k=j) = 2 ???Equivarrebbe a scrivere 1 = 2 !!!!

Page 42: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

INCREMENTO (++) E DECREMENTO (--)

Gli operatori di incremento e decrementosono usabili in due modi

• come pre-operatori: ++v

• come post-operatori: v++

prima incremento, poi uso

prima uso, poi incremento

Page 43: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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! */

Page 44: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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

Page 45: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

UN ESEMPIO

main() { int f, c = 20;

f = 32 + c * 9 / 5;}

L’espressione f = 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)

Ad esempio, se c vale 20, l’espressione vale 68...

… quindi a f viene asse-gnato il valore 68.

L’espressione f=68 denotaancora 68, che però viene

scartato.

Page 46: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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.

Page 47: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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.

Page 48: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESEMPI DI ISTRUZIONI SEMPLICI

x = 0; y = 1; /* due istruzioni */

x = 0, y = 1; /* una istruzione */

k++;

3; /* non fa nulla */

; /* istruz. vuota*/

Page 49: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

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>

Page 50: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONI DI CONTROLLO

Le istruzione di controllo sono alla base dellaprogrammazione strutturata (Dijkstra, 1969).

Concetti chiave:• concatenazione o composizione • selezione o istruzione condizionale

ramifica 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 (“condizione di iterazione”)

Page 51: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

TEOREMA DI JACOPINI-BÖHM

• Le strutture di concatenazione, iterazione e selezione costituiscono un insieme completo in grado di esprimere tutte le funzioni calcolabili.

• Dunque, l’uso di queste sole strutture di controllo non limita il potere espressivo.

• La dimostrazione del teorema è basata sulla Turing-equivalenza di un “mini-linguaggio” che fornisca solo tali strutture di controllo.

Page 52: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

BLOCCO

<blocco> ::= { [ <dichiarazioni e definizioni> ]

{ <istruzione> }

}• dopo un blocco non occorre il

punto e virgola (esso termina le istruzioni semplici, non separa istruzioni)

I1

I2

I3

In

Lo scope dei simboli che compaiono entro il blocco è il blocco stesso

Page 53: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESEMPIO DI BLOCCO

main() { /* INIZIO BLOCCO */ const float F1=9.0, F2=5, SH=32; int c, f, temp = 20; char scala = 'C'; c = (scala != 'F') ? temp : (F2 / F1 * (temp - SH)) ; f = (scala != 'F') ? (SH+temp*F1/F2)

: temp;} /* FINE BLOCCO */

Page 54: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

..una nota “en passant”...

main() { /* INIZIO BLOCCO */ const float F1=9.0, F2=5, SH=32; int c, f, temp = 20; char scala = 'C'; c = (scala != 'F') ? temp : (F2 / F1 * (temp - SH)) ; f = (scala != 'F') ? (SH+temp*F1/F2)

: temp;} /* FINE BLOCCO */

Il qualificatore const rendequeste variabili non modificabili

Page 55: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESEMPIO DI BLOCCHI ANNIDATI

main() { /* INIZIO BLOCCO ESTERNO */ const float F1=9.0, F2=5, SH=32; int c, f, temp = 20; { /* INIZIO BLOCCO INTERNO */ char scala = ‘C’; c = (scala != 'F') ? temp : (F2 / F1 * (temp - SH)) ; f = (scala != 'F') ? (SH+temp*F1/F2)

: temp; } /* FINE BLOCCO INTERNO */} /* FINE BLOCCO ESTERNO */

Page 56: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONI CONDIZIONALI

<selezione> ::=

<scelta> | <scelta-multipla>• la seconda non è essenziale, ma migliora

l’espressività.• l’espressione condizionale ternaria (.. ? … : …)

fornisce già un mezzo per fare scelte, ma è poco leggibile in situazioni di medio/alta complessità. L’istruzione di scelta fornisce un altro modo per esprimere alternative.

Page 57: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE DI SCELTA SEMPLICE

<scelta> ::= if <condizione> <istruzione1> [ else <istruzione2> ]

condizionevera falsa

istruzione2istruzione1

Una espressione logica o relazionale,che viene valutata al momento della

esecuzione dell’istruzione if.

Page 58: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE DI SCELTA SEMPLICE

<scelta> ::= if <condizione> <istruzione1> [ else <istruzione2> ]

condizionevera falsa

istruzione2istruzione1

La parte else è opzionale:se omessa, in caso di

condizione falsa si passasubito all’istruzione che

segue l’if.

Page 59: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESEMPIO DI ISTRUZIONE if

• <istruzione1> e <istruzione2> sono ciascuna una singola istruzione

• Qualora occorra specificare più istruzioni, si deve quindi utilizzare un blocco.

if (n > 0) { /* inizio blocco */

a = b + 5;

c = (x<3) ? a : b;

} /* fine blocco */else n = b;

Page 60: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE if ANNIDATE

• Come caso particolare, <istruzione1> o <istruzione2> potrebbero essere un altro if

• Occorre attenzione ad associare le parti else (che sono opzionali) all’ if corretto

if (n > 0) if (a>b) n = a; else n = b; /* riferito a if(a>b) */

if (n > 0) { if (a>b) n = a; }else n = b; /* riferito a if(n>0) */

Regola semantica:l’else è sempre associato

all’if più interno

Se ciò non soddisfa occor-re inserire esplicitamente

un blocco.

Page 61: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE DI SCELTA MULTIPLA

• Consente di scegliere fra molte istruzioni (alternative o meno) in base al valore di una espressione di selezione.

• L’espressione di sele-zione deve denotare un valore numerabile (intero, carattere,…).

espressione di selezione

caso Aistruzioni1

caso Bistruzioni2

defaultistruzioni

break

break

break

Page 62: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE DI SCELTA MULTIPLA

<scelta-multipla> ::=switch (selettore) {case <etichetta1> : < istruzioni> [ break; ]case <etichetta2> : < istruzioni> [ break; ]

…[ default : < istruzioni> ]}

Il valore dell’espressione selettore viene confron-tato con le etichette dei vari casi: l’esecuzioneprosegue dal ramo corrispondente (se esiste).

Se nessuna etichetta corri-sponde, si prosegue col il

ramo default.

Se neanche quello esiste, si prosegue con l’istruzione

successiva allo switch.

Page 63: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE DI SCELTA MULTIPLA

<scelta-multipla> ::=switch (selettore) {case <etichetta1> : < istruzioni> [ break; ]case <etichetta2> : < istruzioni> [ break; ]

…[ default : < istruzioni> ]}

Il valore dell’espressione selettore viene confron-tato con le etichette dei vari casi: l’esecuzioneprosegue dal ramo corrispondente (se esiste).

Le etichette sono costantidello stesso tipo del

selettore.

Attenzione: <istruzioni> denota una sequenza di

istruzioni (non occorre un blocco)

Page 64: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE DI SCELTA MULTIPLA

espressione di selezione

caso Aistruzioni1

caso Bistruzioni2

defaultistruzioni

break

break

break

I vari rami non sono mutua-mente esclusivi: imboccato un ramo, si eseguono anche

tutti i rami successivi...

… a meno che non ci siail comando break a forzare

esplicitamente l’uscita.

Page 65: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONI DI ITERAZIONE

<iterazione> ::=

<while> | <for> | <do-while>• Per il Teorema di Jacopini-Böhm, una struttura

di controllo iterativa sarebbe sufficiente: averne di più migliora l’espressività del linguaggio.

• Le istruzioni di iterazione: hanno un solo punto di ingresso e un solo punto di

uscita nel flusso del programma perciò possono essere interpretate come una

singola azione in una computazione sequenziale.

Page 66: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE while

<while> ::= while( <condizione> ) <istruzione>

condizione

vera

falsa

istruzione

L’istruzione viene ripetuta pertutto il tempo in cui la condi-

zione rimane vera.

Se la condizione è falsa, l’itera- zione non viene eseguita

neppure una volta.

In generale, non è noto quantevolte l’istruzione sarà ripetuta.

Page 67: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE while

<while> ::= while( <condizione> ) <istruzione>

condizione

vera

falsa

istruzione

Prima o poi, direttamente oindirettamente, l’istruzione

deve modificare la condizione:altrimenti, l’iterazione durerà

per sempre!

Perciò, quasi sempre istruzioneè un blocco, al cui interno simodifica qualche variabile

che compare nella condizione.

Page 68: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE do...while

<do-while> ::=do <istruzione> while( <condizione> );

È una “variazione sul tema” della precedente: la condizione

viene verificata dopo aver eseguito l’istruzione.

Se la condizione è falsa, l’itera- zione viene comunque ese-

guita almeno una volta.

condizione

vera

falsa

istruzione

particolarmente adatta alleverifiche dopo un input

Page 69: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE for

È una evoluzione dell’istruzione whilerispetto a cui mira a eliminare alcunefrequenti sorgenti di errore:

mancanza delle necessarie inizializza-zioni delle variabili

mancanza della fase di modifica del ciclo(rischio di ciclo senza fine)

Page 70: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE for<for> ::=for( <espr-i> ; <cond> ;<espr-m>) <istruzione>

condizione

vera

falsa

istruzione

espr-inizializzazione

espr-modifica

Struttura del while

Page 71: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE for<for> ::=for( <espr-i> ; <cond> ;<espr-m>) <istruzione>

condizione

vera

falsa

istruzione

espr-inizializzazione

espr-modifica

Espressione di inizia-lizzazione: valutata una e una sola volta prima di iniziare l’itera-zione.

Espressione di inizia-lizzazione: valutata una e una sola volta prima di iniziare l’itera-zione.

Page 72: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE for<for> ::=for( <espr-i> ; <cond> ;<espr-m>) <istruzione>

Condizione:valutata a ogni interazione,per decidere se proseguire(come in un while)

condizione

vera

falsa

istruzione

espr-inizializzazione

espr-modifica

Condizione:valutata a ogni interazione,per decidere se proseguire(come in un while)Se manca si assume vera!

Page 73: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ISTRUZIONE for<for> ::=for( <espr-i> ; <cond> ;<espr-m>) <istruzione>

Condizione:valutata a ogni interazione,per decidere se proseguire(come in un while)

condizione

vera

falsa

istruzione

espr-inizializzazione

espr-modifica

Espressione di modifica:valutata a ogni interazione,dopo aver eseguito l’istru-zione.

Page 74: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

UN ESEMPIO

Il solito problema: calcolo del fattoriale

• Dall’approccio ricorsivo…

• ...all’approccio sintatticamente ricorsivo, ma computazionalmente iterativo (ricorsione tail)...

• ...all’approccio iterativo tramite istruzioni di iterazione.

Page 75: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

IL FATTORIALE ITERATIVO TRAMITE ESPRESSIONE CONDIZIONALE...

int factIter(int n, int i, int v){

/* inizialmente, v = 1 */

/* invariante di ciclo: v = i! */ return (i==n) ? v :

factIter(n,i+1,(i+1)*v);

}

Chiamata: factIter(n,0,1)

Page 76: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

... IL FATTORIALE ITERATIVO TRAMITE ISTRUZIONE CONDIZIONALE...

int factIter(int n, int i, int v){

/* inizialmente, v = 1 */

/* invariante di ciclo: v = i! */if (i==n) return v;

else return factIter(n,i+1,(i+1)*v);

}

Chiamata: factIter(n,0,1)

Page 77: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

...IL FATTORIALE ITERATIVO TRAMITE ISTRUZIONE DI ITERAZIONE: while

int fact(int n){int v=1; /* inizialmente, v = 1 */int i=0; /* inizialmente, i = 0 */while (i<n) { /* invariante: v = i! */

v = (i+1)*v;i = i+1;

}return v;

}

I valori iniziali, prima forniti dl-l’esterno, divengono ora varia-bili locali della funzione interfaccia utente più pulita

Page 78: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

...IL FATTORIALE ITERATIVO TRAMITE ISTRUZIONE DI ITERAZIONE: do...while

int fact(int n){int v=1; /* inizialmente, v = 1 */int i=0; /* inizialmente, i = 0 */do { /* invariante: v = i! */

v = (i+1)*v;i = i+1;

} while (i<n);return v;

}

La condizione è ora verificatadopo ogni interazione anzichéprima.

Problema: che succede se siinvoca fact(-3) ???

Page 79: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

...IL FATTORIALE ITERATIVO TRAMITE ISTRUZIONE DI ITERAZIONE: for

int fact(int n){int v=1; /* inizialmente, v = 1 */int i;for (i=0;i<n; i+1) v = (i+1)*v; /* invariante: v = i! */return v;

} Le fasi di inizializzazione e dimodifica della variabile di con-trollo del ciclo sono ben in evi-denza nella struttura del for.

Page 80: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ITERAZIONE & RICORSIONE TAIL

Poiché la ricorsione tail dà luogo a un processo computazionale di tipo iterativo, deve essere possibile trasformare un ciclo in ricorsione tail e viceversa.

COME FARLO?

il corpo del ciclo rimane immutato il ciclo diventa un if con, in fondo, la chiamata tail-ricorsiva.

Page 81: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ITERAZIONE & RICORSIONE TAIL

• il corpo del ciclo rimane immutato

• il ciclo diventa un if con, in fondo, la chiamata tail-ricorsiva.

Naturalmente, può essere necessario aggiungere nuovi parametri nell’intestazione della funzione tail-ricorsiva, per “portare avanti” le variabili di stato.

while (condizione) {

<corpo del ciclo>

}

if (condizione) {

<corpo del ciclo>

<chiamata ricorsiva>}

Page 82: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESEMPIO: Massimo Comun Divisore

La soluzione tail-ricorsiva già vista...int mcd(int m, int n){if (m!=n) if (m>n) return mcd(m-n, n);

else return mcd(m, n-m);else return m;

}… opportunamente riscritta...int mcd(int m, int n){if (m!=n) { if (m>n) m=m-n; else n=n-m; return mcd(m,n);} else return m;

}

Page 83: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESEMPIO: Massimo Comun Divisore

… opportunamente riscritta...int mcd(int m, int n){if (m!=n) { if (m>n) m=m-n; else n=n-m; return mcd(m,n);} else return m;

} … traslata in ciclo:int mcd(int m, int n){while (m!=n) if (m>n) m=m-n; else n=n-m;return m;

}

Page 84: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 1

Dati tre valori a b c che rappresentano le lunghezze di tre segmenti, valutare se posso-no essere i tre lati di un triangolo, e se sì deci-derne il tipo (scaleno, isoscele, equilatero).

Vincolo: deve essere c < (a+b)

Rappresentazione delle informazioni:• la variabile booleana triangolo indica se i tre seg- menti possono costituire un triangolo• le variabili booleane scaleno, isoscele e equil indicano il tipo di triangolo.

Page 85: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 1Specifica:se a+b>c

triangolo = verose a=b=c { equil=isoscele=vero

scaleno=falso }altrimenti se a=b o b=c o a=c { isoscele=vero;

equil=scaleno=falso } altrimenti

{ scaleno=vero; equil=isoscele=falso }

altrimentitriangolo = falso

Page 86: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 1

main (){ float a=1.5, b=3.0, c=4.0; int triangolo, scaleno, isoscele, equil; triangolo = (a+b>c); if (triangolo) {

if (a==b && b==c) { equil=isoscele=1; scaleno=0; }else if (a==b || b==c || a==c) { isoscele=1; scaleno=equil=0;}

else { scaleno=1; isoscele=equil=0;}

}}

Page 87: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 1

main (){ float a=1.5, b=3.0, c=4.0; int triangolo, scaleno, isoscele, equil; triangolo = (a+b>c); if (triangolo) {

if (a==b && b==c) { equil=isoscele=1; scaleno=0; }else if (a==b || b==c || a==c) { isoscele=1; scaleno=equil=0;}

else { scaleno=1; isoscele=equil=0;}

}}

Attenzione! Una espressionecome a==b==c sarebbe stataformalmente lecita, ma avreb-be avuto tutt’altro significato!

Non si può usare l’istruzione di scelta multipla (switch) perchéle condizioni da verificare sonouguaglianze fra variabili, nonsemplici confronti con etichettepredefinite.

Page 88: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 2

Dati due valori positivi X e Y, calcolarne ladivisione intera X/Y come sequenza disottrazioni, ottenendo quoziente e resto.

Invariante di ciclo:

X = Q * Y + R, con R 0

• inizialmente, Q=0, R=X (R>Y)• a ogni passo, Q’=Q+1, R’=R-Y (R>Y)• alla fine, X = Q(n) * Y + R (n) (0<R<Y)

che è la definizione di divisione intera.

Page 89: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 2Specifica:

sia Q il quoziente, inizialmente pari a 0sia R il resto, inizialmente pari a Xwhile (R Y)

incrementare il quoziente Qdecrementare R di una quantità Y

Codifica

main(){ int x = 20, y = 3, q, r; for (q=0, r=x; r>=y; q++, r=r-y);}

Notare l’uso di una espressioneconcatenata per concatenare dueassegnamenti e inizializzare cosìdue variabili.

Idem per le operazionidi modifica

Page 90: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

OPERATORI DI ASSEGNAMENTO “COMPATTI”

Il C introduce una forma particolare di assegnamento che ingloba anche un’operazione aritmetica o bit a bit:

l-espr = <espressione>

è “quasi equivalente” a

l-espr = l-espr <espressione>

dove indica un operatore fra+, –, *, /, %, >>, <<, &, ^, |

Page 91: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

OPERATORI DI ASSEGNAMENTO “COMPATTI”

Perché “quasi” equivalente ? nel primo caso, l-espr viene valutata

una sola volta

nel secondo, invece, viene valutata due volte

Quindi, le due forme sono equivalenti solo se la valutazione di l-espr non comporta effetti collaterali

Page 92: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

OPERATORI DI ASSEGNAMENTO “COMPATTI”

Esempik += j equivale a k = k + j

k *= a + b equivale a k = k*(a+b)*/

v[i++] *= n non equivale av[i++] = v[i++]*n */

Page 93: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 3

Dati tre valori a, b, c, rappresentanti i coeffi-cienti di un’equazione di secondo grado a x2 + b x + c = 0, calcolarne le radici (reali).

Specifica:Calcolare il valore delta = b2 - 4acSe delta0

calcolare d = deltacalcolare le due radici x1, x2 = - (b d) / 2a

altrimenti (radici complesse: halt)

Page 94: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 3

#include <math.h>main (){ float a=1.0, b=2.0, c=-15.0; float delta, d, x1, x2;

delta = b*b-4*a*c; if (delta>=0){

d = sqrt(delta);x1 = -(b+d)/(2*a);x2 = -(b-d)/(2*a);

}}

Direttiva al preprocessore: include la libreria matematica(fornisce la funzione sqrt)

Page 95: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 4

Scrivere una funzione che verifichi se un naturale N è primo.

Specifica di I° livello (Crivello di Eratostene):

Occorre provare a dividere N per tutti i numeri K N: se nessuno risulta essere un divisore, allora N è primo

Specifica di II° livello:

Se N è 1, 2 o 3, allora è primo senz’altro. Altrimenti, se è un numero pari, non è primo.Se invece N è dispari e >3, occorre tentare tutti i possibili divisori da 3 in avanti, fino a N.

Page 96: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 4

#include <math.h>int isPrime(int n) {int max,i;if (n>=1 && n<=3) return true; /* 1,2,3 ok */if (n%2==0) return false; /* numeri pari no */max = sqrt(n);for(i=3; i<=max; i+=2)

if (n%i==0) return false;return true;

}

Page 97: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 5

Scrivere una funzione radice che calcoli la radice quadrata (intera) di un naturale N.

Specifica di I° livello:

int radice(int n);

restituisce il massimo intero X tale che X*X N Specifica di II° livello:

Considera un naturale X dopo l’altro a partire da 1, e calcolane il quadrato X*X: fermati appena tale quadrato supera N.Il precedente numero considerato (X-1) è il risultato.

Page 98: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 5

int radice(int n) {int x;for(x=0; x*x <= n; x++);return x-1;

}Il corpo del ciclo è vuoto: ineffetti, l’elaborazione consistesolo nell’incrementare x perun opportuno numero di volte.

Page 99: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 6

Scrivere una funzione che, dato un carattere C, restituisca il corrispondente maiuscolo.

Specifica di I° livello:

char maiuscolo(char c);restituisce il maiuscolo di C

Specifica di II° livello:

Se C non è una lettera minuscola, restituiscilo tale e quale. Altrimenti, per calcolare il corrispondente maiu-scolo, sfrutta l’ ordinamento della codifica dei caratteri:– ogni carattere è associato a un intero– le lettere da ‘A’ a ‘Z’ sono in sequenza– le lettere da ‘a’ a ‘z’ sono in sequenza

Page 100: RICORSIONE & ITERAZIONE Riconsideriamo lesempio del Massimo Comun Divisore visto tempo addietro: m, se m=n MCD(m, n-m),se m

ESERCIZIO 6

char maiuscolo(char c) {if (c<'a' || c>'z') return c;else return c – 'a' + 'A';

}

Aritmetica fra caratteri: possibileperché le operazioni vengonosvolte sul corrispondente codice(ASCII o UNICODE)

Attenzione! Una espressione come 'a’<c<'z' è lecita, ma ha tutt’altro significato!