• Non ci sono risultati.

Un algoritmo realizza una relazione funzionale tra i valori di input e quelli di output F =

N/A
N/A
Protected

Academic year: 2022

Condividi "Un algoritmo realizza una relazione funzionale tra i valori di input e quelli di output F ="

Copied!
38
0
0

Testo completo

(1)

Un algoritmo realizza una relazione funzionale tra i valori di input e quelli di output

F = { (s, s’) }

per ogni s esiste una e una sola coppia (s, s’).

Esempio: un algoritmo che calcola il quadrato di un numero naturale è descritto dal seguente insieme di coppie:

{ (0, 0), (1, 1), (2, 4), (3, 9), (4, 16) . . . } .

(2)

Specifica di un algoritmo: espressione non ambigua dei requisiti funzionali che l’algoritmo deve soddisfare.

insieme di coppie infinito

predicati della logica per caratterizzare le coppie di input/output

{ (x, z) / x ∈ N & z = x . x }

(3)

Specifica di A è una coppia di predicati:

< p-in(x), p-out(x, z)>, dove:

• p-in(x): predicato di input di A, specifica i

vincoli cui devono soddisfare i valori forniti per le variabili di input (il dominio delle variabili);

• p-out(x, z): predicato di output di A, specifica la relazione di input / output.

Algoritmo A

variabili di input: x1, x2, . . . , xn ( x )

variabili di output: z1, z2, . . .,zk ( z )

(4)

quadrato di un numero naturale p-in(x) ≡ x ≥ 0

p-out(x, z) ≡ z = x

.

x

quoziente e il resto della divisione di x1 per x2 p-in(x1, x2) ≡ x1 ≥ 0 & x2 > 0

p-out(x1, x2, z1, z2) ≡ x1 = z1

.

x2 + z2 & 0 ≤ z2 < x2 moltiplicazione di x1 per x2

p-in(x1, x2) ≡ x1 ≥ 0 & x2 ≥ 0

p-out(x1, x2, z) ≡ z = x1

.

x2

(5)

Correttezza parziale

Dato un algoritmo A e una specifica

< p-in(x), p-out(x, z)>

A si dice parzialmente corretto rispetto alla specifica se

“per ogni valore a delle variabili di input x, che soddisfa il predicato di input, se l’algoritmo termina, termina con valore b per le variabili di output z, che soddisfa il

predicato p-out(a, b)”.

(6)

Terminazione

Dato un algoritmo A e un predicato di input p-in(x), si dice che A termina su p-in(x) se per ogni valore a

delle variabili di input x, che soddisfa il predicato di

input, l’algoritmo termina.

(7)

Correttezza totale

Dato un algoritmo A e una specifica

< p-in(x), p-out(x, z)>

A si dice totalmente corretto rispetto alla specifica se

è parzialmente corretto rispetto alla specifica e termina

sul predicato di input.

(8)

La correttezza parziale di un algoritmo A rispetto alla specifica <p-in(x), p-out(x, z)> è espressa dalla

Formula di correttezza di Hoare :

p-in(x) p-out(x, z) { } A { } { p-in(x) }

A

{ p-out (x, z) }

Verifica della correttezza parziale

(9)

{ p-in(x1, x2) ≡ x1 ≥ 0 & x2 ≥ 0 }

{ p-out(x1, x2, z) ≡ z = x1

.

x2 }

Prodotto

(10)

{ p-in(x) ≡≡ x ≥≥ 0 }

{ p-out(x, z) ≡≡ z > 0 } 1 z ← x

2 z ← z + 1

3 return z

Incremento (x)

(11)

“per ogni valore ≥ 0 assunto da x alla chiamata del metodo, al rientro il valore di z sarà > 0”

{ p-in(x) ≡≡ x ≥≥ 0 }

{ p-out(x, z) ≡≡ z > 0 } 1 z ← x

2 z ← z + 1 3 return z Incremento (x)

{ x ≥≥ 0 }

{ z > 0 } z > 0

z +1 > 0

x +1 > 0

x ≥ 0

(12)

{ }

{ p-out(x, z) ≡≡ z = x } 1 if x ≥ 0

then

2 z ← x

else

3 z ← - x

4 return z modulo (x)

{ z ≥≥ 0 & (z = x ∨∨ z = - x) }

{ x ≥≥ 0 & z ≥≥ 0 & z = x}

{ x < 0 & z > 0 & z = - x}

p-in(x) ≡ true

{ x ≥≥ 0 }

{ x < 0 }

z = x ≡≡ z ≥≥ 0 & (z = x ∨∨ z = - x)

(13)

{ x ≥≥ 0 & z ≥≥ 0 & z = x}

then

z ← x

else

z ← - x

{ z ≥≥ 0 & (z = x ∨∨ z = - x) } { x < 0 & z > 0 & z = - x}

{ x ≥≥ 0 }

{ x < 0 } x < 0 & -x > 0 & -x = - x

x ≥ 0 & x ≥ 0 & x = x

(14)

{x1 ≥≥ 0 & x2 ≥≥ 0 }

{z = x1

.

x2 }

moltiplicazione (x1, x2) y ← x1

z ← 0

while y > 0 do

z ← z + x2

y ← y - 1

return z

(15)

{x1 ≥ 0 & x2 ≥ 0 }

moltiplicazione (x1, x2)

y ← x1 z ← 0

{z = x1

.

x2 }

while y > 0 do z ← z + x2 y ← y - 1 return z

{x1

.

x2 = y

.

x2 + z & y ≥ 0}

x1 . x2 = x1 . x2 + 0 & x1 ≥ 0

{x1 ≥ 0 & x2 ≥ 0}

(16)

{x1 ≥ 0 & x2 ≥ 0 }

moltiplicazione (x1, x2) y ← x1

z ← 0

{z = x1

.

x2}

while y > 0 do z ← z + x2 y ← y - 1 return z

{x1 . x2 = y . x2 + z & y ≥ 0}

{x1 . x2 = y . x2 + z & y > 0}

{x1

.

x2 = y . x2 + z & y ≥ 0}

(17)

z ← z + x2 y ← y - 1

{x1 . x2 = y . x2 + z & y > 0}

x1 . x2 = (y-1) . x2 + x2 + z & y-1 ≥ 0

{x1

.

x2 = y . x2 + z & y ≥ 0}

(18)

{x1 ≥ 0 & x2 ≥ 0}

moltiplicazione (x1, x2) y ← x1

z ← 0

{z = x1.x2}

while y > 0 do z ← z + x2 y ← y - 1

return z

{ x1.x2 = y.x2 + z & y ≥ 0 }

{ x1.x2 = y.x2 + z & y > 0}

E dopo l’esecuzione del while, se termina:

{ x1.x2 = y.x2 + z & y ≥ 0 } { x1.x2 = y.x2 + z & y = 0 }

(19)

Difficoltà: esprimere il predicato che si mantiene vero durante l’esecuzione del ciclo:

Invariante di ciclo

45 19 44 19 43 19

1 19

855 . . . . . . 3 19 2 19

y: valori della prima colonna z : somma parziale

y

z

x1 x x2 y x x2 z

Ad esempio:

855 = 3 x 19 + 798

(20)

Moltiplicazione alla russa

z: somma parziale

y1: valori della prima colonna y2: valori della seconda colonna

x1 x x2 y1 x y2 z

19 76 --- 152 --- 608 855

45 19

22 38

11 76

5 152

2 304

1 608

y1 y2

y1

y2

z

Ad esempio:

855 = 5 x 152 + 95

(21)

while y1 > 0 do

if y1 is odd then z ← z + y2 y1 ← y1 div 2

y2 ← y2 + y2

return z

molt-russa (x1, x2) y1 ← x1

y2 ← x2 z ← 0

{ x1 ≥ 0 & x2 ≥ 0 }

{ x1.x2 = y1.y2 + z & y1 ≥ 0 }

{ x1.x2 = y1.y2 + z & y1 > 0 }

{ z = x1.x2 }

{ x1.x2 = y1.y2 + z & y1 = 0 }

{ x1.x2 = y1.y2 + z & y1 ≥ 0 }

(22)

y1 ← x1 y2 ← x2 z ← 0

{ x1.x2 = y1.y2 + z & y1 ≥ 0 } { x1 ≥ 0 & x2 ≥ 0 }

x1 . x2 = x1.x2 + 0 & x1 ≥ 0

(23)

if y1 is odd then

z ← z + y2 y1 ← y1 div 2

y2 ← y2 + y2

{ x1.x2 = y1.y2 + z & y1 > 0 }

{ x1.x2 = y1.y2 + z & y1 > 0 & y1 dispari}

{ x1.x2 = y1. y2 + z & y1 ≥ 0 }

(y1 div 2) . (y2 + y2) + z se y1 pari (y1 div 2) . (y2 + y2) + (z + y2) se y1 dispari x1.x2 =

& y1 div 2 ≥ 0

(24)

2n x m = n x 2m

(2n + 1) x m = 2n x m + m = n x 2m + m

x1.x2 = y1.y2 + z & y1 > 0

(y1 div 2) . (y2 + y2) + z se y1 pari (y1 div 2) . (y2 + y2) + (z + y2) se y1 dispari x1.x2 =

y1.y2 = (y1 div 2) . (y2 + y2) se y1 pari y1.y2 = (y1 div 2) . (y2 + y2) + y2 se y1 dispari

(25)

while y1 > 0 do

if y1 is odd then z ← z + y2 y1 ← y1 div 2

y2 ← y2 + y2 return z

molt-russa (x1, x2) y1 ← x1

y2 ← x2 z ← 0

{ x1 ≥ 0 & x2 ≥ 0 }

{ z = x1.x2 }

{ x1.x2 = y1. y2 + z & y1 ≥ 0 }

(26)

{ x1 ≥ 0 & x2 > 0 }

{ x1 = q . x2 + r & 0 ≤ r < x2 } q ← 0

r ← x1

while r x2 do q ← q + 1

r ← r - x2

return (q, r) divisione (x1, x2)

{ x1 = q . x2 + r & 0 ≤ r & x2 > 0 }

{ x1 = q . x2 + r & 0 ≤ r & x2 > 0 & r ≥ x2 }

{ x1 = q . x2 + r & 0 ≤ r & x2 > 0 } { x1 = q . x2 + r & 0 ≤ r & r < x2 }

(27)

x1 ≥ 0 & x2 > 0

x1 = 0 . x2 + x1 & 0 ≤ x1 & x2 > 0 q ← 0

r ← x1

q ← q + 1 r ← r - x2

x1 = q . x2 + r & 0 ≤ r & x2 > 0 & r ≥ x2

x1 = (q + 1) . x2 + (r - x2) & 0 ≤ (r - x2) & x2 > 0 }

(28)

supponiamo che: - gli estremi a e b siano numeri naturali - a ≤ b

- “passo” uno.

il costrutto for e` equivalente a:

i ← a

while i b do S

i ← i + 1

Il costrutto for: for i ← a to b do S

(29)

Massimo (A, n)

current-max ← A[0]

for i 1 to n-1 do

if current-max < A[i]

then current-max ← A[i]

return current-max { n ≥ 1 }

{ current-max è il massimo tra gli elementi di A } { current-max ≥ A[j], per ogni j, 0 ≤ j < n }

{ current-max ≥ A[j], per ogni j, 0 ≤ j < i } i ← 1

while i < n do

i ← i + 1

n = length[A]

(30)

Poly-eval (A, x, n) y ← 1

result ← A[0] i ← 1 for i 1 to n do

y ← y x

result result +A[i] y i ← i +1 return result

P(x) = a0 + a1x+ … + anxn

{ result = A[0] + A[1] x + ... + A[i-1] xi-1 & y = xi-1

}

{ result = A[0] + A[1] x + ... + A[n] xn

}

{ n ≥ 1}

n = grado del polinomio

(31)

Horner (A, x, n)

result ← A[n] i ← n - 1 for i n - 1 downto 0 do

result result x + A[i] i ← i - 1 return result

P(x) = a0 + x (a1+ … + x (an-1+ x an))…)

{result = A[i+1] + A[i+2] x + ... + A[n] xn-(i+1) } { n ≥ 1}

{result = A[0] + A[1] x + ... + A[n] xn

}

{result = A[i+1] + A[i+2] x + ... + A[n] xn-(i+1) }

(32)

Metodi ricorsivi

Massimo-ricorsivo (A, n) if n = 1

then current-max ← A[0]

return current-max y ← Massimo-ricorsivo (A, n-1) current-max ← max (y, A[n-1]) return current-max

T(n) = h se n = 1

T(n-1) + k altrimenti { n ≥ 1}

{ current-max è il massimo tra gli elementi di A}

n = length[A]

(33)

{ n = 1}

current-max ← A[0]

return current-max

{current-max è il massimo tra gli elementi di A}

n = 1

A[0] è il massimo tra gli elementi di A

(34)

{ current-max è il massimo tra gli elementi di A}

y ← Massimo-ricorsivo (A, n-1) current-max ← max (y, A[n-1]) return current-max

{ n > 1}

La correttezza viene verificata supponendo che la chiamata interna “funzioni bene” e dimostrando che le modifiche subite dalle variabili rendono vero il predicato.

(35)

y ← Massimo-ricorsivo (A, n-1) current-max ← max (y, A[n-1]) return current-max

{ n > 1}

{ current-max è il massimo tra gli elementi di A}

Supponiamo che Massimo-ricorsivo su un numero di elementi < n lavori correttamente:

{ n > 1}

y ← Massimo-ricorsivo (A, n-1)

{ current-max è il massimo tra gli elementi di A[0..n-2]}

(36)

return current-max { n > 1}

{ current-max è il massimo tra gli elementi di A}

y ← Massimo-ricorsivo (A, n-1)

current-max ← max (y, A[n-1])

{ current-max è il massimo tra gli elementi di A[0..n-2] }

{ current-max è il massimo tra gli elementi di A[0..n-1] }

La dimostrazione di correttezza per i metodi ricorsivi viene fatta per induzione sul numero di chiamate.

(37)

DI-Massimo-ricorsivo (A, p, r)

if p = r then current-max A[p]

return current-max

if p = r-1 then

if A[p] < A[r] then current-max A[r]

return current-max

else current-max A[p]

return current-max q ← (p + r)/2

current-max-1 DI-Massimo-ricorsivo (A, p, q) current-max-2 DI-Massimo-ricorsivo (A, q +1, r) current-max max(current-max1, current-max2) return current-max

{ current-max è il massimo tra gli elementi di A}

{ p ≥ 0 & r ≥ 0 & p ≤ r}

(38)

La correttezza e` facile da verificare.

Piu` difficile valutarne la complessita`

Anche per l’algoritmo ricorsivo la complessita` e` Θ(n), come per l’algoritmo iterativo visto in precedenza.

esprimiamo la complessita` come relazione di ricorrenza:

T(1) = c (p = q)

T(2) = d (p = q-1)

T(n) = T(  n/2  ) + T(  n/2  ) + e (p < q-1)

Riferimenti

Documenti correlati

Se la definizione di limite di funzione reale di variabile reale, con relative proprietà, si estende in modo agevole alle funzioni di R n in R le cose sono diverse quando cerchiamo

[r]

whose name is distinct from all other existing files, and opens the file for binary writing and reading (as if the mode string &#34;wb+&#34; were used in an fopen() call). If

nei testi, nelle pubblicazioni ed in ogni altra forma di divulgazione di studi, analisi ed elaborazioni di qualsiasi tipo realizzati dal soggetto richiedente utilizzando in tutto o

Settori – Tipologia di impianti di trasformazione/elaborazione Domanda Finale – Consumi finali dei prodotti per settori e/o destinazione.. Energy SUT aggregata toscana: 2015..

Teorema di integrabilit`a, teorema di equivalenza, propriet`a di ad- ditivit`a rispetto all’insieme di integrazione, teorema di Fubini, insiemi sem- plici e formule di

¨  Se la stringa di formato contiene un white space, la scanf legge zero o più white space, che verranno scartati, fino al primo carattere non white space.

 An efficient means of transferring data directly between I/O and memory for large data transfers since programmed I/O is suitable only for slow devices and individual