22.11.2014 Views

Appunti di Calcolo Numerico - Esercizi e Dispense - Università degli ...

Appunti di Calcolo Numerico - Esercizi e Dispense - Università degli ...

Appunti di Calcolo Numerico - Esercizi e Dispense - Università degli ...

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Annamaria Mazzia<br />

<strong>Appunti</strong> <strong>di</strong> <strong>Calcolo</strong> <strong>Numerico</strong><br />

Dipartimento <strong>di</strong> Ingegneria Civile E<strong>di</strong>le e Ambientale<br />

Università <strong>degli</strong> Stu<strong>di</strong> <strong>di</strong> Padova<br />

Creative Commons Attribuzione- Non commerciale -Non opere derivate 3.0 Italia License<br />

a.a. 2011/2012


Annamaria Mazzia: <strong>Appunti</strong> <strong>di</strong> <strong>Calcolo</strong> <strong>Numerico</strong>,<br />

Dipartimento <strong>di</strong> Ingegneria Civile E<strong>di</strong>le e Ambientale<br />

Università <strong>degli</strong> Stu<strong>di</strong> <strong>di</strong> Padova<br />

VERSIONE A.A. 2011/2012 .<br />

SITO DELLE DISPENSE:<br />

http://<strong>di</strong>spense.dmsa.unipd.it/<br />

E-MAIL:<br />

mazzia@dmsa.unipd.it<br />

Questo lavoro è stato rilasciato sotto la licenza CREATIVE COMMONS ATTRIBUZIONE- NON COMMERCIALE -<br />

NON OPERE DERIVATE 3.0 ITALIA LICENSE,<br />

Per leggere una copia della licenza visita il sito web (http://creativecommons.org/licenses/<br />

by-nc-nd/3.0/it/)<br />

Foto <strong>di</strong> copertina: Pietre...<br />

Per ricordare l’etimologia della parola CALCOLO: dal latino Calculus – pietruzza, lapillo – a sua volta <strong>di</strong>minuitivo<br />

<strong>di</strong> Calx, nel senso originario <strong>di</strong> ghiaia, sasso, perchè gli antichi, per fare i loro conti, utilizzavano<br />

pietruzze al posto <strong>di</strong> cifre aritmetiche. (definizione tratta dal Vocabolario Etimologico della Lingua Italiana <strong>di</strong><br />

O. Pianigiani http://www.etimo.it)


INDICE<br />

In<strong>di</strong>ce<br />

iii<br />

1 Struttura dell’elaboratore 1<br />

1.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />

1.2 La preistoria del computer: Babbage e Lovelace . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

1.3 Gli albori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

1.4 Architettura del Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

1.5 Software e Sistema Operativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />

1.5.1 Per capire meglio il sistema operativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

1.6 Il file system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.7 Un po’ <strong>di</strong> storia sui sistemi operativi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.8 Lavorare in ambiente Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

1.9 E<strong>di</strong>tor <strong>di</strong> testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

2 Richiami <strong>di</strong> analisi 13<br />

2.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

2.2 Identità trigonometriche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

2.3 Regole su funzione esponenziale e logaritmica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

2.4 Derivate e integrali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

2.5 Teoremi utili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

3 Rappresentazione dei numeri nel calcolatore 19<br />

3.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

3.2 Aritmetica <strong>di</strong> macchina . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

3.3 Conversione <strong>di</strong> base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

3.4 Rappresentazione IEEE dei numeri <strong>di</strong> macchina . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

3.5 Precisione numerica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

3.6 Propagazione <strong>degli</strong> errori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

3.7 Instabilità e malcon<strong>di</strong>zionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

3.7.1 Instabilità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

3.7.2 Malcon<strong>di</strong>zionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />

4 Zeri <strong>di</strong> funzione 37<br />

4.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

4.2 Metodo delle Bisezioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

4.3 Metodo del Punto Fisso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

4.4 Il Metodo <strong>di</strong> Newton-Raphson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

4.5 Convergenza <strong>di</strong> un metodo iterativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

4.6 Complessità computazionale <strong>di</strong> uno schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

4.7 Il metodo delle secanti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

4.8 Confronto tra i meto<strong>di</strong> <strong>di</strong> Newton-Raphson e la Regula Falsi . . . . . . . . . . . . . . . . . . . . . 50<br />

4.9 Metodo <strong>di</strong> Newton-Raphson per ra<strong>di</strong>ci multiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

iii


INDICE<br />

4.10 Controllo sugli scarti e grafici <strong>di</strong> convergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

4.11 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />

5 Interpolazione 61<br />

5.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />

5.2 Interpolazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />

5.3 Interpolazione polinomiale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

5.3.1 Funzioni base monomiali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

5.3.2 Polinomi <strong>di</strong> Lagrange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65<br />

5.3.3 Formula dell’errore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />

5.3.4 Differenze <strong>di</strong>vise e formula <strong>di</strong> Newton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68<br />

5.4 Considerazioni sull’interpolazione polinomiale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

5.4.1 Fenomeno <strong>di</strong> Runge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

5.4.2 Malcon<strong>di</strong>zionamento nell’interpolazione con funzioni base monomiali . . . . . . . . . 72<br />

5.5 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />

6 Approssimazione 77<br />

6.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

6.2 Retta <strong>di</strong> regressione lineare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />

6.3 Approssimazione polinomiale ai minimi quadrati . . . . . . . . . . . . . . . . . . . . . . . . . . . 80<br />

6.4 Approssimazioni <strong>di</strong> tipo esponenziale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />

6.5 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />

7 Meto<strong>di</strong> <strong>di</strong>retti per la soluzione <strong>di</strong> sistemi lineari 85<br />

7.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85<br />

7.2 Elementi <strong>di</strong> Algebra Lineare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86<br />

7.3 Metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />

7.3.1 Sostituzione all’in<strong>di</strong>etro e in avanti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />

7.3.2 Eliminazione <strong>di</strong> Gauss: esempio particolare . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />

7.3.3 Eliminazione <strong>di</strong> Gauss: caso generale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93<br />

7.4 Strategie <strong>di</strong> pivoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />

7.5 Fattorizzazione triangolare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

7.5.1 Fattorizzazione LDU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

7.5.2 Fattorizzazione <strong>di</strong> Gauss senza pivoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98<br />

7.5.3 Fattorizzazione <strong>di</strong> Cholesky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />

7.6 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />

8 Meto<strong>di</strong> Iterativi per la soluzione <strong>di</strong> sistemi lineari 105<br />

8.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />

8.2 Meto<strong>di</strong> iterativi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

8.3 Norme <strong>di</strong> vettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

8.4 Norme <strong>di</strong> matrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107<br />

8.5 Autovalori e autovettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />

8.6 Meto<strong>di</strong> classici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110<br />

8.6.1 Convergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110<br />

8.6.2 Controllo della convergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111<br />

8.6.3 I meto<strong>di</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113<br />

8.6.4 Convergenza dei meto<strong>di</strong> <strong>di</strong> Jacobi, Gauss-Seidel, rilassamento . . . . . . . . . . . . . . . 117<br />

8.7 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />

9 Integrazione numerica 123<br />

9.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123<br />

9.2 Formula dei trapezi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124<br />

iv


In<strong>di</strong>ce<br />

9.3 Formule <strong>di</strong> Newton-Cotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />

9.3.1 Formula <strong>di</strong> Cavalieri-Simpson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

9.3.2 Sull’errore della formula <strong>di</strong> Cavalieri-Simpson . . . . . . . . . . . . . . . . . . . . . . . . 129<br />

9.4 Formule composte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />

9.4.1 Formula composta dei trapezi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />

9.4.2 Confronti tra la formula dei trapezi e <strong>di</strong> Cavalieri-Simpson . . . . . . . . . . . . . . . . . 134<br />

9.5 Estrapolazione <strong>di</strong> Richardson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136<br />

9.6 Approssimazione <strong>di</strong> Romberg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />

9.7 Introduzione alle formule <strong>di</strong> quadratura <strong>di</strong> Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />

9.7.1 Proprietà delle formule <strong>di</strong> Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

9.7.2 Formule <strong>di</strong> Gauss-Legendre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

9.7.3 Altre formule <strong>di</strong> Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

9.7.4 Applicazione delle formule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />

9.7.5 Sulla funzione peso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

9.8 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

10 Equazioni alle derivate or<strong>di</strong>narie 147<br />

10.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />

10.2 Sulle equazioni <strong>di</strong>fferenziali or<strong>di</strong>narie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />

10.3 Metodo <strong>di</strong> Eulero esplicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149<br />

10.4 Metodo <strong>di</strong> Eulero implicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151<br />

10.5 Metodo <strong>di</strong> Crank-Nicolson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154<br />

10.6 Stu<strong>di</strong>o dell’errore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155<br />

10.7 Errori <strong>di</strong> troncamento locale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155<br />

10.8 Convergenza e stabilità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

10.8.1 Convergenza <strong>di</strong> Eulero esplicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

10.8.2 Stabilità <strong>di</strong> Eulero esplicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157<br />

10.8.3 Convergenza <strong>di</strong> Eulero implicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157<br />

10.8.4 Stabilità <strong>di</strong> Eulero implicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

10.8.5 Convergenza <strong>di</strong> Crank-Nicolson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

10.8.6 Stabilità <strong>di</strong> Crank-Nicolson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159<br />

10.8.7 Sulla stabilità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159<br />

10.9 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />

11 Introduzione al FORTRAN 77 161<br />

11.1 Introduzione alla programmazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162<br />

11.2 FORTRAN: FORmula TRANslator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162<br />

11.3 Problemi e Algoritmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163<br />

11.4 Elementi <strong>di</strong> un linguaggio <strong>di</strong> programmazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />

11.5 Prime regole sul FORTRAN77 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />

11.6 Le variabili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165<br />

11.7 I tipi <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />

11.8 Espressioni aritmetiche e funzioni elementari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />

11.9 I pre<strong>di</strong>cati elementari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167<br />

11.10 Struttura alternativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170<br />

11.11 Programma sul metodo <strong>di</strong> punto fisso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172<br />

11.12 I sottoprogrammi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />

11.12.1 Le functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />

11.12.2 Le subroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178<br />

11.13 Il formato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180<br />

11.14 Files <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182<br />

11.15 Vettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182<br />

11.16 Ciclo do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183<br />

v


INDICE<br />

11.16.1 I vettori nei sottoprogrammi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184<br />

11.16.2 Leggere i dati <strong>di</strong> input da file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185<br />

11.17 Matrici in FORTRAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />

11.17.1 Le matrici nei sottoprogrammi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />

11.17.2 Parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189<br />

11.17.3 Memorizzazione delle matrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190<br />

11.17.4 Un programma <strong>di</strong> esempio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191<br />

11.18 La formula dei trapezi in FORTRAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193<br />

11.19 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />

A Cenni su Gnuplot 201<br />

A.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201<br />

A.2 Grafici <strong>di</strong> funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201<br />

A.3 Salvare i grafici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205<br />

A.4 Grafici da files <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206<br />

A.5 Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208<br />

A.6 Print . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209<br />

Bibliografia 211<br />

vi


C A P I T O L O<br />

1<br />

STRUTTURA DELL’ELABORATORE<br />

I computer sono incre<strong>di</strong>bilmente<br />

veloci, accurati e stupi<strong>di</strong>. Gli uomini<br />

sono incre<strong>di</strong>bilmente lenti,<br />

inaccurati e intelligenti. L’insieme<br />

dei due costituisce una forza<br />

incalcolabile.<br />

Albert Einstein<br />

1.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />

1.2 La preistoria del computer: Babbage e Lovelace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

1.3 Gli albori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

1.4 Architettura del Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

1.5 Software e Sistema Operativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />

1.5.1 Per capire meglio il sistema operativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

1.6 Il file system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.7 Un po’ <strong>di</strong> storia sui sistemi operativi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.8 Lavorare in ambiente Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

1.9 E<strong>di</strong>tor <strong>di</strong> testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

1.1 Introduzione<br />

Se dobbiamo comprare un computer, abbiamo solo l’imbarazzo della scelta tra i tanti <strong>di</strong>sponibili sul<br />

mercato. Ma in base a quali criteri scegliamo un computer?<br />

Le caratteristiche fondamentali <strong>di</strong> un computer si possono riassumere in poche parole-chiave: processore,<br />

sistema operativo, memoria. Cosa significano esattamente? E, prima ancora, cosa significa<br />

Computer?<br />

1


1. STRUTTURA DELL’ELABORATORE<br />

Figura 1.1: Stralci <strong>di</strong> volantini pubblicitari per l’acquisto <strong>di</strong> un computer.<br />

Definizione 1.1.1<br />

Computer = elaboratore elettronico <strong>di</strong>gitale<br />

Dispositivo elettronico che elabora le informazioni, immesse sotto forma <strong>di</strong> dati<br />

numerici, secondo una sequenza <strong>di</strong> istruzioni preor<strong>di</strong>nate (programma).<br />

G Elaboratore: macchina capace <strong>di</strong> immagazzinare ed elaborare dati in base<br />

ad una serie <strong>di</strong> istruzioni (programmi) memorizzate sul computer<br />

G elettronico: utilizza componenti elettroniche per elaborare le informazioni<br />

G <strong>di</strong>gitale: elabora e memorizza segnali <strong>di</strong>gitali basati su cifre binarie: 0 e 1<br />

Hardware<br />

Software<br />

In generale, un computer esegue operazioni logiche e aritmetiche e ha una memoria per conservare i dati.<br />

Un programma contiene le informazioni relative alle operazioni da eseguire.<br />

Si definisce hardware la struttura fisica del computer cioè i i suoi componenti elettronici e i <strong>di</strong>spositivi<br />

fisici che lo compongono.<br />

Si chiama, invece, software l’insieme delle istruzioni (i programmi) che consentono all’hardware <strong>di</strong><br />

svolgere i propri compiti (per esempio, il sistema operativo – Windows, Linux, etc – è un tipo <strong>di</strong> software;<br />

programmi applicativi come Word, Excel, LaTex sono dei software).<br />

Attraverso un computer, elaboriamo dati (numeri, suoni, video, fotografie) in modo da ottenere informazioni<br />

(lettere, tabelle, risultati <strong>di</strong> proce<strong>di</strong>menti numerici. . . ). Alcune <strong>di</strong> queste informazioni possono<br />

<strong>di</strong>ventare dati da elaborare <strong>di</strong> nuovo al computer.<br />

1.2 La preistoria del computer: Babbage e Lovelace<br />

Charles<br />

Babbage<br />

La seconda metà del <strong>di</strong>ciannovesimo secolo fu un tempo <strong>di</strong> grande fermento in numerosi campi, dall’ingegneria<br />

ai trasporti, dalla comunicazione all’architettura... Furono scoperti nuovi materiali, la forza animale<br />

fu sostituita dalla forza motrice, le navi a vapore iniziarono a competere con quelle a vela, la rete ferroviaria<br />

si espanse sempre più, il telegrafo elettrico rivoluzionò le comunicazioni... In questo contesto, ingegneri, architetti,<br />

matematici, astronomi, marinai, banchieri, agenti assicurativi... – chiunque avesse a che fare con il<br />

calcolo – si basava su tavole <strong>di</strong> calcolo per eseguire i calcoli meno banali. Tuttavia, si sa, gli uomini possono<br />

sbagliare e il timore che su quelle tavole ci fossero <strong>degli</strong> errori era giustificato: un errore non trovato poteva<br />

<strong>di</strong>ventare un <strong>di</strong>sastro nelle numerose applicazioni in cui le tavole <strong>di</strong> calcolo venivano usate!<br />

Già nel 1812 Charles Babbage 1 era consapevole dell’inaccuratezza dei calcoli fatti dall’uomo. Nel suo<br />

lavoro, Babbage doveva verificare l’esattezza <strong>di</strong> tavole <strong>di</strong> calcolo che sarebbero state usate da banchieri come<br />

da marinai. Le navi avrebbero identificato la loro posizione in mare me<strong>di</strong>ante quelle tavole! Eliminare il<br />

rischio dell’errore umano <strong>di</strong>venne per lui un desiderio sempre più grande. Egli stesso scrisse che, mentre<br />

1 Charles Babbage (1791-1871), inventore e matematico inglese, è senza dubbio il primo ad avere avuto il concetto del moderno<br />

calcolatore.<br />

2


1.3. Gli albori<br />

era seduto nella stanza della Società Analitica, a Cambridge, lavorando, mezzo addormentato, su una tavola<br />

dei logaritmi, arrivò un altro membro della società che gli chiese cosa stesse sognando. E lui rispose : – Sto<br />

pensando che tutte queste tavole – riferendosi alle tavole dei logaritmi – potrebbero essere calcolate da una<br />

macchina!<br />

Nel 1821, Babbage e il suo amico e astronomo John Herschel stanno controllando delle tabelle calcolate<br />

a mano. Errore dopo errore, Babbage esclama : – Volesse Dio che questi calcoli venissero eseguiti da una<br />

macchina a vapore!<br />

Il suo desiderio <strong>di</strong> creare una macchina per eseguire calcoli si concretizzò in due progetti, quello della<br />

Macchina alle Differenze e quello della Macchina Analitica 2 . La Macchina alle Differenze doveva calcolare<br />

in modo automatico funzioni polinomiali ma non venne mai completata per il suo costo eccessivamente<br />

elevato. La Macchina Analitica, invece, doveva essere una macchina <strong>di</strong> calcolo programmabile, e si può considerare<br />

come la prima idea del moderno computer. Anche questo progetto, tuttavia, rimase incompiuto.<br />

Solo nel 2002 è stato possibile costruire una macchina che rispondesse al progetto <strong>di</strong> Babbage.<br />

Nel 1833, Babbage incontrò Ada Lovelace 3 , figlia del famoso poeta Lord Byron. Lovelace, appena <strong>di</strong>ciassettenne,<br />

aveva parecchie conoscenze matematiche, inusuali per l’epoca, e si entusiasmò talmente tanto per<br />

il progetto <strong>di</strong> Babbage, da intuire altre potenzialità della macchina stessa, come la capacità dei numeri <strong>di</strong><br />

poter rappresentare altre entità quali le lettere dell’alfabeto o le note musicali, e che dalla manipolazione dei<br />

numeri la macchina avrebbe esteso la propria potenza oltre il mondo della matematica. Sempre la Lovelace<br />

intuì che la soluzione dei problemi matematici si sarebbe effettuata attraverso delle procedure <strong>di</strong> calcolo<br />

(quelli che noi chiamiamo programmi).<br />

Alla luce <strong>degli</strong> sviluppi che si sono avuti nel ventesimo secolo, la visione <strong>di</strong> Babbage e della Lovelace<br />

appare profetica.<br />

Ada Lovelace<br />

1.3 Gli albori<br />

Il 1800 si chiude con una grande invenzione: nel 1896, Guglielmo Marconi inventa la ra<strong>di</strong>o. Il 1900 si apre<br />

con altre importanti invenzioni: il triodo, il registratore magnetico, la televisione, fino ad arrivare intorno alla<br />

metà del 1900 con il transistor (nel 1947) e il circuito integrato (nel 1958). La nuova tecnologia elettromeccanica<br />

ed elettronica si rivelò decisiva per lo sviluppo dei computer, grazie allo stu<strong>di</strong>o sistematico della teoria dei<br />

circuiti elettrici. Il più noto tra gli stu<strong>di</strong>osi <strong>di</strong> questa teoria fu l’americano Claude Shannon 4 . Il suo contributo<br />

fondamentale fu quello <strong>di</strong> elaborare un metodo sistematico per progettare reti logiche capaci <strong>di</strong> eseguire le<br />

operazioni logico-aritmetiche desiderate: detto più semplicemente, egli mostrò come trasformare una assegnata<br />

operazione matematica in un circuito elettrico costruito con interruttori e relè <strong>di</strong> commutazione (quelli<br />

usati nelle telecomunicazioni). Nel 1948, il suo articolo A Mathematical Theory of Communication pubblicato<br />

sulla rivista The Bell System Technical Journal getta le basi teoriche dell’informatica. Per prima volta<br />

viene usato il termine bit come abbreviazione <strong>di</strong> binary <strong>di</strong>git, termine suggeritogli dal chimico e statistico J.<br />

W. Tukey.<br />

Il lavoro <strong>di</strong> Shannon <strong>di</strong>ede l’avvio allo stu<strong>di</strong>o delle tecniche in<strong>di</strong>spensabili per progettare in modo<br />

sistematico tutti i circuiti logici <strong>di</strong> base necessari per realizzare i circuiti <strong>di</strong> calcolo dei futuri computer.<br />

Da un punto <strong>di</strong> vista propriamente ”pratico“ invece, la nascita e lo sviluppo dei calcolatori elettronici<br />

inizia nel 1938: il tedesco Konrad Zuse 5 costruisce Z1, una macchina costruita e pensata in maniera completamente<br />

meccanica, tutta da migliorare, ma che può essere considerata come il primo calcolatore. Zuse<br />

passa subito al progetto Z2, dove l’aritmetica meccanica è sostituita da relè elettromeccanici. L’inizio della<br />

seconda guerra mon<strong>di</strong>ale interrompe bruscamente il lavoro <strong>di</strong> Zuse, che viene chiamato alle armi, ma riesce<br />

2 Osserviamo che l’invenzione del telaio meccanico a schede, in cui il tipo <strong>di</strong> tessuto veniva scelto (o programmato) in base a delle<br />

schede inserite nella macchina, è un precursore del progetto <strong>di</strong> Babbage.<br />

3 Augusta Ada Lovelace (1815-1852) fu la figlia del famoso poeta Lord Byron. I genitori si separono subito dopo la sua nascita e<br />

la bambina crebbe insieme alla madre (Lord Byron partì dall’Inghilterra senza farvi più ritorno e morì in Grecia quando Ada aveva otto<br />

anni). Poichè la madre era appassionata <strong>di</strong> matematica e non voleva che la figlia seguisse la strada del padre, incoraggiò la figlia in questa<br />

<strong>di</strong>rezione, impartendole un’istruzione legata alla matematica e alla musica. Nel 1835 sposò William King, <strong>di</strong> <strong>di</strong>eci anni più anziano. Nel<br />

1838 il marito ricevette il titolo nobiliare <strong>di</strong> Conte <strong>di</strong> Lovelace. Ebbero tre figli. La Lovelace morì <strong>di</strong> cancro a soli 37 anni.<br />

4 Claude Shannon (1916-2002) fu fisico e matematico del MIT.<br />

5 Konrad Zuse, ingegnere civile (1910-1995).<br />

3


1. STRUTTURA DELL’ELABORATORE<br />

von<br />

Neumann<br />

a persuadere l’Istituto <strong>di</strong> Ricerca Aero<strong>di</strong>namica del Terzo Reich a continuare i suoi stu<strong>di</strong>. Completa quin<strong>di</strong> la<br />

costruzione dello Z2 e inizia a lavorare sullo Z3, che è il primo computer che Zuse costruisce per essere usato<br />

e non per verificare le proprie idee. Lo Z3 ha non solo l’unità aritmetica ma anche la memoria realizzata con<br />

relè elettromeccanici, ben 2600. Z3 fu la prima macchina <strong>di</strong> calcolo programmabile e venne usata dall’industria<br />

aerea per risolvere sistemi <strong>di</strong> equazioni e altri sistemi matematici ricavati da problemi <strong>di</strong> vibrazione<br />

<strong>degli</strong> apparecchi aerei messi sotto stress.<br />

Quando Zuse propose <strong>di</strong> passare all’uso <strong>di</strong> un computer basato su valvole elettroniche, la proposta fu<br />

respinta perchè i tedeschi si consideravano così vicini alla vittoria della guerra che ulteriori sforzi nella ricerca<br />

non apparivano necessari.<br />

Il lavoro <strong>di</strong> Zuse, comunque, andò avanti con la costruzione dello Z4, <strong>di</strong> S1 e S2. E, soprattutto, fu<br />

completamente in<strong>di</strong>pendente dai lavori <strong>di</strong> John Eckert e John Mauchly negli Stati Uniti e <strong>di</strong> A. Turing in<br />

Inghilterra.<br />

In Inghilterrra, Turing 6 si occupò <strong>di</strong> problematiche riguardanti un macchina <strong>di</strong> calcolo <strong>di</strong>gitale astratta,<br />

con una memoria senza limiti, mentre negli USA Eckert e Mauchly 7 costruirono l’ENIAC (Electronic Integrator<br />

and Computer). L’ENIAC fu costruito, con progetto <strong>di</strong> Eckert, in piena seconda guerra mon<strong>di</strong>ale, a<br />

partire dal 1943, presso il Ballistic Research Laboratory e fu completato nel febbraio del 1946. La macchina<br />

era pensata per compiere operazioni <strong>di</strong> carattere generale, ma fu costruita con lo scopo preciso <strong>di</strong> compilare<br />

tabelle per le traiettorie <strong>di</strong> bombe. L’ENIAC conteneva circa 18 . 000 valvole termoioniche e misurava circa 2<br />

metri e mezzo <strong>di</strong> altezza per 24 metri <strong>di</strong> lunghezza! La macchina era più <strong>di</strong> mille volte veloce <strong>di</strong> tutti i predecessori<br />

elettromeccanici costruiti fino a quel momento e poteva eseguire 5000 ad<strong>di</strong>zioni al secondo. Le sue<br />

operazioni erano controllate da un programma che veniva inserito dall’esterno me<strong>di</strong>ante nastri perforati.<br />

Intanto, nel 1944 aveva iniziato a collaborare nella costruzione dell’ENIAC, John von Neumann 8 . Egli si<br />

accorse che l’architettura della macchina andava rivista e che la programmazione del computer me<strong>di</strong>ante un<br />

numero enorme <strong>di</strong> cavi e interruttori rendeva lenta e poco flessibile la programmazione stessa. Sostenne,<br />

quin<strong>di</strong>, che il programma non dovesse essere rigidamente pre<strong>di</strong>sposto nell’hardware tramite interruttori e<br />

cavi e neanche letto me<strong>di</strong>ante nastri perforati, ma risiedesse in una memoria su cui poter scrivere e accedere<br />

velocemente insieme ai dati da elaborare. Von Neumann per primo descrisse l’architettura dei calcolatori in<br />

termini logico-funzionale, secondo uno schema astratto non legato ai <strong>di</strong>spositivi fisici utilizzati per le varie<br />

operazioni. E il suo schema, sostanzialmente invariato, è l’architettura adottata dai calcolatori dei nostri<br />

giorni!<br />

Prima <strong>di</strong> von Neumann, il calcolatore veniva controllato me<strong>di</strong>ante programmi non mo<strong>di</strong>ficabili, registrati<br />

su nastro perforato o cablati in una configurazione <strong>di</strong> cavetti e interruttori. Con von Neumann si presenta<br />

un’architettura <strong>di</strong> riferimento precisa.<br />

Il primo calcolatore costruito seguendo l’architettura <strong>di</strong> von Neumann entrò in funzione nel 1948<br />

all’Università <strong>di</strong> Manchester e venne chiamato Manchester Mark I.<br />

Inizia, in tal modo, una nuova fase per i calcolatori: i programmi che controllano le operazioni da svolgere<br />

risiedono nella memoria del calcolatore insieme ai dati e possono essere mo<strong>di</strong>ficati <strong>di</strong>namicamente nel corso<br />

dell’elaborazione.<br />

Dal 1948 fino ai nostri giorni, lo sviluppo dei calcolatori elettronici ha avuto ritmi esponenziali: l’invenzione<br />

del circuito integrato (chip) alla fine <strong>degli</strong> anni cinquanta permise non solo <strong>di</strong> ridurre via via lo spazio<br />

fisico occupato dai computer ma anche <strong>di</strong> ottenere computer sempre più potenti tanto che, in due suoi lavori,<br />

del 1965 e del 1975, Gordon Moore 9 stabilì che il numero dei transistor inseribili su un chip raddoppia<br />

6 Alan Turing (1912-1954), matematico inglese, si interessò <strong>di</strong> logica matematica e <strong>di</strong> teoria della probabilità. Introdusse il concetto<br />

<strong>di</strong> una macchina astratta, detta macchina <strong>di</strong> Turing e pose questioni riguardanti l’intelligenza artificiale<br />

7 John Presper Eckert (1919-1995) e John William Mauchly (1907-1980) lavorarono a quello che si può considerare il vero primo<br />

calcolatore elettronico.<br />

8 John von Neumann (1903-1957) ungherese, stu<strong>di</strong>ò prima a Berlino, poi a Zurigo e infine a Budapest, dove ricevette il dottorato in<br />

matematica. Nel 1930 si trasferì alla Università <strong>di</strong> Princeton dove insegnò matematica. Il suo nome è legato a stu<strong>di</strong> in <strong>di</strong>versi settori:<br />

teoria dei giochi, matematica applicata, logica... Occupa un ruolo fondamentale nello sviluppo dei calcolatori elettronici. Ricevette<br />

numerosi premi e riconoscimenti in tutto il mondo.<br />

9 Gordon Moore è nato nel 1929 in California. Di lui basti ricordare che ha stabilito la legge <strong>di</strong> Moore, è co-fondatore della Intel<br />

Corporation e nel 2008 ha ricevuto la medaglia d’onore dell’IEEE per il suo pioneristico contributo nei processi dei circuiti integrati,<br />

e per la leadership nello sviluppo della memoria del MOS (semiconduttore metal-ossido), del microprocessore e dell’industria dei<br />

semiconduttori.<br />

4


1.4. Architettura del Computer<br />

approssimativamente ogni 24 mesi (legge <strong>di</strong> Moore). Nel 1971 tre ingegneri della Intel tra cui l’italiano Federico<br />

Faggin 10 inventarono il microprocessore, vale a <strong>di</strong>re un’intera CPU in un singolo circuito integrato:<br />

su una piastrina <strong>di</strong> 4 × 3 millimetri riuscirono a inserire 2250 transistor, che formavano il cuore <strong>di</strong> un intero<br />

computer: questo microprocessore fu chiamato Intel 4004 ed era capace <strong>di</strong> eseguire 60 . 000 operazioni al<br />

secondo.<br />

Se pensiamo che il processore Intel Pentium 4 introdotto nel 2000 ha 42 . 000 . 000 processori e l’Intel Itanium<br />

2 (con 9MB <strong>di</strong> cache) introdotto nel 2004 ha 592 . 000 . 000 transistors, ci accorgiamo <strong>di</strong> come la legge <strong>di</strong><br />

Moore, dal 1968 ad oggi, sia stata rispettata.<br />

1.4 Architettura del Computer<br />

L’architettura del Computer si può riassumere in tre unità:<br />

G il processore, che fornisce la capacità <strong>di</strong> elaborazione delle informazioni;<br />

G la memoria (centrale e <strong>di</strong> massa)<br />

G i <strong>di</strong>spositivi <strong>di</strong> input/output, che comunicano attraverso un canale detto BUS, costituito da un insieme<br />

<strong>di</strong> linee elettriche <strong>di</strong>gitali.<br />

Il processore è composto da blocchi con funzionalità <strong>di</strong>verse:<br />

G CPU (Central Processing Unit), unità centrale <strong>di</strong> elaborazione<br />

G cache<br />

G varie interfacce<br />

Se il processore è integrato su un unico chip prende il nome <strong>di</strong> microprocessore. Sia la CPU sia gran parte<br />

dei <strong>di</strong>spositivi che servono per l’attività della CPU sono realizzati con la tecnologia dei circuiti integrati, che<br />

possono essere <strong>di</strong>sposti in una singola scheda detta scheda madre. Questa scheda può essere dunque considerata<br />

la parte più importante del computer. La CPU esegue tutte le operazioni <strong>di</strong> elaborazione numerica e<br />

<strong>di</strong> controllo e rappresenta la parte centrale del computer.<br />

A sua volta si sud<strong>di</strong>vide in<br />

G unità logico-aritmetica (ALU), che svolge tutti i calcoli logici ed aritmetici;<br />

G unità floating-point (FPU) (Floating Point Unit), che consente <strong>di</strong> eseguire le operazioni su numeri reali;<br />

G unità <strong>di</strong> controllo (CU), che sovrintende all’elaborazione dei dati e alle operazioni <strong>di</strong> input e output;<br />

G registri, cioè memoria locale per memorizzare dati e lo stato <strong>di</strong> avanzamento delle istruzioni. Abbiamo,<br />

ad esempio, il registro <strong>di</strong> Program Counter, <strong>di</strong> Program Status Word, il registro Istruzioni, In<strong>di</strong>rizzi<br />

Memoria. . .<br />

Ogni elaboratore contiene un circuito <strong>di</strong> temporizzazione (clock) che genera un riferimento temporale<br />

comune per tutti gli elementi del sistema.<br />

Un ciclo-macchina è il tempo richiesto per svolgere un’operazione elementare (ed è un multiplo del periodo<br />

del clock). La velocità <strong>di</strong> elaborazione <strong>di</strong> un processore <strong>di</strong>pende dalla frequenza del clock. I processori<br />

10 Federico Faggin è nato nel 1940 a Vicenza e si è laureato in fisica all’Università <strong>di</strong> Padova. Nel 1968 si è trasferito prima a Palo Alto<br />

presso la Fairchild Semiconductor e poi nel 1970 nella Intel. Oggi è presidente e CEO (Chief Executive Officer) della Foveon.<br />

5


1. STRUTTURA DELL’ELABORATORE<br />

RAM<br />

attuali hanno valori <strong>di</strong> frequenza del clock che variano tra gli 8 MHz e i 3500 MHz (1 MHz = 1 milione <strong>di</strong><br />

istruzioni al secondo).<br />

La memoria serve per conservare le istruzioni da eseguire e per scrivere/leggere i dati elaborati. Si<br />

sud<strong>di</strong>vide in memoria principale e memoria secondaria.<br />

La memoria principale (o <strong>di</strong> lavoro) è la memoria in grado <strong>di</strong> conservare <strong>di</strong>namicamente dati e<br />

programmi che il processore sta utilizzando. A sua volta la memoria principale può essere <strong>di</strong> due tipi:<br />

G memoria <strong>di</strong> sola lettura (read-only memory): ROM. Viene scritta una volta per tutte dal produttore del<br />

sistema e contiene programmi e informazioni specifiche per il sistema; è utilizzata per memorizzare<br />

parametri <strong>di</strong> configurazione del sistema, utili all’avvio del computer;<br />

G memoria per scrittura-lettura (random access memory): RAM. Serve alla CPU per lavorare con i<br />

programmi inseriti dall’utente.<br />

Poichè la RAM conserva i dati solo fino a quando il computer rimane acceso (infatti è detta memoria<br />

<strong>di</strong> tipo volatile, perchè se ne perde il contenuto quando la macchina viene spenta), per conservare dati e<br />

programmi per tempi lunghi e a sistema spento, si utilizza la memoria <strong>di</strong> massa (o secondaria) – <strong>di</strong>schi<br />

come l’Hard Disk, CDROM, DVD, pendrive USB. . . .<br />

La RAM può essere pensata come una sequenza <strong>di</strong> celle (locazioni), ognuna identificata da un in<strong>di</strong>rizzo e<br />

capace <strong>di</strong> contenere informazioni binarie.<br />

L’unità minima in<strong>di</strong>rizzabile della memoria è detta parola (word) e può variare da macchina a macchina.<br />

In genere una parola vale un byte, cioè 8 bit.<br />

Bit è l’unità elementare <strong>di</strong> informazione.<br />

Per esempio: 0/1, sì/no.<br />

1 byte = 8 bit<br />

1 Kilobyte (KB) = 2 10 byte = 1024 byte (circa 10 3 )<br />

1 Megabyte (MB) = 2 20 byte (circa 10 6 )<br />

1 Gigabyte (GB) ≈ 10 9 byte (un miliardo <strong>di</strong> byte)<br />

1 Terabyte (TB) ≈ 10 12 byte (mille miliar<strong>di</strong> <strong>di</strong> byte)<br />

1 Petabyte (PB) ≈ 10 15 byte (un milione <strong>di</strong> miliar<strong>di</strong> <strong>di</strong> byte)<br />

Il computer scambia informazioni con il “mondo esterno” per mezzo delle periferiche <strong>di</strong> input/output<br />

(monitor, mouse, stampante, web-cam,...).<br />

Input è l’inserimento <strong>di</strong> dati nel computer per l’elaborazione. Output è il trasferimento <strong>di</strong> dati dal<br />

computer a <strong>di</strong>spositivi che permettono all’utente <strong>di</strong> vedere/ascoltare i risultati dell’elaborazione.<br />

1.5 Software e Sistema Operativo<br />

Un software è una sequenza <strong>di</strong> istruzioni per eseguire le varie elaborazioni sui dati.<br />

Ci sono <strong>di</strong>verse<br />

categorie <strong>di</strong> software: software per il sistema operativo, software <strong>di</strong> base, software <strong>di</strong> tipo applicativo.<br />

Il sistema operativo è costituito dall’insieme dei programmi essenziali per far funzionare la macchina.<br />

Esso utilizza piccoli programmi già presenti nel calcolatore per accedere ai singoli <strong>di</strong>spositivi fisici. Questi<br />

programmi prendono il nome <strong>di</strong> Device Driver e sono memorizzati nel BIOS (Basic Input Output System).<br />

Il BIOS si trova nella ROM del Computer.<br />

Il sistema operativo, da una parte, permette <strong>di</strong> rendere fruibile all’utente le molteplici risorse del computer<br />

(gestione della memoria, della stampante, della tastiera,...); dall’altra rende il computer uno strumento<br />

amichevole e utile per affrontare le molteplici attività che gli si richiedono.<br />

I compiti affidati al sistema operativo sono molteplici:<br />

G agire da interme<strong>di</strong>ario tra l’utente e l’harware del computer<br />

G controllare e coor<strong>di</strong>nare l’utilizzo dell’hardware tra i programmi applicativi<br />

G fornire gli strumenti per l’uso corretto delle risorse <strong>di</strong> tipo hardware e software del sistema<br />

G nascondere i dettagli legati alla gestione delle risorse del sistema.<br />

6


1.5. Software e Sistema Operativo<br />

I primi sistemi operativi iniziarono a vedersi intorno alla metà <strong>degli</strong> anni cinquanta quando si cominciò<br />

a in<strong>di</strong>viduare una serie <strong>di</strong> programmi standard <strong>di</strong> comune utilizzo in<strong>di</strong>pendenti dall’applicazione specifica<br />

richiesta al computer.<br />

L’evoluzione dei sistemi operativi ha influenzato anche lo sviluppo dell’hardware in quanto per supportare<br />

certe funzioni del sistema operativo sono necessari meccanismi hardware ad hoc (basti pensare alla<br />

gestione della memoria o delle interruzioni).<br />

I primi computer come lo Z3 <strong>di</strong> Zuse o l’ENIAC non avevano sistema operativo. Per inserire un programma<br />

(scritto in linguaggio macchina) bisognava azionare un gruppo <strong>di</strong> interruttori o mo<strong>di</strong>ficare collegamenti<br />

tramite opportuni cavi e spinotti. Ci ren<strong>di</strong>amo conto, quin<strong>di</strong>, <strong>di</strong> quanto fosse <strong>di</strong>fficile usare il computer per<br />

risolvere problemi me<strong>di</strong>ante l’esecuzione <strong>di</strong> un programma perchè oltre alla competenza specifica del problema<br />

da risolvere, si richiedeva una grande conoscenza tecnica della macchina su cui si doveva lavorare. Il<br />

programma doveva contenere non solo le istruzioni per la risoluzione del problema (per esempio un sistema<br />

<strong>di</strong> equazioni) ma anche le istruzioni per gestire le unità <strong>di</strong> input e output e delle altre periferiche collegate al<br />

computer. Infine, poteva essere eseguito un solo programma alla volta.<br />

Considerando gli elevatissimi costi per la realizzazione e la gestione dei primi computer, il calcolo automatico<br />

era una risorsa preziosa a <strong>di</strong>sposizione <strong>di</strong> pochi utenti. Tutto ciò portò ad un ripensamento del modo<br />

Cenni storici<br />

7


1. STRUTTURA DELL’ELABORATORE<br />

Sul software<br />

Memoria<br />

cache<br />

<strong>di</strong> utilizzare i computer e nacquero le prime idee <strong>di</strong> sistema operativo.<br />

Per prima cosa si pensò <strong>di</strong> creare delle librerie con le istruzioni necessarie per eseguire le operazioni<br />

più comuni legate alla gestione delle periferiche del computer (ingresso e uscita dei dati, accesso alla<br />

memoria,...).<br />

Ulteriori progressi si ebbero quando il sistema operativo iniziò a sfruttare anche il <strong>di</strong>sco fisso ed ebbe<br />

inizio la cosiddetta multiprogrammazione, in base alla quale nella memoria centrale venivano tenuti attivi<br />

contemporaneamente alcuni processi e i loro dati pronti per essere eseguiti. Ad ogni momento, uno solo <strong>di</strong><br />

questi processi veniva eseguito, tuttavia, quando il processo in esecuzione richiedeva un’istruzione <strong>di</strong> ingresso<br />

o <strong>di</strong> uscita, esso veniva sospeso attivando le unità periferiche necessarie per l’esecuzione dell’istruzione<br />

data. Questa tecnica richiedeva una elevata capacità della memoria centrale e solo pochi sistemi potevano<br />

funzionare in modo adeguato.<br />

Uno dei primi sistemi che iniziò ad utilizzare la multiprogrammazione fu il sistema OS/360 realizzato per<br />

i computer IBM 360. Questo sistema operativo fu importante per due motivi:<br />

G si cercò <strong>di</strong> realizzare un sistema operativo uniforme e compatibile per macchine IBM molto <strong>di</strong>verse tra<br />

loro per quando riguarda l’hardware sottostante: fino a quel momento ogni macchina aveva il proprio<br />

sistema operativo, che cambiava da macchina a macchina!<br />

G lo sviluppo <strong>di</strong> questo sistema operativo fu molto delicato e complesso e aprì lo stu<strong>di</strong>o delle<br />

problematiche relative all’ingegneria del software.<br />

Nonostante questi progressi, la multiprogrammazione non permetteva molta interattività tra utente e<br />

computer: <strong>di</strong> fatto l’utente consegnava i dati e il programma da eseguire (un pacco <strong>di</strong> schede perforate) all’operatore<br />

del computer e accedeva ai risultati dopo qualche ora se non ad<strong>di</strong>rittura dopo giorni e giorni, risultati<br />

che riceveva in forma cartacea ad esecuzione avvenuta (non c’era ancora il monitor per la visualizzazione<br />

su video dei risultati).<br />

Per risolvere questo tipo <strong>di</strong> problemi, l’uso delle schede fu sostituito da appositi terminali sempre collegati<br />

al computer e furono cambiate le modalità <strong>di</strong> gestione dell’unità centrale mo<strong>di</strong>ficando i sistemi operativi<br />

esistenti. Si arrivò all’interazione con il computer non più me<strong>di</strong>ante schede perforate bensì tramite tastierastampante<br />

o tramite tastiera-monitor.<br />

Alla fine del 1950 si introdusse il concetto <strong>di</strong> time-sharing che permetteva l’esecuzione <strong>di</strong> più processi<br />

in modo da poter sod<strong>di</strong>sfare le esigenze <strong>di</strong> più utenti contemporaneamente. Con il time-sharing si assegna,<br />

infatti, un piccolo intervallo <strong>di</strong> tempo a ciascun processo dando l’impressione che ciascun processo vada<br />

avanti parallelamente agli altri.<br />

Gli sviluppi del sistema operativo ottenuti da allora fino ad oggi si possono così riassumere: il sistema<br />

operativo fornisce funzioni <strong>di</strong> base per la gestione delle risorse, quali:<br />

G uso del processore (multitasking: l’uso della CPU è permesso ad un programma alla volta per brevi<br />

intervalli <strong>di</strong> tempo, quin<strong>di</strong> l’utente può eseguire più programmi contemporaneamente)<br />

G uso della memoria centrale (memoria virtuale)<br />

riconoscimento e gestione <strong>degli</strong> utenti (multiutenza)<br />

gestione delle periferiche (drivers)<br />

file system<br />

G interfaccia grafico.<br />

Il software <strong>di</strong> base (o general purpose) può avere funzioni varie: e<strong>di</strong>tor <strong>di</strong> testo, elaborazione <strong>di</strong> testi, fogli<br />

elettronici, posta elettronica, internet.<br />

Il software applicativo è costituito da programmi che hanno obiettivi specifici come intrattenimento,<br />

controllo <strong>di</strong> sistemi, progettazione (CAD), risoluzione <strong>di</strong> problemi matematici.<br />

Per migliorare le prestazioni <strong>di</strong> un computer si inserisce una memoria interme<strong>di</strong>a tra CPU e RAM, detta<br />

cache. Si trova all’interno del processore. È più veloce della RAM ma anche più costosa.<br />

1.5.1 Per capire meglio il sistema operativo<br />

Immaginiamo un ristorante con un capo-cuoco, il suo aiutante, una cucina, i camerieri e i clienti. I clienti<br />

scelgono un piatto dal menu, un cameriere prende l’or<strong>di</strong>ne e lo porta al capo-cuoco. Il capo-cuoco riceve<br />

l’or<strong>di</strong>ne e assegna al suo aiutante il compito <strong>di</strong> preparare il piatto. L’aiutante si de<strong>di</strong>cherà alla preparazione<br />

del piatto, compito che potrà richiedere più attività. Il capo-cuoco, intanto, supervisiona la preparazione dei<br />

piatti e gestisce le risorse (limitate) dei posti nel ristorante.<br />

8


1.6. Il file system<br />

G il capo-cuoco rappresenta il sistema operativo,<br />

G i clienti sono gli utenti,<br />

G le ricette associate ai piatti corrispondono ai programmi,<br />

G gli ingre<strong>di</strong>enti sono l’input del programma,<br />

G il piatto è l’output del programma,<br />

G il menu e il cameriere sono l’interfaccia verso il sistema operativo,<br />

G l’aiutante corrisponde al processore (CPU) (Se abbiamo più processori, ci sono più aiutanti),<br />

G la cucina corrisponde al computer,<br />

G pentole, fornelli etc, sono le parti che compongono il computer.<br />

L’aiuto cuoco, quin<strong>di</strong>, rappresenta la CPU mentre il tavolo da lavoro, su cui appoggia gli ingre<strong>di</strong>enti e la<br />

ricetta per preparare il piatto, rappresenta la memoria centrale. Prima <strong>di</strong> iniziare a lavorare, il cuoco deve<br />

svolgere alcune mansioni (sempre le stesse ogni volta: pulire il tavolo, controllare lo stato <strong>di</strong> pentole, tegami,<br />

coltelli. . . , ricevere le or<strong>di</strong>nazioni). Supponiamo che queste mansioni siano incise su un pezzo del tavolo da<br />

lavoro: corrispondono alla memoria ROM (quella che non può essere alterata). La RAM invece è la parte del<br />

tavolo che può essere alterata a piacimento (spostare pentole, tegami, ingre<strong>di</strong>enti).<br />

Quando il ristorante chiude, il tavolo deve essere pulito e sgombro altrimenti si rovina tutto quello che vi<br />

rimane, ad eccezione <strong>di</strong> ciò che vi è stato inciso. Perciò il cuoco conserva in <strong>di</strong>spense e frigoriferi i vari ingre<strong>di</strong>enti<br />

rimasti e gli utensili da lavoro: le <strong>di</strong>spense e i frigoriferi rappresentano i <strong>di</strong>schi (Hard Disk, CDROM,<br />

pen drive USB . . . ) per immagazzinare i dati.<br />

1.6 Il file system<br />

Il sistema operativo gestisce le informazioni su <strong>di</strong>spositivi <strong>di</strong> memoria secondaria (<strong>di</strong>schi).<br />

La gestione delle informazioni avviene me<strong>di</strong>ante file 11 . Un file costituisce un insieme <strong>di</strong> informazioni<br />

della stessa natura e logicamente correlate. In genere un file contiene un programma (programma sorgente<br />

o programma eseguibile), oppure una sequenza <strong>di</strong> dati.<br />

L’informazione è rappresentata da files, organizzati in maniera gerarchica (pensiamo ad una struttura ad<br />

albero) in <strong>di</strong>rectories (cartelle). Una <strong>di</strong>rectory è un file che svolge il ruolo <strong>di</strong> ”raccoglitore“.<br />

I files possono contenere dati (abbiamo i cosiddetti files <strong>di</strong> testo) oppure programmi (i files <strong>di</strong><br />

applicazioni).<br />

Un file è caratterizzato da:<br />

G posizione (path, o percorso): sequenza delle <strong>di</strong>rectories che portano al file<br />

<strong>di</strong>r1 / <strong>di</strong>r2 /.../.../<br />

G nome: in<strong>di</strong>vidua univocamente il file all’interno della cartella (o <strong>di</strong>rectory)<br />

G estensione: la parte del nome del file che segue l’ultimo punto . (dati.txt prova.f matrice.dat<br />

welcome.html foto.jpeg )<br />

G <strong>di</strong>mensione: quantità <strong>di</strong> informazione contenuta nel file<br />

G altre informazioni (data <strong>di</strong> creazione, data <strong>di</strong> ultima mo<strong>di</strong>fica, permessi <strong>di</strong> scrittura, lettura. . . )<br />

L’intera gestione dei file è a carico <strong>di</strong> un componente del sistema operativo detto file system.<br />

1.7 Un po’ <strong>di</strong> storia sui sistemi operativi<br />

Tra i numerosi sistemi operativi, il sistema Unix è quello che ha maggiormente influenzato questo settore<br />

dell’informatica. Il sistem Unix venne sviluppato sul finire <strong>degli</strong> anni sessanta nei laboratori della AT &<br />

T. La filosofia <strong>di</strong> base era <strong>di</strong> realizzare un sistema semplice rispetto agli altri in uso e adatto per la ricerca e<br />

lo sviluppo. La prima versione fu scritta in linguaggio Assembly e <strong>di</strong>pendeva dal tipo <strong>di</strong> macchina su cui si<br />

doveva applicare. Successivamente venne scritto in larga parte in un linguaggio <strong>di</strong> alto livello, il C, progettato<br />

11 File in inglese significa archivio. Il termine compare nei primi anni cinquanta e inizialmente si riferisce a un pacco <strong>di</strong> schede<br />

contenente informazioni omogenee. È il sistema operativo a realizzare il concetto astratto <strong>di</strong> file nella gestione dei <strong>di</strong>spositivi <strong>di</strong> memoria<br />

<strong>di</strong> massa.<br />

9


1. STRUTTURA DELL’ELABORATORE<br />

appositamente per il sistema Unix. In tal modo il sistema operativo <strong>di</strong>ventava facilmente portabile su macchine<br />

<strong>di</strong> tipo <strong>di</strong>verso senza <strong>di</strong>pendere eccessivamente dalle caratteristiche dell’hardware su cui veniva fatto<br />

funzionare. Diversamente dalle abitu<strong>di</strong>ni del tempo, l’azienda AT & T <strong>di</strong>stribuì Unix nelle università e rese<br />

<strong>di</strong>sponibili i co<strong>di</strong>ci sorgenti utilizzati per realizzarlo. Questo portò ad una sua ulteriore innovazione grazie a<br />

tutti i ricercatori delle università che iniziarono a sperimentarlo.<br />

Quando furono messi in commercio i primi microcomputer (a partire dal 1975), fu necessario sviluppare<br />

sistemi operativi appositamente progettati per sfruttare le poche risorse <strong>di</strong>sponibili essendo le risorse <strong>di</strong><br />

calcolo <strong>di</strong> tali macchine molto limitate. Inoltre, queste macchine erano pensate più per gli appassionati che<br />

per il personale tecnico esperto e quin<strong>di</strong> era importante creare un sistema operativo che fosse d’uso relativamente<br />

semplice. In questo campo si <strong>di</strong>stinsero Bill Gates e Paul Allen, che iniziarono la loro attività scrivendo<br />

il linguaggio <strong>di</strong> programmazione Basic per il micromputer Altair. Nel 1975 crearono una <strong>di</strong>tta... la Microsoft.<br />

Un altro microcomputer, popolare nei primi anni ottanta, fu l’Apple sviluppato da Steve Wozniak e Steve<br />

Jobs. Per questa macchina svilupparono un sistema più semplice ed efficiente <strong>di</strong> quello usato per l’Altair, che<br />

si ispirava vagamente al sistema Unix.<br />

I sistemi operativi per i microcomputer dovevano essere più semplici <strong>di</strong> quelli impiegati per i gran<strong>di</strong> computer,<br />

in quanto la macchina veniva utilizzata da un solo utente e le periferiche collegate erano poche e semplici.<br />

Il problema maggiore ero quello <strong>di</strong> gestire i file su floppy <strong>di</strong>sk (gli antenati dei CD-ROM e dei DVD, in<br />

uso fino ad una decina <strong>di</strong> anni fa) o su nastri magnetici e mettere a <strong>di</strong>sposizione dell’utente un linguaggio<br />

<strong>di</strong> programmazione semplice, come il Basic. Tuttavia, il confine tra linguaggio <strong>di</strong> programmazione e sistema<br />

operativo non era ancora ben definito e, una volta avviato, il sistema era pronto per ricevere sia coman<strong>di</strong> del<br />

sistema operativo, sia istruzioni in linguaggio Basic.<br />

I microcomputer iniziarono ad avere un grosso successo tanto che all’inizio <strong>degli</strong> anni ottanta, l’IBM pensò<br />

<strong>di</strong> entrare in questo settore (prima si era solo occupata <strong>di</strong> gran<strong>di</strong> computer e <strong>di</strong> software), introducendo<br />

il personal computer, IBM PC, realizzando in tal modo una macchina che servisse non solo per gli appassionati<br />

e per giocare (uno dei fattori che aveva determinato il successo dei microcomputer) ma anche come<br />

strumento <strong>di</strong> stu<strong>di</strong>o, per i professionisti e per la gestione <strong>di</strong> piccole aziende.<br />

L’IBM incaricò Bill Gates <strong>di</strong> realizzare un sistema operativo per il nuovo personal computer. Il successo<br />

dell’IBM PC portò al successo anche <strong>di</strong> Bill Gates: i profitti della Microsoft iniziarono a crescere in modo<br />

esponenziale. Il sistema realizzato dalla Microsoft prese il nome <strong>di</strong> MS-Dos e <strong>di</strong>venne il sistema operativo<br />

più <strong>di</strong>ffuso al mondo grazie alla standar<strong>di</strong>zzazione dei personal computer lanciato dall’IBM.<br />

Il sistema MS-Dos non era facile da usare perchè l’utente interagiva con il computer solo attraverso<br />

coman<strong>di</strong> testuali la cui sintassi non era così semplice da ricordare (qualche anno più tar<strong>di</strong> fu lanciata sul<br />

mercato una versione più amichevole).<br />

Nel 1984, invece, dalla Apple fu prodotto il personal computer Macintosh che adottava un tipo <strong>di</strong> interfaccia<br />

grafico progettato per interagire in modo semplice e intuitivo con l’utente. Il Macintosh utilizzava un<br />

interfaccia grafico chiamato GUI (Graphic User Interface) composto da icone, finestre, menù... Gli oggetti<br />

dell’ambiente operativo erano rappresentati con simboli grafici <strong>di</strong> facile intuizione senza dover comprendere<br />

a fondo tutti i tecnicismi informatici. L’interfaccia GUI non era un’invezione della Apple perchè era stata<br />

già sperimentata nel corso <strong>degli</strong> anni settanta dalla Xerox, che però non aveva intuito le potenzialità <strong>di</strong> questo<br />

lavoro, lasciandone invece la fortuna e il successo alla Apple che, insieme ad esso, introdusse il mouse.<br />

Ovviamente, queste novità furono molto apprezzate e la Microsoft, per colmare questa lacuna, lanciò un<br />

altro sistema operativo basato su interfaccia grafica: nel 1985 nacque il primo Windows 1.0 che trovò pochi<br />

consensi perchè troppo lento e instabile. Nel 1986, con la comparsa <strong>di</strong> nuovi microprocessori, il sistema<br />

Windows cominciò a funzionare in modo adeguato tanto che le versioni <strong>di</strong> Windows 3.1 e <strong>di</strong> Windows 95<br />

portarono al sopravvento del sistema operativo Windows rispetto al Macintosh.<br />

Accanto a questi sistemi operativi, e forse anche per ridurre lo strapotere della Microsoft, si deve vedere<br />

la strada percorsa da un informatico <strong>di</strong> Helsinki (data <strong>di</strong> nascita 1969), Linus Bene<strong>di</strong>ct Torvalds, che ha<br />

introdotto il sistema Linux.<br />

Durante gli stu<strong>di</strong> universitari, Torvalds si era interessato <strong>di</strong> sistemi operativi e aveva stu<strong>di</strong>ato una versione<br />

semplificata <strong>di</strong> Unix, chiamata Minix. Questo sistema poteva funzionare su personal computer e veniva<br />

<strong>di</strong>stributo con i programmi sorgenti <strong>di</strong>sponibili. Torvalds migliorò il sistema Minix, in modo da poterlo utilizzare<br />

come alternativa a Windows, nella logica <strong>di</strong> non realizzare profitti (cioè non <strong>di</strong>ventare milionario) ma<br />

<strong>di</strong> realizzare un sistema utilizzabile gratuitamente da tutti e migliorabile con il contributo <strong>di</strong> tutti (la filosofia<br />

10


1.8. Lavorare in ambiente Linux<br />

dell’open source). Nel 1991 fu completata la prima versione del sistema, che fu chiamata Linux e venne messa<br />

a <strong>di</strong>sposizione <strong>di</strong> tutti. Torvalds si riservò il compito <strong>di</strong> coor<strong>di</strong>nare i <strong>di</strong>versi miglioramenti via via introdotti<br />

dagli altri sviluppatori.<br />

Tra le tante <strong>di</strong>stribuzioni attualmente in uso ricor<strong>di</strong>amo: Debian, Ubuntu, Fedora, Gentoo, Slackware. . .<br />

Linux si è <strong>di</strong>mostrato e si <strong>di</strong>mostra tuttora un valido sistema operativo, affidabile, sicuro e <strong>di</strong> buone<br />

prestazioni, in grado <strong>di</strong> gestire situazioni multiutente e multitasking.<br />

Ed è il sistema operativo <strong>di</strong> riferimento del corso <strong>di</strong> <strong>Calcolo</strong> <strong>Numerico</strong>.<br />

1.8 Lavorare in ambiente Linux<br />

Una volta entrati nel sistema (tramite login e password), si apre l’ambiente grafico e <strong>di</strong> qui possiamo<br />

lavorare (per esempio, aprire una finestra <strong>di</strong> e<strong>di</strong>tor, lavorare in Office, navigare in Internet ....).<br />

Per aprire nuove <strong>di</strong>rectories (cartelle), per spostare files, per eseguire programmi FORTRAN, ... è bene<br />

lavorare tramite una finestra <strong>di</strong> terminale o shell.<br />

La finestra <strong>di</strong> terminale (shell) mostra il prompt dei coman<strong>di</strong>.<br />

Un esempio <strong>di</strong> prompt è la login dell’utente (ad esempio studente) + chiocciola + nome della macchina<br />

su cui si sta lavorando (ad esempio george) + attuale <strong>di</strong>rectory <strong>di</strong> lavoro (se non compare nessun nome, è<br />

perchè ci troviamo nella home <strong>di</strong>rectory, la <strong>di</strong>rectory principale dell’utente) + un simbolo (% o $, a seconda<br />

della macchina):<br />

studente@george:~ $<br />

Ve<strong>di</strong>amo ora alcuni coman<strong>di</strong> essenziali (coman<strong>di</strong> da scrivere dopo il prompt, in una finestra <strong>di</strong> terminale<br />

– dopo<strong>di</strong>chè si clicca il tasto <strong>di</strong> Invio):<br />

G ls mostra l’elenco dei files e delle <strong>di</strong>rectories contenuti nella <strong>di</strong>rectory attuale ( ls sta per list):<br />

Esempio:<br />

studente@george:~ $ ls<br />

Un volta cliccato Invio, compare l’elenco delle <strong>di</strong>rectories presenti nello spazio <strong>di</strong> lavoro <strong>di</strong>sponibile per<br />

l’utente studente sulla macchina george, ad esempio (i numeri a sinistra delle <strong>di</strong>rectories o files sono<br />

in<strong>di</strong>catori dello spazio che occupano in memoria):<br />

5 appunti/ 4 mail/<br />

2 calcolonumerico/ 4 movies/<br />

3 fortran/ 1 varie/<br />

3 foto/ 57 prova.pdf<br />

G Per cambiare <strong>di</strong>rectory, si deve <strong>di</strong>gitare cd nome-<strong>di</strong>rectory<br />

(cd sta per change <strong>di</strong>rectory). Esempio: per entrare nella <strong>di</strong>rectory foto, scriviamo<br />

studente@george:~ $ cd foto<br />

Una volta cliccato il tasto <strong>di</strong> Invio, si è entrati nella <strong>di</strong>rectory foto:<br />

studente@george:~/foto $<br />

Il comando cd .. fa tornare nella <strong>di</strong>rectory precedente.<br />

Per creare una nuova <strong>di</strong>rectory: mk<strong>di</strong>r nome<strong>di</strong>rectory (mk<strong>di</strong>r sta per make <strong>di</strong>rectory).<br />

Per copiare un file dentro una <strong>di</strong>rectory: cp nomefile nome<strong>di</strong>rectory (cp sta per copy).<br />

Per trasferire un file in una <strong>di</strong>rectory mv nomefile nome<strong>di</strong>rectory (mv sta per move).<br />

Per rinominare un file (o una <strong>di</strong>rectory): mv nomevecchio nomenuovo .<br />

Per cancellare un file si usa il comando rm nomefile.<br />

G Per cancellare una <strong>di</strong>rectory, dobbiamo prima cancellare tutti i files della <strong>di</strong>rectory e poi usare il<br />

comando rm<strong>di</strong>r nome<strong>di</strong>rectory.<br />

11


1. STRUTTURA DELL’ELABORATORE<br />

G Per sapere in quale <strong>di</strong>rectory ci troviamo, si usa il comando pwd. Esempio: siamo nella <strong>di</strong>rectory foto,<br />

che è una sotto<strong>di</strong>rectory della home <strong>di</strong> studente. Con il comando pwd si ha:<br />

studente@george:~/foto $ pwd<br />

studente@george:~/foto $ /home/studente/foto<br />

Esempio 1.8.1 Abbiamo due <strong>di</strong>rectory chiamate uno e due e il file prova.f nella <strong>di</strong>rectory uno.<br />

Vogliamo copiare il file dalla <strong>di</strong>rectory uno alla <strong>di</strong>rectory due.<br />

Se ci troviamo nella home, cioè nell’ambiente <strong>di</strong> partenza, dobbiamo scrivere<br />

cp uno/prova.f due<br />

studente@george:~ $ cp uno/prova.f due<br />

Se ora passiamo nella <strong>di</strong>rectory due e facciamo ls, vedremo il file prova.f<br />

studente@george:~ $ cd due<br />

studente@george:~/due $ ls<br />

total 1<br />

1 prova.f<br />

Se siamo nella <strong>di</strong>rectory uno, dobbiamo scrivere<br />

cp prova.f ../due per ottenere lo stesso risultato.<br />

Se siamo nella <strong>di</strong>rectory due, dobbiamo scrivere<br />

cp ../uno/prova.f . Il punto finale serve per copiare il file prova.f nella <strong>di</strong>rectory in cui ci<br />

troviamo.<br />

Con cp abbiamo due file identici, quello nella <strong>di</strong>rectory uno e quello copiato nella <strong>di</strong>rectory due.<br />

Possiamo anche scrivere cp prova.f prova2.f: in questo modo creiamo il file prova2.f nella<br />

stessa <strong>di</strong>rectory in cui si trova prova.f.<br />

Se vogliamo trasferire il file dalla <strong>di</strong>rectory uno alla <strong>di</strong>rectory due (in questo modo avremo solo un file<br />

alla fine del proce<strong>di</strong>mento), dobbiamo usare il comando mv.<br />

Riassumendo<br />

G ls : lista dei files e delle <strong>di</strong>rectory<br />

G cd : per cambiare <strong>di</strong>rectory<br />

G mk<strong>di</strong>r: per creare una nuova <strong>di</strong>rectory<br />

G cp: per copiare files<br />

G mv: per trasferire o rinominare files<br />

G rm: per cancellare files<br />

G rm<strong>di</strong>r: per cancellare <strong>di</strong>rectories<br />

1.9 E<strong>di</strong>tor <strong>di</strong> testo<br />

Se vogliamo scrivere su un file un documento <strong>di</strong> testo, abbiamo bisogno <strong>di</strong> un e<strong>di</strong>tor <strong>di</strong> testo. Sotto Linux<br />

ne troviamo <strong>di</strong>versi: vi, emacs, ke<strong>di</strong>t, ge<strong>di</strong>t, ne<strong>di</strong>t.... I più semplici da utilizzare sono ge<strong>di</strong>t e ne<strong>di</strong>t.<br />

Sotto Linux esiste anche il pacchetto Office (del tutto simile all’equivalente Microsoft) per scrivere<br />

documenti in word, creare tabelle, etc. . . . Anche il programma Gnumeric è molto utile per creare tabelle.<br />

Per visualizzare grafici, invece, c’è il pacchetto Gnuplot.<br />

12


C A P I T O L O<br />

2<br />

RICHIAMI DI ANALISI<br />

La teoria attrae la pratica come il<br />

magnete attrae il ferro.<br />

Carl Friedrich Gauss<br />

2.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

2.2 Identità trigonometriche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

2.3 Regole su funzione esponenziale e logaritmica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

2.4 Derivate e integrali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

2.5 Teoremi utili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

2.1 Introduzione<br />

Quando si descrivono teoremi, si danno definizioni o, semplicemente, si <strong>di</strong>scute <strong>di</strong> matematica, è<br />

abbastanza usuale prendere in prestito lettere dell’alfabeto greco.<br />

È importante, quin<strong>di</strong>, saperle riconoscere e chiamarle in maniera corretta:<br />

A α Alfa N ν Nu<br />

B β Beta Ξ ξ Xi<br />

Γ γ Gamma O o Omicron<br />

∆ δ Delta Π π Pi<br />

E ɛ Epsilon P ρ Rho<br />

Z ζ Zeta Σ σ Sigma<br />

H η Eta T τ Tau<br />

Θ θ Theta Υ υ Upsilon<br />

I ι Iota Φ φ Fi<br />

K κ Kappa X χ Chi<br />

Λ λ Lambda Ψ ψ Psi<br />

M µ Mu Ω ω Omega<br />

13


2. RICHIAMI DI ANALISI<br />

2.2 Identità trigonometriche<br />

Nel seguito introduciamo alcune formule trigonometriche, con la notazione:<br />

G sin(x) ≡ seno(x), cos(x) ≡ coseno(x),<br />

G tan(x) ≡ tangente(x) = sin(x)<br />

cos(x) , sec(x) ≡ secante(x) = 1<br />

cos(x) ,<br />

cos(−θ) = cos(θ)<br />

cos( π 2<br />

− θ) = sin(θ)<br />

sin(<br />

cos( π 2<br />

+ θ) = −sin(θ)<br />

sin(<br />

cos(π − θ) = −cos(θ)<br />

cos(π + θ) = −cos(θ)<br />

cos(θ + φ) = cos(θ)cos(φ) − sin(θ)sin(φ)<br />

sin(2θ) = 2sin(θ)cos(θ)<br />

sin 2 (θ) + cos 2 (θ) = 1<br />

sin(−θ) = −sin(θ)<br />

π<br />

2<br />

− θ) = cos(θ)<br />

π<br />

2<br />

+ θ) = cos(θ)<br />

sin(π − θ) = sin(θ)<br />

sin(π + θ) = −sin(θ)<br />

sin(θ + φ) = sin(θ)cos(φ) + cos(θ)sin(φ)<br />

cos(2θ) = cos 2 (θ) − sin 2 (θ)<br />

tan 2 (θ) + 1 = sec 2 (θ)<br />

2.3 Regole su funzione esponenziale e logaritmica<br />

Assumiano a,b ∈ R, con a > 0 e b > 0. Si ha:<br />

1 x = 1<br />

a x+y = a x a y<br />

a x y = (a x ) y<br />

a log a (x) = x a 0 = 1<br />

a x−y = a x /a y<br />

a x b x = (ab) x<br />

log a (x y) = log a (x) + log a (y)<br />

log a (x/y) = log a (x) − log a (y)<br />

log a (x y ) = y log a (x)<br />

log a (a x ) = x<br />

log b (x) = log a (x)<br />

log a (b)<br />

b x = a x log a (b)<br />

2.4 Derivate e integrali<br />

Siano f e g due funzioni <strong>di</strong>pendenti dalla variabile reale x mentre c ∈ R sia una costante. In<strong>di</strong>chiamo la<br />

derivata <strong>di</strong> f con il simbolo d f<br />

d x o me<strong>di</strong>ante f ′ . Si ha:<br />

d (c f )<br />

d x = c f ′ regola della costante<br />

d (f + g )<br />

= d f<br />

d x d x + d g<br />

d x<br />

regola della somma<br />

d (f /g )<br />

= f ′ g − f g ′<br />

d x g 2<br />

regola del quoziente<br />

d (f g )<br />

= f g ′ + f ′ g<br />

d x<br />

regola del prodotto<br />

d f r<br />

d x = r f r −1 f ′ regola della potenza<br />

Tra le regole <strong>di</strong> integrazione, invece, ricor<strong>di</strong>amo quella <strong>di</strong> integrazione per parti:<br />

∫<br />

∫<br />

f g ′ dx = f g − f ′ g dx<br />

14


2.5. Teoremi utili<br />

Diamo ora una tabella delle derivate e <strong>degli</strong> integrali delle funzioni più note (per gli integrali lasciamo<br />

fuori la costante <strong>di</strong> integrazione), e con la simbologia arcsin(x) ≡ arcoseno(x), arccos(x) ≡ arcocoseno(x),<br />

cot(x) ≡ cotangente (x), arctan(x) ≡ arcotangente(x), arccot(x) ≡, arcocotangente(x).<br />

f<br />

f f ′ f f ′<br />

1<br />

ln(x)<br />

e x<br />

e x<br />

x<br />

sin(x) cos(x) cos(x) −sin(x)<br />

1<br />

tan(x)<br />

cos 2 (x) (= 1<br />

sec2 (x)) cot(x) −<br />

sin 2 (x)<br />

1<br />

1<br />

1<br />

1<br />

tan(x)<br />

−cot(x)<br />

cos(x)<br />

cos(x)<br />

sin(x)<br />

sin(x)<br />

1<br />

1<br />

arcsin(x) arccos(x) − <br />

1 − x<br />

2<br />

1 − x<br />

2<br />

1<br />

arctan(x)<br />

1 + x 2 arccot(x) − 1<br />

1 + x 2<br />

x r x r +1<br />

∫<br />

f d x f<br />

∫<br />

f d x<br />

r + 1 (r ≠ 1) x−1 ln|x|<br />

e x e x ln|x| x ln|x| − x<br />

sin(x) −cos(x) cos(x) sin(x)<br />

tan(x)<br />

1<br />

ln| |<br />

cos(x)<br />

cot(x) ln|sin(x)|<br />

1<br />

cos(x)<br />

1<br />

ln|<br />

cos(x) + tan(x)| 1<br />

sin(x)<br />

1<br />

ln|<br />

sin(x) + cot(x)|<br />

1<br />

cos 2 (x)<br />

tan(x)<br />

1<br />

sin 2 (x)<br />

−cot(x)<br />

tan(x)<br />

cos(x)<br />

1<br />

cos(x)<br />

cot(x)<br />

sin(x)<br />

− 1<br />

sin(x)<br />

arcsin(x) x arcsin(x) + 1 − x 2 arccos(x) x arccos(x) − 1 − x 2<br />

arctan(x) x arctan(x) − 1 2 ln(1 + x2 ) arccot(x) xarccot(x) − 1 2 ln(1 + x2 )<br />

1<br />

<br />

1 − x<br />

2<br />

2.5 Teoremi utili<br />

arcsin(x)<br />

1<br />

1 + x 2 arctan(x)<br />

Richiamiamo, nel seguito, teoremi che trovano applicazione nel <strong>Calcolo</strong> <strong>Numerico</strong>. Per alcuni <strong>di</strong>amo<br />

anche la <strong>di</strong>mostrazione.<br />

Utilizzeremo, inoltre, le seguenti notazioni per funzioni <strong>di</strong> una sola variabile definite in un insieme X ⊂ R.<br />

L’insieme delle funzioni continue in X verrà denotato con il simbolo C (X ). L’insieme delle funzioni continue<br />

in X , che hanno le prime n derivate pure esse continue, sarà in<strong>di</strong>cato con C n (X ).<br />

Notazioni<br />

usate per le<br />

funzioni<br />

continue<br />

15


2. RICHIAMI DI ANALISI<br />

Teorema 2.5.1 (Teorema <strong>di</strong> Rolle) a<br />

Sia f ∈ C ([a,b]) e <strong>di</strong>fferenziabile in ]a,b[.<br />

Se f (a) = f (b) = 0, allora esiste un punto ξ ∈]a,b[<br />

tale che f ′ (ξ) = 0<br />

a Michel Rolle (1652- 1719) fu un matematico francese. È<br />

conosciuto per il teorema che porta il suo nome. Si deve a lui<br />

la notazione della ra<strong>di</strong>ce n-sima per mezzo del simbolo n x.<br />

Teorema 2.5.2 (Teorema del Valor Me<strong>di</strong>o)<br />

Sia f ∈ C ([a,b]) e <strong>di</strong>fferenziabile in ]a,b[,<br />

allora esiste un punto ξ ∈]a,b[ tale che<br />

f ′ f (b) − f (a)<br />

(ξ) =<br />

b − a<br />

Teorema 2.5.3 (Teorema del Valore Interme<strong>di</strong>o)<br />

Sia f ∈ C ([a,b]) e sia K un valore compreso tra f (a)<br />

e f (b). Allora esiste almeno un punto ξ ∈]a,b[ tale<br />

che f (ξ) = K .<br />

Quin<strong>di</strong> per funzioni continue, un valore compreso tra i due estremi dell’insieme <strong>di</strong> definizione, è un valore<br />

assunto dalla funzione stessa (in uno o più punti).<br />

Come conseguenza <strong>di</strong> questo teorema, se f (a)f (b) < 0 (la funzione assume segno opposto agli estremi<br />

dell’intervallo [a,b]) allora esiste almeno un punto ξ tale che f (ξ) = 0, cioè esiste almeno una ra<strong>di</strong>ce<br />

dell’equazione f (x) = 0 nell’intervallo [a,b].<br />

Teorema 2.5.4 (Esistenza del punto fisso) Data una funzione g definita in [a,b], continua e tale che a ≤<br />

g (x) ≤ b per ogni x ∈ [a,b], allora g ammette almeno un punto fisso.<br />

Dimostrazione. Dire che una funzione g ammette almeno un punto fisso, vuol <strong>di</strong>re che esiste almeno<br />

un punto ξ nel suo insieme <strong>di</strong> definizione, tale che g (ξ) = ξ.<br />

Dalle ipotesi del teorema, i valori della funzione g sono contenuti nell’intervallo [a,b] e, in particolare<br />

a ≤ g (a) ≤ b e a ≤ g (b) ≤ b. Definiamo, perciò, la funzione continua Φ(x) me<strong>di</strong>ante la relazione<br />

Φ(x) = g (x) − x<br />

Allora Φ(a) = g (a) − a > 0 e Φ(b) = g (b) − b < 0. Per il Teorema del Valore Interme<strong>di</strong>o esiste almeno un punto<br />

ξ ∈]a,b[ tale che Φ(ξ) = 0, vale a <strong>di</strong>re g (ξ) − ξ = 0, cioè g (ξ) = ξ. Esiste almeno un punto fisso per la funzione<br />

g . ✔<br />

16


2.5. Teoremi utili<br />

Teorema 2.5.5 (Esistenza e unicità del punto fisso) Data una funzione g <strong>di</strong> classe C 1 in [a,b], con a ≤ g (x) ≤<br />

b per ogni x ∈ [a,b], e con |g ′ (x)| ≤ m < 1 per ogni x ∈ [a,b] allora esiste ed è unico il punto fisso della g in tale<br />

intervallo.<br />

Dimostrazione. L’esistenza <strong>di</strong> almeno un punto fisso è assicurata dal teorema precedente (le ipotesi del<br />

teorema precedente ci sono tutte). Supponiamo, allora, che esistano due punti fissi ξ e η, con ξ ≠ η, per la<br />

funzione g . Si ha<br />

|ξ − η| = |g (ξ) − g (η)|<br />

Applicando il teorema del Valor Me<strong>di</strong>o, esiste un punto c compreso tra ξ e η per cui<br />

|g (ξ) − g (η)| = |g ′ (c)(ξ − η)| ≤ |g ′ (c)||ξ − η|<br />

Ma per ipotesi |g ′ (c)| ≤ m < 1 da cui<br />

|ξ − η| ≤ m|ξ − η| < |ξ − η|<br />

Si arriva ad una contrad<strong>di</strong>zione. L’assurdo deriva dall’aver supposto ξ ≠ η. Quin<strong>di</strong> ξ = η e il punto fisso è<br />

unico. ✔<br />

Teorema 2.5.6 (Teorema del Valor Me<strong>di</strong>o del <strong>Calcolo</strong> Integrale) Se f ∈ C ([a,b]) e g è integrabile in [a,b] e<br />

g (x) non cambia segno in [a,b], allora esiste un punto ξ ∈]a,b[ tale che<br />

∫ b<br />

a<br />

f (x)g (x) d x = f (ξ)<br />

∫ b<br />

a<br />

g (x) d x<br />

Per g ≡ 1, questo teorema ci dà il valore me<strong>di</strong>o della funzione f sull’intervallo [a,b], dato da f (ξ) =<br />

1 ∫ b<br />

a<br />

b − a<br />

f (x) d x<br />

Teorema 2.5.7 (Teorema <strong>di</strong> Rolle generalizzato) Sia f ∈ C ([a,b]) n volte <strong>di</strong>fferenziabile in ]a,b[. Se f si annulla<br />

in n +1 punti <strong>di</strong>stinti x 0 , x 1 ,..., x n in ]a,b[, allora esiste un punto ξ ∈]a,b[ in cui la derivata n-sima della<br />

f si annulla: f (n) (ξ) = 0.<br />

Teorema 2.5.8 (Formula <strong>di</strong> Taylor) 1<br />

Sia f ∈ C 2 ([a,b]) e sia x 0 un punto dell’intervallo [a,b]. Allora, per qualunque x ∈ [a,b] si può scrivere:<br />

f (x) = f (x 0 ) + f ′ (x 0 )(x − x 0 ) + (x − x 0) 2<br />

f ′′ (ξ x )<br />

2<br />

dove ξ x è un opportuno punto <strong>di</strong> [a,b] che si trova sul segmento in<strong>di</strong>viduato da x 0 e x.<br />

La formula appena scritta si <strong>di</strong>ce formula <strong>di</strong> Taylor <strong>di</strong> centro x 0 nel punto x.<br />

La formula <strong>di</strong> Taylor appena scritta si può generalizzare se la funzione f è derivabile n +1 volte. Si ha così<br />

la formula polinomiale <strong>di</strong> Taylor <strong>di</strong> centro x 0 :<br />

dove<br />

f (x) = f (x 0 ) + f ′ (x 0 )(x − x 0 ) + f ′′ (x 0 )<br />

2!<br />

(x − x 0 ) 2 + ... + f (n) (x 0 )<br />

(x − x 0 ) n + R n<br />

n!<br />

R n (x) = f (n+1) (ξ x )<br />

(x − x 0 ) n+1<br />

(n + 1)!<br />

con ξ x un opportuno punto <strong>di</strong> [a,b] che si trova sul segmento in<strong>di</strong>viduato da x 0 e x.<br />

1 Brook Taylor (1685 - 1731) fu un matematico inglese che sviluppò quello che oggi è chiamato calcolo delle <strong>di</strong>fferenze finite.<br />

L’importanza del suo lavoro e, soprattutto, della formula conosciuta oggi con il suo nome, venne riconosciuta solo nel 1772 da Lagrange.<br />

17


C A P I T O L O<br />

3<br />

RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Tutti noi ogni giorno usiamo la<br />

matematica: per prevedere il tempo,<br />

per <strong>di</strong>re l’ora, per contare il denaro.<br />

Usiamo la matematica anche per<br />

analizzare i crimini, comprendere<br />

gli schemi, prevedere i<br />

comportamenti. Usando i numeri,<br />

possiamo svelare i più gran<strong>di</strong><br />

misteri della vita!<br />

NUMB3RS<br />

3.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

3.2 Aritmetica <strong>di</strong> macchina . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

3.3 Conversione <strong>di</strong> base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

3.4 Rappresentazione IEEE dei numeri <strong>di</strong> macchina . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

3.5 Precisione numerica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

3.6 Propagazione <strong>degli</strong> errori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

3.7 Instabilità e malcon<strong>di</strong>zionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

3.7.1 Instabilità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

3.7.2 Malcon<strong>di</strong>zionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />

3.1 Introduzione<br />

Molte volte, si pensa che i risultati numerici ottenuti da un calcolatore elettronico, specie se sono ottenuti<br />

come output <strong>di</strong> un sofisticato software, non contengano errori e, se ne abbiano, siano da ritenersi trascurabili.<br />

In realtà, quando si esegue un programma al calcolatore, bisogna prima <strong>di</strong> tutto aver verificato che sia stato<br />

scritto correttamente (il programma deve, cioè, tradurre correttamente il problema matematico che si vuole<br />

risolvere). Inoltre, bisogna tener conto che i risultati numerici sono sempre affetti da un certo tipo <strong>di</strong> errore,<br />

che può essere, per esempio, <strong>di</strong> arrotondamento o <strong>di</strong> troncamento: π è un numero con infinite cifre decimali<br />

ma il calcolatore lo può vedere solo come un numero con finite cifre decimali..., molte formule non possono<br />

essere usate così come sono ma devono essere in qualche modo semplificate (basti pensare ad una somma <strong>di</strong><br />

infiniti termini). Non tenere conto <strong>di</strong> questi fattori può portare a risultati davvero <strong>di</strong>sastrosi, come può essere<br />

19


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

verificato andando a controllare la pagina web de<strong>di</strong>cata ai <strong>di</strong>sastri dovuti a uno scorretto calcolo numerico:<br />

http://www.ima.umn.edu/~arnold/<strong>di</strong>sasters/<strong>di</strong>sasters.html<br />

La pagina web è del prof. Douglas N. Arnold, dell’Università del Minnesota, e viene introdotta con la<br />

seguente frase (traducendo): Stai seguendo con attenzione il tuo corso <strong>di</strong> analisi numerica o <strong>di</strong> calcolo scientifico?<br />

Se no, potrebbe essere un caro errore. Nel seguito, ci sono esempi dalla vita reale <strong>di</strong> ciò che può succedere<br />

quando gli algoritmi numerici non sono applicati correttamente.<br />

Ve<strong>di</strong>amo alcuni <strong>di</strong> questi <strong>di</strong>sastri numerici.<br />

Esempio sul<br />

<strong>di</strong>sastro del<br />

missile<br />

Patriot<br />

L’esplosione<br />

dell’Ariane 5<br />

Il <strong>di</strong>sastro del<br />

Mars Climate<br />

Orbiter<br />

Il 25 febbraio 1991, durante la prima Guerra del Golfo, un missile Patriot fallì l’intercettazione <strong>di</strong> un<br />

missile Scud iracheno. Questo errore costò la vita <strong>di</strong> 28 soldati, un centinaio <strong>di</strong> feriti e la <strong>di</strong>struzione <strong>di</strong><br />

un capannone americano. La causa del <strong>di</strong>sastro fu dovuto ad errori <strong>di</strong> arrotondamento nel sistema operativo<br />

del Patriot: ad ogni secondo che passava si introduceva un ritardo infinitesimo che comportava un<br />

errore nella valutazione della traiettoria del missile Scud. Col passare delle ore il ritardo accumulato fu<br />

tale da far intercettare una posizione del tutto <strong>di</strong>versa da quella in cui si trovava il missile da abbattere.<br />

Difatti, il computer usato per controllare il missile Patriot era basato su<br />

un’aritmetica a 24 bit. Per i calcoli, il tempo veniva registrato dall’orologio<br />

interno del sistema in decine <strong>di</strong> secon<strong>di</strong> e successivamente moltiplicato<br />

per 1/10 per ottenere i secon<strong>di</strong>, utilizzando 24 bit in virgola fissa. Il<br />

numero 1/10 in base 2 ha infinite cifre decimali: la sua espansione binaria<br />

è infatti 0.0001100110011001100110011001100.... In 24 bit esso veniva<br />

registrato come 0.00011001100110011001100 introducendo un errore<br />

<strong>di</strong> 0.0000000000000000000000011001100..., che, in base 10, significa<br />

circa 0.000000095.<br />

Gli errori <strong>di</strong> arrotondamento nella conversione del tempo<br />

causarono un errore nel calcolo della traiettoria: il tempo<br />

<strong>di</strong> 100 ore calcolato in secon<strong>di</strong> <strong>di</strong>ede il valore 359999.6567<br />

Figura 3.1: Il <strong>di</strong>sastro del missile invece <strong>di</strong> 360000, un errore <strong>di</strong> 0.3433 secon<strong>di</strong> che portò<br />

Patriot<br />

il Patriot 687 metri fuori della traiettoria del missile Scud!<br />

Il 4 giugno 1996, dopo una spesa <strong>di</strong> 7 miliar<strong>di</strong> <strong>di</strong> dollari, e dopo appena 40<br />

secon<strong>di</strong> dal suo lancio, esplose il razzo Ariane 5, nella Guiana Francese. Il razzo<br />

e il suo carico erano valutati per oltre 500 milioni <strong>di</strong> dollari. Perciò il costo<br />

totale della missione era stato <strong>di</strong> oltre 7 miliar<strong>di</strong> e mezzo <strong>di</strong> dollari. Fu scoperto<br />

che l’errore era nel software e, in particolare, nella componente del Sistema <strong>di</strong><br />

Riferimento Inerziale, che era stato preso dal software dell’Ariane 4. Certe parti<br />

del software dell’Ariane 5 erano state aggiornate rispetto al software dell’Ariane<br />

4, ma non si era aggiornato quanto preso dal software dell’Ariane 4.<br />

In particolare, il fallimento dell’Ariane 5 è dovuto ad un errore <strong>di</strong> conversione<br />

da un sistema a 64 bit a virgola mobile ad uno a 16 bit a virgola<br />

fissa.<br />

La velocità orizzontale del razzo rispetto alla piattaforma misurato in 64 bit<br />

era un numero più grande del massimo consentito nell’aritmetica a 16 bit. Si<br />

ebbe quin<strong>di</strong> un errore <strong>di</strong> overflow che causò l’arresto del software <strong>di</strong> controllo<br />

del volo 37 secon<strong>di</strong> dopo il lancio del razzo. Dopo 3 secon<strong>di</strong> il razzo si <strong>di</strong>strusse.<br />

Figura 3.2: L’esplosione <strong>di</strong><br />

Ariane 5<br />

Il <strong>di</strong>sastro, invece, del veicolo spaziale della missione Mars Climate Orbiter<br />

non si trova sulla pagina web del prof. Douglas, ma i dettagli della storia si possono<br />

trovare, ad esempio, sul sito http://marsprogram.jpl.nasa.gov/<br />

msp98/orbiter.<br />

Il 23 settembre 1999 si perdono le tracce del veicolo spaziale<br />

Mars Climate Orbiter. Gli obiettivi <strong>di</strong> questa missione della NASA erano sia <strong>di</strong> monitoraggio<br />

dei cambiamenti climatici sia <strong>di</strong> supporto per la missione Mars Polar Lander. I costi<br />

della Climate Orbiter e della Polar Lander erano <strong>di</strong> un totale <strong>di</strong> oltre 320 milioni <strong>di</strong> dollari.<br />

20


3.2. Aritmetica <strong>di</strong> macchina<br />

Figura 3.3: La Mars Climate Orbiter<br />

unità metriche!<br />

Si era ipotizzato <strong>di</strong> entrare nell’atmosfera <strong>di</strong> Marte ad una altezza<br />

<strong>di</strong> circa 150 km mentre il veicolo spaziale entrò ad una altezza<br />

<strong>di</strong> circa 60 km. Per un errore <strong>di</strong> conversione delle unità <strong>di</strong><br />

misura, il velivolo entrò nell’atmosfera con una traiettoria inferiore<br />

rispetto a quella pianificata. La velocità del mezzo era molto<br />

elevata e portò alla <strong>di</strong>struzione non solo del veicolo spaziale ma<br />

anche della stessa Polar Lander.<br />

Diversi furono i motivi che portarono al fallimento <strong>di</strong> questa<br />

missione. Il principale è dovuto all’errore nel trasferimento <strong>di</strong> informazioni<br />

tra il team che lavorava sul veicolo spaziale, che si trovava<br />

in Colorado e il team della missione <strong>di</strong> navigazione, che lavorava<br />

in California. Un team usava le unità inglesi (inches, feet,<br />

pounds) mentre l’altro usava le unità metriche. L’errore fu nella<br />

mancata conversione delle unità <strong>di</strong> misura tra unità inglesi e<br />

3.2 Aritmetica <strong>di</strong> macchina<br />

Un qualunque numero reale può essere rappresentato accuratamente da una sequenza <strong>di</strong> infinite cifre<br />

decimali.<br />

Ad esempio:<br />

(<br />

1<br />

0<br />

3 = 0.3333333... = 10 0 + 3<br />

10 1 + 3<br />

10 2 + 3<br />

10 3 + 3 )<br />

10 4 ... × 10 0<br />

( 3<br />

π = 3.14159265358979... =<br />

10 0 + 1<br />

10 1 + 4<br />

10 2 + 1<br />

10 3 + 5 )<br />

10 4 ... × 10 0<br />

Osserviamo che abbiamo scritto 1/3 e π in base 10, usando, quin<strong>di</strong>, le cifre 0,1,2,...,9 per poterli<br />

rappresentare.<br />

In genere, un numero reale x può essere rappresentato in base N come<br />

x = x m N m + x m−1 N m−1 + ... + x 1 N + x 0 + x −1 N −1 + x −2 N −2 + ... x −n N −n<br />

} {{ }<br />

parte intera<br />

} {{ }<br />

parte frazionaria<br />

dove m e n sono interi naturali e x k , k = m,m − 1,...,−n sono interi naturali compresi tra 0 e N − 1.<br />

In base 10, il numero 726.625, scritto in forma estesa è dato dalla forma:<br />

Esempio<br />

7 × 10 2 + 2 × 10 1 + 6 + 6 × 10 −1 + 2 × 10 −2 + 5 × 10 −3<br />

Tuttavia, i calcolatori hanno una memoria finita per poter rappresentare i numeri. Ciò significa che solo<br />

una sequenza finita <strong>di</strong> cifre possono essere usate. Inoltre, i calcolatori lavorano in base binaria, quin<strong>di</strong> ogni<br />

numero può essere rappresentato me<strong>di</strong>ante una sequenza <strong>di</strong> 0 e 1.<br />

Avendo in mente questi due fattori, possiamo ora capire la rappresentazione dei numeri al calcolatore,<br />

per cui ad ogni numero reale x è associato il numero <strong>di</strong> macchina denotato come f l(x), in rappresentazione<br />

floating point – virgola mobile.<br />

21


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

3.3 Conversione <strong>di</strong> base<br />

Nel seguito, non affronteremo gli aspetti teorici del passaggio da una base ad un altra per rappresentare<br />

lo stesso numero, ma vedremo l’implementazione pratica per convertire un numero dalla base 10 alla base 2<br />

e viceversa.<br />

Il passaggio <strong>di</strong> un numero dalla rappresentazione in base 2 alla rappresentazione in base 10 è semplice, in<br />

quanto si tratta <strong>di</strong> scrivere il numero come combinazione delle opportune potenze <strong>di</strong> 2. Ve<strong>di</strong>amo un esempio.<br />

Esempio 3.3.1 Sia 10001000.010 il numero scritto in base 2.<br />

Se lo scriviamo me<strong>di</strong>ante le potenze <strong>di</strong> 2 si ha:<br />

10001000.010 = 1 · 2 7 + 0 · 2 6 + 0 · 2 5 + 0 · 2 4 + 1 · 2 3 + 0 · 2 2 + 0 · 2 1 + 0 · 2 0 +<br />

} {{ }<br />

parte intera<br />

0 · 2 −1 + 1 · 2 −2 + 0 · 2 −2<br />

= 2 7 + 2 3 + 2 −2 = 128 + 8 + 0.25 = 136.25<br />

Questo è quin<strong>di</strong> lo stesso numero ma rappresentato in base 10.<br />

} {{ }<br />

parte frazionaria<br />

Il passaggio <strong>di</strong> un numero dalla rappresentazione in base 10 a quella in base 2 si effettua, invece, in due<br />

passi.<br />

GSi prende la parte intera del numero e la si <strong>di</strong>vide per 2: se il resto della <strong>di</strong>visione è zero, allora la corrispondente<br />

cifra binaria sarà 0; se il resto è <strong>di</strong>verso da zero, la corrispondente cifra binaria sarà 1. Si ripete<br />

la procedura sul risultato avuto dalla <strong>di</strong>visione, fino a quando si arriva a 1. In tal modo, calcoliamo le cifre<br />

binarie a partire da x 0 (il primo resto ottenuto) e andando avanti con in<strong>di</strong>ce crescente.<br />

GSi prende la parte frazionaria del numero e la si moltiplica per 2. Se il risultato dell’operazione ha la<br />

parte intera <strong>di</strong>versa da zero, allora la corrispondente cifra binaria vale 1, altrimenti vale 0. Si ripete la procedura<br />

sulla parte frazionaria del risultato appena ottenuto e si continua fino a quando si arriva allo zero (o se<br />

si vede che c’è una perio<strong>di</strong>cità nei risultati). Le cifre binarie vengono costruite da x −1 con in<strong>di</strong>ce decrescente.<br />

Esempio 3.3.2 Vogliamo convertire il numero 725.625 dalla base 10 nella base 2.<br />

Per la parte intera si ha:<br />

Per la parte decimale si ha :<br />

: 2 = quoziente resto<br />

.625 × 2 = 1.250 x<br />

725 362 1 x −1 = 1<br />

0<br />

.250 × 2 = 0.50 x<br />

362 181 0 x −2 = 0<br />

1<br />

.5 × 2 = 1.0 x<br />

181 90 1 x −3 = 1<br />

2<br />

.0 × 2 = 0.0<br />

90 45 0 x 3<br />

1 0 1 x 9<br />

45 22 1 x 4<br />

22 11 0 x 5<br />

11 5 1 x 6<br />

5 2 1 x 7<br />

2 1 0 x 8<br />

In base 2 il numero <strong>di</strong>venta 1011010101.101.<br />

22


3.4. Rappresentazione IEEE dei numeri <strong>di</strong> macchina<br />

Osserviamo che un numero può avere una rappresentazione finita in base 10 e infinita in base 2. Ve<strong>di</strong>amo<br />

in dettaglio un esempio:<br />

Esempio 3.3.3 Scriviamo il numero 11 , che è 1.1 in base 10, nella base 2.<br />

10<br />

Per la parte intera:<br />

Per la parte decimale:<br />

: 2 = quoziente resto<br />

.1 × 2 = 0.2 x<br />

1 0 1 x −1 = 0<br />

0<br />

.2 × 2 = 0.4 x −2 = 0<br />

.4 × 2 = 0.8 x −3 = 0<br />

.8 × 2 = 1.6 x −3 = 1<br />

.6 × 2 = 1.2 x −4 = 1<br />

.2 × 2 = 0.4 x −5 = 0<br />

.4 × 2 = 0.8 x −6 = 0<br />

.8 × 2 = 1.6 x −7 = 1<br />

.6 × 2 = 1.2 x −8 = 1<br />

.2 × 2 = 0.4 x −9 = 0<br />

Osserviamo che nella parte decimale si ripetono all’infinito le cifre 0011. Il numero in base 2 si scrive quin<strong>di</strong><br />

come: 1.00011<br />

} {{ } 0011 } {{ } ...<br />

3.4 Rappresentazione IEEE dei numeri <strong>di</strong> macchina<br />

Lo sviluppo dei calcolatori ha promosso e sviluppato l’uso del sistema binario, in cui ciascun numero è<br />

rappresentato da una successione <strong>di</strong> cifre binarie (0 e 1). Ma come avviene la rappresentazione <strong>di</strong> un numero<br />

nel calcolatore? Come rappresentare un numero a infinite cifre in maniera accurata utilizzando solo un<br />

numero finito <strong>di</strong> cifre?<br />

Lo standard IEEE (Institute of Electrical and Electronics Engineers), oggi utilizzato dalla maggior parte dei<br />

calcolatori, è dato dalla rappresentazione in virgola mobile (floating point). Esiste anche un tipo <strong>di</strong> rappresentazione<br />

in virgola fissa (fixed point), ma in genere è preferita quella in floating point, e noi ci soffermeremo<br />

solo su questa.<br />

Ripren<strong>di</strong>amo l’esempio proposto in Sezione 3.2, dove abbiamo scritto 1 in base 10 come<br />

3<br />

(<br />

1<br />

0<br />

3 = 0.3333333... = 10 0 + 3<br />

10 1 + 3<br />

10 2 + 3<br />

10 3 + 3 )<br />

10 4 ... × 10 0<br />

Questo è un esempio <strong>di</strong> numero scritto in virgola mobile: un qualunque numero x, in base 10, si può<br />

scrivere sotto la forma x = f 10 e dove f rappresenta la mantissa del numero e e è l’esponente (intero) della<br />

base con cui stiamo rappresentando il numero stesso, che dà informazioni sulla parte intera del numero.<br />

Ci sono <strong>di</strong>verse rappresentazioni in virgola mobile, tutte equivalenti tra loro. Per esempio 12.5 = 1.25 ×<br />

10 1 = 0.125×10 2 = 0.000125×10 5 . Si parla <strong>di</strong> virgola mobile normalizzata quando la mantissa ha una singola<br />

cifra <strong>di</strong> valore <strong>di</strong>verso da zero a sinistra della virgola, quin<strong>di</strong>, in base 2, la mantissa è del tipo 1.qual cosa.<br />

La rappresentazione in virgola mobile normalizzata in base 2 è quella utilizzata nello standard IEEE: i<br />

numeri si possono scrivere nella forma x = f 2 e . Al calcolatore, tuttavia, non possiamo rappresentare numeri<br />

con una mantissa a infinite cifre, perciò f = ±1.f −1 f −2 ... f −n e e = ±e Ne−1 e Ne−2 ...e 0 ., dove f −1 , f −2 ,..., f −n ,<br />

e e Ne−1 ,e Ne−2 ,...,e 0 sono le cifre che caratterizzano rispettivamente la mantissa e l’esponente del numero<br />

in virgola mobile normalizzata in base 2, e quin<strong>di</strong> possono valere 1 o 0. Abbiamo n cifre per la mantissa (in<br />

realtà sono n + 1 ma poichè la rappresentazione è normalizzata f 0 = 1) e Ne per l’esponente. Nel sistema<br />

binario, le cifre vengono chiamate bits ( binary <strong>di</strong>gits): quin<strong>di</strong> n bits sono riservati per la mantissa, Ne per<br />

l’esponente.<br />

23


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Un numero in floating point nella rappresentazione IEEE viene scritto come<br />

x = ±(1 + f −1 2 −1 + f −2 2 −2 + ... + f −n 2 −n ) × 2 e<br />

dove<br />

G 1+ f −1 2 −1 + f −2 2 −2 +...+ f −n 2 −n è la mantissa, normalizzata, cui sono riservati<br />

un numero n <strong>di</strong> bits,<br />

G e è la potenza della base 2 cui sono riservati un numero Ne <strong>di</strong> bits ed è<br />

limitato a variare in un determinato intervallo [L,U ].<br />

Il primo 1 della mantissa (che corrisponde a f 0 ) non viene messo in memoria ma c’è. La rappresentazione<br />

in virgola mobile può essere schematizzata nel modo seguente (s, e ed f rappresentano i bits riservati rispettivamente<br />

per il segno della mantissa, e per le cifre dell’esponente e della mantissa – ogni celletta può avere<br />

il valore 0 o 1):<br />

s e e e e e ··· ··· e f f f f f ··· ··· f<br />

}{{}<br />

segno<br />

} {{ }<br />

cifre dell’esponente<br />

} {{ }<br />

cifre della mantissa<br />

Abbiamo 1 bit riservato al segno (si ha 0 per il segno + e 1 per il segno −), un numero Ne <strong>di</strong> bits per<br />

l’esponente 2 e , e un numero n <strong>di</strong> bits per la mantissa.<br />

La scelta del numero <strong>di</strong> bits da riservare all’esponente e alla mantissa si basa su un compromesso tra la<br />

<strong>di</strong>mensione dell’esponente (e quin<strong>di</strong> il più piccolo e il più grande numero rappresentabile) e la <strong>di</strong>mensione<br />

della mantissa (e quin<strong>di</strong> la precisione del numero rappresantibile, più o meno cifre decimali).<br />

Nel sistema IEEE, la rappresentazione in singola precisione è a 32 bits mentre quella in doppia precisione<br />

è a 64 bits. La sud<strong>di</strong>visione dei bits tra esponente e mantissa viene ripartita nel modo seguente:<br />

s Ne n # totale bits<br />

Singola precisione 1 8 23 32<br />

Doppia precisione 1 11 52 64<br />

Gli esponenti possono essere sia positivi sia negativi ma si preferisce memorizzarli come interi positivi<br />

(senza segno). Abbiamo dunque bisogno <strong>di</strong> una tecnica che permetta <strong>di</strong> rappresentare esponenti negativi<br />

come interi positivi. La tecnica utilizzata nello standard IEEE è chiamata <strong>di</strong> biasing (<strong>di</strong>storsione): un numero<br />

positivo (detto bias) viene aggiunto all’esponente (sia esso positivo o negativo) in modo che il risultato finale<br />

sia sempre positivo. Ed è questo valore che viene memorizzato per rappresentare l’esponente. L’esponente<br />

viene quin<strong>di</strong> rappresentato in forma biased (parziale, influenzata da un altro numero): se e è l’esponente<br />

effettivo, noi memorizziamo il valore b + e dove b è il bias dato b = 0111...1<br />

} {{ }<br />

, vale a <strong>di</strong>re b = 1 + 2 + 2 2 + ... +<br />

Ne bits<br />

2 Ne−2 +0·2 Ne−1 = 1 − 2Ne−1<br />

= 2 Ne−1 −1 (si veda la nota per capire perchè si ha questo risultato nella somma).<br />

1 − 2<br />

Per trovare il limite superiore e inferiore entro cui può variare e, dobbiamo tener conto del fatto che, nella<br />

rappresentazione IEEE, due patterns <strong>di</strong> bits sono riservati per rappresentare numeri speciali quali lo zero,<br />

infinito e il Not-a-Number, precisamente 0000...0 e 1111...1.<br />

Quin<strong>di</strong>, b + e non può essere uguale nè a 0000...0, nè a 1111...1. Ciò significa che il massimo esponente<br />

che si può rappresentare è dato sottraendo a 1111...1 il valore 1 in base 2, cioè da 1111...1 − 0000...01 =<br />

1111...10.<br />

Si ha b + e ≤ 1111...10, o equivalentemente, 0111...1 + e ≤ 1111...10, da cui ricaviamo<br />

e ≤ 1111...10 − 0111...1 = 0111...1 = b<br />

.<br />

Il limite superiore U è proprio uguale a b.<br />

24


3.4. Rappresentazione IEEE dei numeri <strong>di</strong> macchina<br />

Per il limite inferiore abbiamo: 0000...0 < b + e cioè, equivalentemente,<br />

−b < e ⇔ −b + 0000...01 ≤ e.<br />

Osserviamo che siamo passati da una <strong>di</strong>seguaglianza in senso stretto (


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Consideriamo, ora, la rappresentazione dei numeri speciali.<br />

Per convenzione si pone uguale a 0 la rappresentazione che vede tutti zero sia nel segno, sia nell’esponente<br />

che nella mantissa (non <strong>di</strong>mentichiamo che il valore 1 della normalizzazione non è messo in memoria<br />

ma c’è e quin<strong>di</strong> non potremmo mai avere il valore 0, perciò lo si pone per convenzione).<br />

Per i valori ±∞ si considerano tutti 1 nello spazio de<strong>di</strong>cato all’esponente, tutti 0 nello spazio de<strong>di</strong>cato alla<br />

mantissa e 0 o 1 per il segno, a seconda che sia + o −∞.<br />

0 / 1 1 1 1 ... 1 1 0 0 0 ... 0 0<br />

}{{}<br />

s<br />

} {{ }<br />

esponente<br />

} {{ }<br />

mantissa<br />

I valori ±∞ si hanno se si fa una <strong>di</strong>visione per zero o si fa un calcolo che comporta overflow.<br />

Si ha invece il Not-a-Number (NaN) come risultato <strong>di</strong> operazioni non definite, come 0/0 o log0.<br />

A seconda della macchina si ha:<br />

NaNS, che produce un segnale <strong>di</strong> errore<br />

0 1 1 1 ... 1 1 0 1 1 ... 1 1<br />

}{{}<br />

s<br />

} {{ }<br />

esponente<br />

} {{ }<br />

mantissa<br />

NaNQ, con il quale il calcolo continua comunque...<br />

0 1 1 1 ... 1 1 1 0 0 ... 0 0<br />

}{{}<br />

s<br />

3.5 Precisione numerica<br />

} {{ }<br />

esponente<br />

} {{ }<br />

mantissa<br />

Un numero può avere una rappresentazione finita o infinita. Basti pensare al valore <strong>di</strong> π o a 2 in base 10.<br />

Abbiamo anche visto che un numero può avere rappresentazione finita in una base ma infinita in un’altra.<br />

Quando rappresentiamo un numero al calcolatore è possibile memorizzare solo un certo numero <strong>di</strong> cifre:<br />

in che modo lo esprimiamo?<br />

Per lasciare maggiore generalità al <strong>di</strong>scorso, consideriamo una base N .<br />

Sia x = ±( ∑ ∞<br />

k=0 x −k N −k )N p il numero esatto (può avere infinite cifre decimali e lo rappresentiamo come<br />

somma <strong>di</strong> infiniti termini).<br />

In floating-point esso sarà espresso come x ∗ = ±( ∑ t−1<br />

k=0 x∗ −k N −k )N p∗ , esso, cioè, sarà arrotondato (non<br />

possiamo avere infinite cifre decimali e, <strong>di</strong>fatti, la somma considera solo t termini).<br />

Ci sono due mo<strong>di</strong> per arrotondare un numero<br />

G troncamento: x ∗ = tr onc(x), dove p ∗ = p e x ∗ −k = x −k per k = 0,..., t − 1. Le altre cifre, x −t , x −t−1 ,...<br />

sono ignorate.<br />

G arrotondamento simmetrico: x ∗ = ar r (x) = tr onc(x + 1 2 N −t+1 N p ), aggiungiamo un’unità a x −t+1 se<br />

x −t ≥ N /2.<br />

L’errore assoluto |x − x ∗ | che si commette approssimando il numero x con x ∗ sarà 2<br />

⎧<br />

⎨N N p nel troncamento<br />

|x − x ∗ | ≤ 1<br />

⎩<br />

2 N 1−t N p nell’arrotondamento<br />

2 Evitiamo <strong>di</strong> effettuare tutti i passaggi che portano alle formule dell’errore assoluto e relativo, che sono il risultato <strong>di</strong> maggiorazioni<br />

<strong>di</strong> serie geometriche.<br />

26


3.6. Propagazione <strong>degli</strong> errori<br />

Per l’errore relativo |x − x∗ |<br />

, invece, si ha:<br />

|x|<br />

⎧<br />

|x − x ∗ |<br />

⎨N 1−t nel troncamento<br />

≤ 1<br />

|x| ⎩<br />

2 N 1−t nell’arrotondamento<br />

Il valore 1 2 N 1−t è il numero conosciuto come precisione <strong>di</strong> macchina.<br />

Nel caso della rappresentazione IEEE <strong>di</strong> un numero, si ha t−1 = n, (ricor<strong>di</strong>amo che nella rappresentazione<br />

IEEE si memorizza il numero normalizzato), da cui l’errore <strong>di</strong> arrotondamento relativo che si commette è<br />

|x − x ∗ |<br />

≤ 2 −(n+1) .<br />

|x|<br />

In singola precisione (n = 23), avremo<br />

Esempio<br />

|x − x ∗ |<br />

≤ 2 −24 ≈ 5.96 × 10 −8<br />

|x|<br />

ciò significa che avremo 8 cifre decimali corrette.<br />

In doppia precisione (n = 52) avremo<br />

|x − x ∗ |<br />

≤ 2 −53 ≈ 1.11 × 10 −16<br />

|x|<br />

ciò significa che avremo 16 cifre decimali corrette.<br />

3.6 Propagazione <strong>degli</strong> errori<br />

Prima <strong>di</strong> vedere come si propagano gli errori nelle operazioni elementari <strong>di</strong> moltiplicazione, <strong>di</strong>visione,<br />

ad<strong>di</strong>zione e sottrazione, ve<strong>di</strong>amo il concetto <strong>di</strong> cifre significative.<br />

Le cifre significative sono quelle che danno un’informazione effettiva sul valore del numero,<br />

in<strong>di</strong>pendentemente dalla parte esponenziale.<br />

Se scriviamo il numero in virgola mobile normalizzata, le cifre significative sono date dalle cifre della<br />

parte frazionaria. La bontà delle cifre va <strong>di</strong>minuendo procedendo da sinistra verso destra e questo può portare<br />

ad una per<strong>di</strong>ta <strong>di</strong> cifre significative, come possiamo vedere stu<strong>di</strong>ando la propagazione <strong>degli</strong> errori nelle<br />

operazioni elementari.<br />

Supponiamo che i numeri su cui lavoriamo siano affetti da errore (<strong>di</strong> arrotondamento), mentre le operazioni<br />

siano eseguite in modo esatto. In<strong>di</strong>chiamo con il simbolo o una qualunque delle operazioni elementari<br />

{×,/,+,−} e in<strong>di</strong>chiamo con f l(x) il numero x rappresentato in floating point e arrotondato, quin<strong>di</strong><br />

f l(x) = x(1 + e x ) dove e x è l’errore <strong>di</strong> arrotondamento.<br />

Allora f l(x o y) = f l(x)o f l(y) = x(1 + e x )o y(1 + e y ).<br />

G Moltiplicazione 3 x(1 + e x ) × y(1 + e y ) = (x × y)(1 + e x )(1 + e y ) ≈ (x × y)(1 + e x + e y )<br />

Quin<strong>di</strong> l’errore nel prodotto è dato da e x y = e x + e y<br />

G Divisione (con y ≠ 0) 4 x(1 + e x )<br />

y(1 + e y ) = x y (1 + e x)(1 − e y + e 2 y + ...) ≈ x y (1 + e x − e y )<br />

Si ha e x/y = e x − e y : gli errori si accumulano ad<strong>di</strong>tivamente<br />

3 Nei calcoli sono trascurabili le potenze maggiori o uguali a due per e x e e y<br />

4 1<br />

Possiamo scrivere = (1 − e y + e 2 y<br />

1 + e + ...) come risultato della formula polinomiale <strong>di</strong> Taylor della funzione f (e 1<br />

y ) = <strong>di</strong><br />

y 1 + e y<br />

centro 0.<br />

27


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Sulla cancellazione<br />

G Ad<strong>di</strong>zione (e, analogamente, Sottrazione)<br />

x(1 + e x ) + y(1 + e y ) = x + y + xe x + ye y = (x + y)(1 + x<br />

x + y e x +<br />

y<br />

x + y e y )<br />

L’errore è e x+y =<br />

x<br />

x + y e x +<br />

y<br />

x + y e y , una combinazione lineare che <strong>di</strong>pende da x e y.<br />

– x y > 0 =⇒ |e x+y | ≤ |e x | + |e y |<br />

– x y < 0 =⇒ |x|<br />

|x + y| e |y|<br />

possono essere molto gran<strong>di</strong> e, in tal caso, ci sarà un’amplificazione<br />

|x + y|<br />

notevole dell’errore. Si ha il fenomeno <strong>di</strong> cancellazione se non si fa attenzione al numero <strong>di</strong> cifre<br />

significative dei numeri che vengono sommati.<br />

Supponiamo <strong>di</strong> avere due numeri molto vicini tra loro, in cui le prime p + 2 cifre della parte frazionaria<br />

sono buone mentre le altre sono corrotte. Inoltre, le prime p cifre siano le stesse per entrambi i numeri<br />

(usiamo i simboli v v v v v e w w w w w w per esprimere le cifre corrotte):<br />

f l(x) = 1.d −1 d −2 ...d −p b −(p+1) b −(p+2) v v v v × 2 e<br />

f l(y) = 1.d −1 d −2 ...d −p b ′ −(p+1) b′ −(p+2) w w w w × 2e<br />

Quando an<strong>di</strong>amo a fare la sottrazione le prime p cifre buone si annullano. Da p + 2 cifre buone, ne abbiamo<br />

ora solo 2 e tutte le altre sono quelle corrotte. Con la normalizzazione il risultato <strong>di</strong>venta del tipo (ora qqqqq<br />

sono le cifre corrotte):<br />

f l(x − y) = 1.b −1 ′′ b′′ −2qqqqqq × 2e<br />

Ricor<strong>di</strong>amo, infine, che in aritmetica <strong>di</strong> macchina non valgono più la proprietà <strong>di</strong>stributiva o associativa<br />

del prodotto.<br />

Esempio 3.6.1 Sia x = 0.1103 e y = 0.009963. Se consideriamo un sistema decimale a 4 cifre,<br />

normalizzando i numeri, abbiamo x = 1.103 · 10 −1 e y = 9.963 · 10 −3<br />

Facendo la sottrazione <strong>di</strong> questi due numeri, abbiamo 1.103 · 10 −1 − 9.963 · 10 −3 = 0.1103 − 0.009963 =<br />

0.100337. Facendo l’arrotondamento a 4 cifre abbiamo il valore 1.0034 · 10 −1 .<br />

|0.100337 − 0.10034|<br />

L’errore relativo che commettiamo è: ≈ 2.99 × 10 −5 . Questo errore è minore della<br />

0.100337<br />

precisione <strong>di</strong> macchina (considerata la base 10 e le 4 cifre) 1 2 · 10−3 .<br />

Tuttavia, se non teniamo conto delle cifre significative ma tronchiamo i numeri alle prime 4 cifre, abbiamo<br />

la sottrazione <strong>di</strong> 0.1103 − 0.0099 = 0.1004.<br />

|0.100337 − 0.1004|<br />

Questa volta l’errore relativo è ≈ .63 × 10 −3 . L’errore è maggiore della precisione <strong>di</strong><br />

0.100337<br />

macchina.<br />

Esempio 3.6.2 Sia da risolvere l’equazione ax 2 +bx+c = 0 con a = 1, b = −56 e c = 1, quin<strong>di</strong> x 2 −56x+1 = 0,<br />

in una macchina a 4 cifre decimali (normalizzata).<br />

Applicando la formula x 1/2 = −b ± b 2 − 4ac<br />

abbiamo x 1/2 = 28 ± 783 = 28 ± 27.98213716 =<br />

{ 2a<br />

0.01786284073<br />

. L’arrotondamento delle due ra<strong>di</strong>ci in virgola mobile normalizzata a 4 cifre decimali<br />

55.98213716<br />

dà: x 1 = 1.7863 · 10 −2 e x 2 = 5.5982 · 10 1 .<br />

28


3.6. Propagazione <strong>degli</strong> errori<br />

Consideriamo ora la macchina a 4 cifre decimali per risolvere l’equazione:<br />

x 1 = 28 − 783 = 2.8 · 10 1 − 2.7982 · 10 1 = 0.0018 · 10 1 = 0.018 = 1.8 · 10 −2<br />

x 2 = 28 + 783 = 2.8 · 10 1 + 2.7982 · 10 1 = 5.5982 · 10 1<br />

La ra<strong>di</strong>ce x 2 è arrotondata correttamente, mentre la variabile x 1 no, per effetto della cancellazione.<br />

Per ricavare x 1 con l’arrotondamento corretto, applichiamo la formula x 1 x 2 = c/a, che, nel nostro caso, vale<br />

x 1 x 2 = 1 da cui x 1 = 1/x 2 = 1/(5.5982·10 1 ) = 1.7863·10 −2 . Abbiamo fatto un’operazione che non risente del<br />

fenomeno <strong>di</strong> cancellazione numerica!<br />

Esempio 3.6.3 Ve<strong>di</strong>amo come non valga più la relazione (a − b) 2 = a 2 − 2ab + b 2 .<br />

Sia a = 15.6 e b = 15.7 e la macchina sia a 3 cifre decimali (questa volta lavoriamo su una macchina non<br />

normalizzata, per cui scriveremo la parte frazionaria come 0.qual cosa. Ripetere poi l’esempio lavorando<br />

su una macchina a 2 cifre decimali normalizzata e su una macchina a 3 cifre decimali normalizzata. Cosa<br />

si osserva?)<br />

(a − b) = (a − b) ∗ + e a−b . Abbiamo (a − b) ∗ = 15.6 − 15.7 = −0.1.<br />

Quin<strong>di</strong> (a − b) 2 = +0.01 = 0.1 · 10 −1 .<br />

Consideriamo ora a 2 − 2ab + b 2 = 243.36 − 489.84 + 246.49 = 0.24336 · 10 3 − 0.48984 · 10 3 + 0.24649 · 10 3<br />

Considerando la macchina a 3 cifre decimali, abbiamo: 0.243 · 10 3 − 0.490 · 10 3 + 0.246 · 10 3 = −0.1 · 10 1<br />

I risultati sono completamente <strong>di</strong>versi!<br />

Esempio 3.6.4 Consideriamo il problema <strong>di</strong> approssimare la derivata della funzione f (x) = sin x nel punto<br />

x = 1.2.<br />

Supponiamo <strong>di</strong> non poter valutare <strong>di</strong>rettamente la derivata della f e <strong>di</strong> volerla approssimare applicando<br />

la formula polinomiale <strong>di</strong> Taylor:<br />

f (x 0 + h) = f (x 0 ) + h f ′ (x 0 ) + h2<br />

2 f ′′ (x 0 ) + h3<br />

6 f ′′′ (x 0 ) + h4<br />

24 f IV (x 0 ) + ...<br />

Allora<br />

f ′ (x 0 ) = f (x 0 + h) − f (x 0 )<br />

− ( h h<br />

2 f ′′ (x 0 ) + h2<br />

6 f ′′′ (x 0 ) + h3<br />

24 f IV (x 0 ) + ...)<br />

Approssimiamo, quin<strong>di</strong>, la f ′ (x 0 ) calcolando f (x 0 + h) − f (x 0 )<br />

.<br />

h<br />

L’errore, detto errore <strong>di</strong> <strong>di</strong>scretizzazione, che si commette è<br />

|f ′ (x 0 ) − f (x 0 + h) − f (x 0 )<br />

| = | h h<br />

2 f ′′ (x 0 ) + h2<br />

6 f ′′′ (x 0 ) + h3<br />

24 f IV (x 0 ) + ...|<br />

Supponendo <strong>di</strong> conoscere il valore della derivata seconda in x 0 , per piccoli valori <strong>di</strong> h possiamo dare una<br />

stima dell’errore <strong>di</strong> <strong>di</strong>scretizzazione,<br />

|f ′ (x 0 ) − f (x 0 + h) − f (x 0 )<br />

| ≈ h h<br />

2 |f ′′ (x 0 )|<br />

Ci aspettiamo, anche senza conoscere il valore <strong>di</strong> f ′′ (x 0 ) (purchè <strong>di</strong>verso da 0) che l’errore <strong>di</strong> <strong>di</strong>scretizzazione<br />

<strong>di</strong>minuisca proporzionalmente con il passo h, al decrescere <strong>di</strong> h.<br />

Nel nostro caso, in cui f (x) = sin(x), noi conosciamo il valore esatto della derivata in 1.2, cos(1.2) =<br />

0.362357754476674... e possiamo dunque calcolare l’errore esatto che commettiamo approssimando la<br />

derivata <strong>di</strong> sin x con la formula che abbiamo ricavato.<br />

29


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Per h = 0.1 non abbiamo un’approssimazione accurata. Ci aspettiamo che <strong>di</strong>minuendo il passo h l’errore<br />

che commettiamo <strong>di</strong>minuisca.<br />

Riportiamo gli errori della formula (in valore assoluto) e confrontiamoli con l’errore <strong>di</strong> <strong>di</strong>scretizzazione<br />

h<br />

2 |f ′′ (x 0 )| (i conti sono fatti in singola precisione):<br />

h errore<br />

h<br />

2 |f ′′ (x 0 )|<br />

1.e-1 4.7167e-2 4.6602e-2<br />

1.e-2 4.6662e-3 4.6602e-3<br />

1.e-3 4.6608e-4 4.6602e-4<br />

1.e-4 4.6603e-5 4.6602e-5<br />

1.e-5 4.6602e-6 4.6602e-6<br />

1.e-6 4.6597e-7 4.6602e-7<br />

L’errore commesso dall’algoritmo decresce come h e, in particolare, come h 2 |f ′′ (1.2)| = 0.46602h.<br />

Possiamo pensare <strong>di</strong> ottenere un’accuratezza grande quanto vogliamo a con<strong>di</strong>zione <strong>di</strong> prendere valori <strong>di</strong> h<br />

sempre più piccoli. In realtà, per valori <strong>di</strong> h molto piccoli, gli errori iniziano ad aumentare!<br />

h errore<br />

h<br />

2 |f ′′ (x 0 )|<br />

1.e-8 4.3611e-10 4.6602e-9<br />

1.e-9 5.5947e-8 4.6602e-10<br />

1.e-10 1.6697e-7 4.6602e-11<br />

1.e-11 4.6603e-5 4.6602e-12<br />

1.e-12 1.3006e-4 4.6602e-13<br />

1.e-13 4.2505e-4 4.6602e-14<br />

1.e-16 3.6236e-1 4.6602e-16<br />

1.e-18 3.6236e-1 4.6602e-19<br />

In Figura 3.4 ve<strong>di</strong>amo come la curva dell’errore inizialmente segue la retta descritta dall’errore <strong>di</strong> <strong>di</strong>scretizzazione<br />

ma poi si allontana da essa. Perchè questo <strong>di</strong>verso comportamento per valori <strong>di</strong> h molto piccoli?<br />

Dobbiamo tenere presente che l’errore che noi valutiamo non è semplicemente l’errore <strong>di</strong> <strong>di</strong>scretizzazione<br />

ma la somma dell’errore <strong>di</strong> <strong>di</strong>scretizzazione e dell’errore <strong>di</strong> arrotondamento! Per valori <strong>di</strong> h gran<strong>di</strong>, l’errore<br />

<strong>di</strong> <strong>di</strong>scretizzazione descresce al <strong>di</strong>minuire <strong>di</strong> h e domina sull’errore <strong>di</strong> arrotondamento. Ma quando l’errore<br />

<strong>di</strong> <strong>di</strong>scretizzazione <strong>di</strong>venta molto piccolo, per valori <strong>di</strong> h minori <strong>di</strong> 10 −8 , allora l’errore <strong>di</strong> arrotondamento<br />

inizia a dominare e ad aumentare sempre più al <strong>di</strong>minuire <strong>di</strong> h. Questo è un motivo per cui si deve cercare<br />

<strong>di</strong> far prevalere l’errore <strong>di</strong> <strong>di</strong>scretizzazione in un proce<strong>di</strong>mento numerico. Nell’errore <strong>di</strong> arrotondamento,<br />

per h via via più piccoli, si verifica un errore <strong>di</strong> cancellazione: f (x 0 + h) è praticamente uguale a f (x 0 ) per<br />

h molto piccoli! per cui l’errore che calcoliamo è |f ′ (x 0 ) − 0| = f ′ (x 0 ) = 0.3623577544....<br />

Una strategia per evitare la cancellazione è <strong>di</strong> scrivere <strong>di</strong>versamente la <strong>di</strong>fferenza f (x 0 +h)− f (x 0 ). Nel caso<br />

<strong>di</strong> f (x) = sin(x) ricorriamo alla formula trigonometrica per cui sin(φ) − sin(ψ) = 2cos( φ + ψ )sin( φ − ψ ).<br />

2 2<br />

Ve<strong>di</strong>amo come migliorano le cose inserendo nel grafico 3.5 anche la curva dell’errore che otteniamo utilizzando<br />

questa espressione trigonometrica. L’errore continua a <strong>di</strong>minuire anche quando la formula precedente<br />

dà un errore crescente. Sempre in Figura 3.5, e in riferimento alla formula “non buona”, abbiamo<br />

considerato la curva dell’errore <strong>di</strong> arrotondamento in modo da confrontare l’andamento effettivo dell’errore<br />

con un limite superiore teorico dell’errore computazionale totale dato dalla somme <strong>degli</strong> errori <strong>di</strong><br />

<strong>di</strong>scretizzazione e <strong>di</strong> arrotondamento.<br />

30


3.7. Instabilità e malcon<strong>di</strong>zionamento<br />

Figura 3.4: Errore <strong>di</strong> <strong>di</strong>scretizzazione ed effettivo approssimando f ′ (x 0 ) con il rapporto incrementale<br />

f (x 0 + h) − f (x 0 )<br />

.<br />

h<br />

La rappresentazione <strong>di</strong> f (x) è affetta da errore per cui avremo: f (x) = f ∗ (x)+e x . L’errore <strong>di</strong> arrotondamento<br />

è f (x 0 + h) − f (x 0 )<br />

= f ∗ (x 0 + h) − f ∗ (x 0 )<br />

+ e x 0 +h − e x0<br />

. Maggiorando e x con la precisione <strong>di</strong> macchina ɛ,<br />

h<br />

h<br />

h<br />

l’errore <strong>di</strong> arrotondamento è dato da 2ɛ/h: per h piccoli è l’errore che predomina!<br />

3.7 Instabilità e malcon<strong>di</strong>zionamento<br />

3.7.1 Instabilità<br />

In generale è impossibile evitare un accumulo lineare <strong>degli</strong> errori <strong>di</strong> arrotondamento durante un calcolo,<br />

ed è accettabile che ci sia una crescita lineare moderata, del tipo<br />

E n ≈ c 0 nE 0<br />

dove E n misura l’errore relativo dell’n-sima operazione dell’algoritmo 5 e c 0 sia una costante non molto<br />

grande.<br />

Se invece avviene una crescita <strong>di</strong> tipo esponenziale<br />

E n ≈ c n 1 E 0<br />

con c 1 > 1, allora l’algoritmo è instabile. Algoritmi del genere devono essere evitati!<br />

5 Per algoritmo inten<strong>di</strong>amo un proce<strong>di</strong>mento <strong>di</strong> calcolo. Per una definizione più approfon<strong>di</strong>ta si veda pag. 163 al Capitolo 11.<br />

31


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Figura 3.5: Errori <strong>di</strong> <strong>di</strong>scretizzazione, <strong>di</strong> arrotondamento, ed errore effettivo approssimando f ′ (x 0 ) con il<br />

rapporto incrementale f (x 0 + h) − f (x 0 )<br />

, ed errore che si commette applicando la formula trigonometrica<br />

h<br />

per cui f (x 0 + h) − f (x 0 ) = sin(x 0 + h) − sin(x 0 ) = 2cos(2x 0 + h/2)sin(h/2).<br />

Definizione 3.7.1 Un proce<strong>di</strong>mento numerico si <strong>di</strong>ce instabile se gli errori che vi sono associati non rimangono<br />

limitati ma crescono fino a <strong>di</strong>struggere completamente la soluzione.<br />

Esempio 3.7.1 Consideriamo l’integrale<br />

∫ 1<br />

x n<br />

y n =<br />

0 x + 10 dx<br />

per valori <strong>di</strong> n = 1,2,...,30. Osserviamo che, poichè x ∈ [0,1], la funzione integranda varia pure essa<br />

nell’intervallo [0,1] per cui 0 < y n < 1.<br />

Analiticamente, si ha:<br />

∫ 1<br />

x n + 10x n−1 ∫ 1<br />

x n−1 ∫<br />

(x + 10)<br />

1<br />

y n + 10y n−1 =<br />

dx =<br />

dx = x n−1 dx = 1<br />

0 x + 10<br />

0 x + 10<br />

0<br />

n<br />

Vale anche∫la relazione<br />

1<br />

1<br />

y 0 =<br />

dx = ln(11) − ln(10).<br />

0 x + 10<br />

Possiamo pensare, quin<strong>di</strong>, <strong>di</strong> calcolare numericamente il valore <strong>di</strong> y n attraverso il seguente algoritmo:<br />

1. valutare y 0 = ln(11) − ln(10)<br />

2. per n = 1,2,...,30 valutare y n = 1 n − 10y n−1<br />

Questa formula ricorsiva darebbe l’esatto valore se non fossero presenti errori <strong>di</strong> arrotondamento che ci<br />

allontanano completamente dalla soluzione vera. L’errore si moltiplica esponenzialmente.<br />

32


3.7. Instabilità e malcon<strong>di</strong>zionamento<br />

Infatti<br />

y 1 = 1 − 10y 0<br />

y 2 = 1 2 − 10(1 − 10y 0) = 1 2 − 10 + (−10)2 y 0<br />

y 3 = 1 3 − 10( 1 2 − 10 + 102 y 0 ) = −10 3 y 0 + cost ante<br />

. . . .<br />

y n = (−10) n y 0 + cost ante n<br />

L’algoritmo quin<strong>di</strong>, considerati gli errori <strong>di</strong> arrotondamento, presenta un errore E n con crescita <strong>di</strong> tipo<br />

esponenziale. Difatti otteniamo valori che via via si allontanano dall’intervallo <strong>di</strong> ammissibilità [0,1].<br />

I risultati che ricaviamo sono i seguenti (osserviamo che sono leggermente <strong>di</strong>versi a seconda dal linguaggio<br />

usato, proprio per effetto dell’instabilità).<br />

Da un programma in Fortran:<br />

Da un programma Matlab:<br />

n y n<br />

n y n<br />

0 9.5310e-2<br />

0 9.5310e-2<br />

1 4.6898e-2<br />

1 4.6898e-2<br />

2 3.1021e-2<br />

2 3.1018e-2<br />

3 2.3122e-2<br />

3 2.3154e-2<br />

4 1.8778e-2<br />

4 1.8465e-2<br />

... ....<br />

... ....<br />

7 -3.0229e-1<br />

7 1.1481-2<br />

8 3.1479e+0<br />

8 1.0194e-2<br />

9 -3.1368e+1<br />

9 9.1673e-3<br />

10 3.1378e+2<br />

10 8.3270e-3<br />

18 3.1377e+10<br />

18 -9.1694e+1<br />

27 -3.1377e+19<br />

27 -9.1699e+9<br />

30 3.1377e+22<br />

30 -9.1699e+13<br />

Se invece, consideriamo y n−1 = 1<br />

10 ( 1 n − y n), partendo da un valore <strong>di</strong> n molto grande e andando a ritroso,<br />

l’errore <strong>di</strong>minuisce. Perciò, dato un valore <strong>di</strong> accuratezza ɛ > 0 e fissato un intero n 1 è possibile determinare<br />

l’intero n 0 tale che, partendo da y n0 = 0 e andando a ritroso, gli integrali y n saranno valutati con un errore<br />

in valore assoluto minore <strong>di</strong> ɛ per 0 < n ≤ n 1 . Infatti:<br />

y n0 = 0<br />

y n0 −1 = 1 1<br />

10<br />

n 0<br />

y n0 −2 = 1<br />

10 ( 1<br />

n 0 − 1 − 1<br />

10<br />

. . .<br />

y n =<br />

1<br />

) =<br />

n 0<br />

1<br />

(−10) n 0−n n 0<br />

+ cost ante n0 −n<br />

1<br />

(−10) 2 n 0<br />

+ cost ante<br />

L’errore al passo n <strong>di</strong>pende, quin<strong>di</strong>, (in valore assoluto) da<br />

1<br />

10 n 0−n . 33


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Se richie<strong>di</strong>amo una tolleranza ɛ = 10 −6 , e fissiamo un valore n 1 , per calcolare n 0 dovrà essere<br />

1<br />

10 n 0−n 1<br />

< ɛ cioè 10 n 1−n 0<br />

< ɛ<br />

Passando al logaritmo in base 10:<br />

n 1 − n 0 < logɛ =⇒ n 0 > n 1 − logɛ<br />

Fissato n 1 = 20 si ricava n 0 = 26.<br />

Questa volta i calcoli danno gli stessi risultati sia in Matlab sia in Fortran:<br />

n y n n y n<br />

26 0.000000 11 7.62944e-3<br />

25 3.84615e-3 10 8.32797e-3<br />

24 3.61538e-3 9 9.16720e-3<br />

23 3.80513e-3 8 1.01944e-2<br />

22 3.96731e-3 7 1.14806e-2<br />

21 4.14872e-3 6 1.31377e-2<br />

20 4.34703e-3 5 1.53529e-2<br />

19 4.56530e-3 4 1.84647e-2<br />

18 4.80663e-3 3 2.31535e-2<br />

17 5.07489e-3 2 3.10180e-2<br />

16 5.37486e-3 1 4.68982e-2<br />

15 5.71251e-3 0 9.53102e-2<br />

14 6.09542e-3<br />

13 6.53332e-3<br />

12 7.03898e-3<br />

Osserviamo come il valore y 0 coincida con il valore teorico noto.<br />

L’esempio appena visto ci porta a dare alcune considerazioni sui criteri su cui si deve basare un algoritmo:<br />

un algoritmo deve essere accurato, efficiente e robusto, accurato nel senso che bisogna essere in grado<br />

<strong>di</strong> sapere la grandezza dell’errore che si commette nell’algoritmo stesso; efficiente in termini <strong>di</strong> velocità <strong>di</strong><br />

esecuzione e <strong>di</strong> richiesta <strong>di</strong> spazio <strong>di</strong> memoria per le variabili utilizzate; robusto nel dare il risultato corretto<br />

entro un livello <strong>di</strong> tolleranza dell’errore che sia accettabile.<br />

3.7.2 Malcon<strong>di</strong>zionamento<br />

Definizione 3.7.2 Un problema si <strong>di</strong>ce malcon<strong>di</strong>zionato se a piccole variazioni nei dati <strong>di</strong> input del problema<br />

corrispondono forti variazioni nei dati <strong>di</strong> output.<br />

Quando il problema è molto sensibile alle variazioni dei dati <strong>di</strong> input, producendo risultati molto <strong>di</strong>versi tra<br />

loro, allora nessun algoritmo, per quanto robusto e stabile, potrà dare una soluzione robusta al problema<br />

stesso.<br />

Esempio 3.7.2 Il problema del calcolo delle ra<strong>di</strong>ci <strong>di</strong> un polinomio p(x) <strong>di</strong> grado n è un esempio <strong>di</strong><br />

problema malcon<strong>di</strong>zionato.<br />

Sia p(x) = a 0 + a 1 x + a 2 x 2 +...+ a n x n . I dati <strong>di</strong> input del problema sono i coefficienti a 0 , a 1 ,..., a n . I dati <strong>di</strong><br />

output sono le ra<strong>di</strong>ci del polinomio.<br />

Si può provare che a piccole variazioni sui dati iniziali, corrispondono gran<strong>di</strong> variazioni sui risultati.<br />

34


3.7. Instabilità e malcon<strong>di</strong>zionamento<br />

Figura 3.6: Esempio: malcon<strong>di</strong>zionamento<br />

Ve<strong>di</strong>amo il caso del polinomio p(x) = (x − 1)(x − 2)···(x − 10). Chiaramente, tale polinomio ha ra<strong>di</strong>ci<br />

1,2,...,10. Se perturbiamo il polinomio variando il coefficiente a 9 del valore <strong>di</strong> 0.00001, considerando quin<strong>di</strong><br />

il polinomio p(x) + 0.00001x 9 , le ra<strong>di</strong>ci corrispondenti si <strong>di</strong>scostano <strong>di</strong> poco da quelle del polinomio <strong>di</strong><br />

partenza, come si può notare in Figura 3.6. Ma se variamo il coefficiente a 9 del valore 0.0001, considerando<br />

cioè il polinomio p(x) + 0.0001x 9 allora le ra<strong>di</strong>ci corrispondenti a x 7 , x 8 , x 9 , x 10 non saranno più reali ma<br />

avranno anche una parte immaginaria. La piccola variazione sui dati <strong>di</strong> ingresso, quin<strong>di</strong>, provoca una<br />

grande variazione sui dati in uscita, proprio perchè il problema è malcon<strong>di</strong>zionato.<br />

Una quantità che misura il grado <strong>di</strong> sensibilità <strong>di</strong> un problema – fornendoci in<strong>di</strong>cazioni sul fatto che a<br />

piccole variazioni sui dati <strong>di</strong> ingresso del problema ci possono essere piccole o gran<strong>di</strong> variazioni sui dati <strong>di</strong><br />

uscita – si chiama in<strong>di</strong>ce <strong>di</strong> con<strong>di</strong>zionamento (o numero <strong>di</strong> con<strong>di</strong>zionamento) del problema.<br />

Diamo la definizione nel caso in cui il nostro problema si possa identificare come una funzione f : R −→<br />

R. Il valore y = f (x) è il valore <strong>di</strong> uscita del problema f . Vogliamo vedere cosa succede se il dato <strong>di</strong> ingresso<br />

non è più x ma x + ∆x. ∆x rappresenta quin<strong>di</strong> una perturbazione sul dato iniziale. Assumiamo x ≠ 0, y ≠ 0.<br />

Applichiamo la formula <strong>di</strong> Taylor <strong>di</strong> centro x. Si ha:<br />

in<strong>di</strong>ce <strong>di</strong><br />

con<strong>di</strong>zionamento<br />

f (x + ∆x) = f (x) + f ′ (x)∆x +O(∆x 2 ) ≈ f (x) + f ′ (x)∆x<br />

La variazione sul dato d’uscita è data dalla <strong>di</strong>fferenza f (x + ∆x) − f (x). Chiamiamo questa <strong>di</strong>fferenza con<br />

∆y. Quin<strong>di</strong> ∆y = f (x + ∆x) − f (x) ≈ f ′ (x)∆x (utilizziamo il risultato ottenuto dalla formula <strong>di</strong> Taylor).<br />

35


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Se utilizziamo gli errori relativi, abbiamo (e sapendo che y = f (x)):<br />

∆y<br />

y<br />

∆y<br />

y<br />

≈ f ′ (x)∆x<br />

f (x)<br />

Moltiplico poi numeratore e denominatore a secondo membro per x<br />

≈ x f ′ (x) ∆x<br />

f (x) x<br />

Al limite per ∆x → 0, questa uguaglianza approssimata (abbiamo usato il simbolo ≈) <strong>di</strong>venta una vera<br />

uguaglianza. Questo suggerisce <strong>di</strong> definire l’in<strong>di</strong>ce <strong>di</strong> con<strong>di</strong>zionamento <strong>di</strong> f me<strong>di</strong>ante la formula<br />

(cond f )(x) =<br />

x f ′ (x)<br />

∣<br />

f (x)<br />

∣<br />

Questo numero ci <strong>di</strong>ce quanto gran<strong>di</strong> sono le perturbazioni relative per y confrontate con le relative<br />

perturbazioni <strong>di</strong> x.<br />

Per x = 0 e y ≠ 0, non ha senso considerare l’errore relativo ∆x , e si considera l’errore assoluto su x. In tal<br />

x<br />

caso, si definisce in<strong>di</strong>ce <strong>di</strong> con<strong>di</strong>zionamento la quantità<br />

(cond f )(x) =<br />

f ′ (x)<br />

∣<br />

f (x)<br />

∣<br />

Per x = y = 0 si considera invece l’errore assoluto sia per x che per y, <strong>di</strong>modochè l’in<strong>di</strong>ce <strong>di</strong><br />

con<strong>di</strong>zionamento <strong>di</strong>venta<br />

(cond f )(x) = |f ′ (x)|<br />

Esempio 3.7.3 Sia f (x) = x 1/α , con x > 0 e α > 0. Calcoliamo l’in<strong>di</strong>ce <strong>di</strong> con<strong>di</strong>zionamento applicando la<br />

formula (poichè abbiamo supposto x > 0, si ha f (x) ≠ 0). Risulta<br />

∣ (cond f )(x) =<br />

x f ′ ∣∣∣∣∣∣<br />

(x)<br />

x 1 ∣ ∣∣∣∣∣∣ ∣<br />

f (x)<br />

∣ = α x1/α−1<br />

= 1 α<br />

x 1/α<br />

Per α grande, (cond f )(x) tende a zero, quin<strong>di</strong> abbiamo un problema bencon<strong>di</strong>zionato. Se, invece α è molto<br />

piccolo si ha un problema malcon<strong>di</strong>zionato (se α = 10 −10 , si ha f (x) = x 1010 e (cond f )(x) = 10 10 , un valore<br />

molto grande).<br />

36


C A P I T O L O<br />

4<br />

ZERI DI FUNZIONE<br />

Non so come il mondo potrà<br />

giu<strong>di</strong>carmi ma a me sembra<br />

soltanto <strong>di</strong> essere un bambino che<br />

gioca sulla spiaggia, e <strong>di</strong> essermi<br />

<strong>di</strong>vertito a trovare ogni tanto un<br />

sasso o una conchiglia più bella del<br />

solito, mentre l’oceano della verità<br />

giaceva insondato davanti a me.<br />

Isaac Newton<br />

4.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

4.2 Metodo delle Bisezioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

4.3 Metodo del Punto Fisso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

4.4 Il Metodo <strong>di</strong> Newton-Raphson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

4.5 Convergenza <strong>di</strong> un metodo iterativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

4.6 Complessità computazionale <strong>di</strong> uno schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

4.7 Il metodo delle secanti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

4.8 Confronto tra i meto<strong>di</strong> <strong>di</strong> Newton-Raphson e la Regula Falsi . . . . . . . . . . . . . . . . . . . . . . 50<br />

4.9 Metodo <strong>di</strong> Newton-Raphson per ra<strong>di</strong>ci multiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

4.10 Controllo sugli scarti e grafici <strong>di</strong> convergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

4.11 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />

4.1 Introduzione<br />

Il problema <strong>di</strong> calcolare la ra<strong>di</strong>ce quadrata <strong>di</strong> un numero è un problema molto antico. Già gli antichi<br />

Babilonesi, intorno al 1700 a.C., se lo erano posto e avevano trovato la soluzione: per calcolare b, partivano<br />

da un certo valore x che si avvicinava alla soluzione, <strong>di</strong>videvano b per questo numero, e facevano poi la<br />

me<strong>di</strong>a, iterando il proce<strong>di</strong>mento. L’algoritmo si può schematizzare nel modo seguente:<br />

G partire da x 0 prossimo a b;<br />

G considerare x 1 = 1 2 (x 0 + b x 0<br />

);<br />

G generalizzando: x n+1 = 1 2 (x n + b x n<br />

).<br />

37


4. ZERI DI FUNZIONE<br />

Per esempio, per calcolare 2 ≈ 1.41421356237310, sapendo che il valore che dobbiamo approssimare è<br />

compreso tra 1 e 2, possiamo partire da x 0 = 1.5, ottenendo:<br />

x 0 = 1.5<br />

x 1 = 1 2 (1.5 + 2<br />

1.5 ) = 1.41666667<br />

x 2 = 1 2 (1.41666667 + 2<br />

1.41666667 ) = 1.41421569<br />

x 3 = 1 2 (1.41421569 + 2<br />

1.41421569 ) = 1.41421356<br />

Il metodo usato dai Babilonesi non è altro che il metodo <strong>di</strong> Newton-Raphson (che vedremo più avanti)<br />

per trovare gli zeri della funzione f (x) = x 2 − b.<br />

I meto<strong>di</strong> numerici <strong>di</strong>scussi in questo Capitolo servono per trovare approssimazioni numeriche ad<br />

equazioni del tipo f (x) = 0.<br />

4.2 Metodo delle Bisezioni<br />

Sia data una funzione f continua in un intervallo [a,b], con f (a) e f (b) che assumono valori <strong>di</strong> segno<br />

opposto. Allora, per il teorema del Valore Interme<strong>di</strong>o (si veda il Teorema 2.5.3 con K = 0), esiste almeno un<br />

punto ξ ∈]a,b[ tale che f (ξ) = 0.<br />

Assumiamo, per semplicità che ci sia una sola ra<strong>di</strong>ce ξ nell’intervallo ]a,b[ (nel caso ci sia più <strong>di</strong> una<br />

ra<strong>di</strong>ce, la procedura che ora descriviamo vale sempre, e ci permette <strong>di</strong> calcolare una <strong>di</strong> queste ra<strong>di</strong>ci).<br />

Il metodo delle bisezioni (detto anche metodo <strong>di</strong>cotomico) si chiama così perchè, ad ogni passo, viene<br />

<strong>di</strong>mezzato l’intervallo precedente, cercando in tal modo <strong>di</strong> racchiudere la ra<strong>di</strong>ce ξ in sottointervalli sempre<br />

più piccoli.<br />

G Si pone a 1 = a e b 1 = b. Si prende il punto me<strong>di</strong>o dell’intervallo [a 1 ,b 1 ], c 1 = a 1 + b 1<br />

.<br />

G Se f (c 1 ) = 0 allora abbiamo trovato la ra<strong>di</strong>ce dell’equazione, altrimenti si va a controllare il segno <strong>di</strong><br />

f (c 1 ).<br />

– Se f (c 1 ) e f (a 1 ) hanno lo stesso segno, allora ξ si trova nell’intervallo ]c 1 ,b 1 [ (applicando <strong>di</strong> nuovo<br />

il teorema del Valore Interme<strong>di</strong>o). In tal caso porremo a 2 = c 1 e b 2 = b 1 .<br />

– Se, invece, f (c 1 ) e f (b 1 ) hanno lo stesso segno, allora ξ si trova nell’intervallo ]a 1 ,c 1 [ In tal caso<br />

porremo a 2 = a 1 e b 2 = c 1 .<br />

G Riapplichiamo questa procedura appena descritta sul sottointervallo [a 2 ,b 2 ]<br />

G Fermiamo il proce<strong>di</strong>mento ad una certa iterazione n, se f (c n ) = 0 o se l’ampiezza del sottointervallo<br />

è sufficientemente piccola, cioè b n − a n<br />

≤ tol l dove tol l è una certa tolleranza prefissata. In tal caso<br />

2<br />

assumiamo c n come approssimazione della ra<strong>di</strong>ce ξ.<br />

Osserviamo che, ad ogni passo, viene <strong>di</strong>mezzato l’intervallo in cui si trova la ra<strong>di</strong>ce ξ, da cui<br />

|ξ − c n | ≤ b − a<br />

2 n .<br />

Da questa relazione, si può determinare il numero <strong>di</strong> iterazioni n necessarie per calcolare un’approssimazione<br />

della ra<strong>di</strong>ce ξ entro una certa tolleranza tol l richiesta. Infatti<br />

b − a<br />

2 n ≤ tol =⇒ |ξ − c n | ≤ tol<br />

2<br />

Ma<br />

( ) b − a<br />

b − a<br />

2 n ≤ tol ⇐⇒ 2 n ≥ b − a log<br />

tol<br />

=⇒ n ≥<br />

.<br />

tol<br />

log(2)<br />

L’algoritmo <strong>di</strong> bisezione può essere descritto nel modo seguente (sotto forma <strong>di</strong> pseudo-co<strong>di</strong>ce). Se il<br />

metodo non converge (perchè, ad esempio, la funzione che abbiamo scelto non assume segno opposto agli<br />

38


4.3. Metodo del Punto Fisso<br />

Figura 4.1: Metodo delle Bisezioni<br />

estremi dell’intervallo), il proce<strong>di</strong>mento iterativo potrebbe entrare in stallo (pensiamo ad un programma da<br />

fare eseguire al calcolatore) e quin<strong>di</strong> conviene introdurre un numero massimo <strong>di</strong> iterazioni, che viene in<strong>di</strong>cato<br />

con itmax.<br />

Dati <strong>di</strong> input: a, b, tol , i tmax<br />

Dati <strong>di</strong> output: soluzione approssimata c o messaggio <strong>di</strong> fallimento<br />

1 verificare che f (a)f (b) < 0, altrimenti non si può implementare il metodo ;<br />

2 n ←− 1 ;<br />

3 c ←− (a + b)/2 ;<br />

4 scar to ←− |b − a|/2 ;<br />

5 Fintantochè n ≤ i tmax e ( f (c) ≠ 0 e scar to > tol )<br />

6 n ←− n + 1 (incrementa n) ;<br />

7 Se f (a)f (c) > 0 allora<br />

8 a ←− c<br />

9 altrimenti<br />

10 b ←− c<br />

11 Fine-Se<br />

12 aggiorna c ;<br />

13 aggiorna scar to ;<br />

14 Fine-Fintantochè<br />

15 Se f (c) = 0 o scar to ≤ tol allora<br />

16 c è la soluzione approssimata<br />

17 altrimenti<br />

18 n > i tmax ;<br />

19 il metodo è fallito dopo i tmax iterazioni ;<br />

20 Fine-Se<br />

4.3 Metodo del Punto Fisso<br />

Il problema f (x) = 0 può essere reso equivalente alla ricerca del punto fisso <strong>di</strong> una opportuna funzione g<br />

(vale a <strong>di</strong>re del problema g (x) = x).<br />

39


4. ZERI DI FUNZIONE<br />

( x<br />

) 2−sin(x) ( x<br />

) 2−sin(x)+x<br />

Ad esempio, da f (x) =<br />

= 0, aggiungendo ad ambo i membri x, otteniamo = x<br />

( 2<br />

2<br />

x<br />

) 2<br />

da cui poniamo g (x) = − sin(x) + x. Le ra<strong>di</strong>ci della f coincidono con i punti fissi della g .<br />

2<br />

Definizione 4.3.1 Data una funzione g , si definisce punto fisso della g , quel punto<br />

ξ che sod<strong>di</strong>sfa la relazione g (ξ) = ξ<br />

Una funzione può ammettere uno o più punti fissi o non ammetterne affatto.<br />

Un modo per calcolare un punto fisso <strong>di</strong> una funzione g è dato da iterazioni successive sulla funzione g<br />

stessa.<br />

Esempio 4.3.1 Supponiamo che la funzione g sia g (x) = cos(x). Pren<strong>di</strong>amo come valore iniziale x 0 = 1.<br />

Con una calcolatrice, an<strong>di</strong>amo a calcolare (in modalità ra<strong>di</strong>anti!) il suo coseno: ricaviamo x 1 = cos(x 0 ) =<br />

g (x 0 ) = 0.54030230. Successivamente, calcoliamo il coseno <strong>di</strong> x 1 , ottenendo x 2 = cos(x 1 ) = 0.857553216.<br />

Osserviamo che x 2 = cos(x 1 ) = cos(cos(x 0 )) e non cos 2 (x 0 )! Abbiamo innescato, in questo modo, un proce<strong>di</strong>mento<br />

iterativo per cui x n+1 = cos(x n ) = g (x n ). Con la calcolatrice, basta <strong>di</strong>gitare sulla funzione cos ogni<br />

volta in modo da avere i nuovi valori della successione x n+1 . I primi numeri che otteniamo non sono molto<br />

importanti. Quelli importanti sono quelli che si hanno dopo 15, 30 o 100 passi. Nel nostro caso, abbiamo<br />

n x n<br />

5 0.7013687746<br />

11 0.7356047404<br />

13 0.7414250866<br />

14 0.7375068905<br />

15 0.7401473356<br />

29 0.7390893414<br />

30 0.7390822985<br />

56 0.7390851333<br />

57 0.7390851332<br />

58 0.7390851332<br />

Perchè i valori <strong>di</strong> x tendono a 0.7390851332? Cosa ha <strong>di</strong> speciale questo numero? È un punto fisso per la<br />

funzione cos(x).<br />

Esempio 4.3.2 Consideriamo la funzione g (x) = 1 2 x + 2. Partendo da x 0 = 0 si ha<br />

n x n<br />

1 x 1 = 1 2 · 0 + 2 = 2<br />

2 x 2 = 1 2 · 2 + 2 = 3<br />

3 x 3 = 1 2 · 3 + 2 = 3.5<br />

4 x 4 = 1 2 · 3.5 + 2 = 3.75<br />

5 x 5 = 1 2 · 3.75 + 2 = 3.875<br />

6 x 6 = 1 2 · 3.875 + 2 = 3.9375<br />

I numeri 2, 3, 3.5, 3.75, 3.875, 3.9375 sembrano avvicinarsi a ξ = 4. Difatti, per valori crescenti <strong>di</strong> n, per x n<br />

1<br />

che tende a ξ, si ha, da una parte ξ = lim n→∞ x n+1 = lim n→∞<br />

2 x n + 2 = 1 2 ξ + 2 da cui, ξ = 1 ξ + 2, cioè ξ = 4.<br />

2<br />

40


4.3. Metodo del Punto Fisso<br />

Scopriamo quin<strong>di</strong> che se l’iterazione x n+1 = g (x n ) converge a ξ, ξ è punto fisso per la funzione g .<br />

Da un punto <strong>di</strong> vista geometrico, i grafici <strong>di</strong> y = x (bisettrice del primo e terzo quadrante) e <strong>di</strong> y = g (x) si<br />

intersecano in ξ.<br />

Tuttavia, non sempre questo schema iterativo, applicato a funzioni che ammettono uno o più punti fissi,<br />

converge. Ve<strong>di</strong>amo con un esempio.<br />

Esempio 4.3.3 Sia g (x) = x 2 . Analiticamente troviamo due punti fissi per questa funzione. Dovendo essere<br />

ξ = ξ 2 , si ricava ξ 2 − ξ = 0, vale a <strong>di</strong>re ξ(ξ − 1) = 0: quin<strong>di</strong> ξ = 0 e ξ = 1 sono i due punti fissi per questa<br />

funzione.<br />

Partendo da x 0 = 0.5, si ha la successione <strong>di</strong> valori 0.25, 0.0625, 0.00390625, rapidamente il metodo converge<br />

a ξ = 0<br />

Se si prende come punto iniziale un valore x 0 ∈] − 1,1[, la successione converge a ξ = 0. Le sole successioni<br />

che convergono a ξ = 1 solo le ovvie successioni generate da x 0 = ±1. Se si prende come punto iniziale x 0 tale<br />

che |x 0 | > 1 allora lo schema iterativo x n+1 = x 2 n <strong>di</strong>verge a +∞. Partendo da x 0 = 2, si ha 4, 16, 256, 65536...<br />

Questo esempio è significativo per capire come ciascun punto fisso ξ abbia un proprio bacino <strong>di</strong> attrazione:<br />

se si prende x 0 in questo bacino, allora i valori x n tendono a ξ. Un punto fisso può dunque attirare o<br />

respingere i valori x n prodotti dallo schema iterativo.<br />

Prima <strong>di</strong> passare a stu<strong>di</strong>are quando lo schema <strong>di</strong> punto fisso converge, ricor<strong>di</strong>amo che una funzione può<br />

ammettere più <strong>di</strong> un punto fisso, ammetterne uno solo o non ammetterne affatto. Ci sono due teoremi (2.5.4<br />

e 2.5.5) che ci <strong>di</strong>cono quando una funzione può ammettere punti fissi. Il primo assicura l’esistenza <strong>di</strong> almeno<br />

un punto fisso (ciò vuol <strong>di</strong>re che vi possono essere più punti fissi) quando la funzione g , definita e continua<br />

in [a,b], è tale che a ≤ g (x) ≤ b per ogni x ∈ [a,b]. Il secondo teorema aggiunge, a queste ipotesi, quelle che g<br />

sia <strong>di</strong> classe C 1 e, inoltre, |g ′ (x)| ≤ m < 1 per ogni x ∈ [a,b]: in tal caso esiste un unico punto fisso.<br />

È importante osservare che, data una funzione che ammette punto fisso, le ipotesi dei due teoremi 2.5.4<br />

e 2.5.5 possono essere rilassate dall’intervallo [a,b] ad un intorno del punto fisso.<br />

Possiamo ora provare un teorema <strong>di</strong> convergenza per lo schema iterativo del punto fisso.<br />

Teorema 4.3.1 A partire da un punto iniziale x 0 , lo schema iterativo x n+1 = g (x n ) converge al punto fisso ξ <strong>di</strong><br />

g se e solo se |g ′ (x)| < 1 in un intorno <strong>di</strong> ξ.<br />

Dimostrazione.<br />

Dalle relazioni<br />

ξ = g (ξ)<br />

x n+1 = g (x n )<br />

sottraendo membro a membro e, applicando il teorema del Valore Me<strong>di</strong>o 2.5.2 (con ξ n un opportuno punto<br />

del segmento che congiunge ξ a x n ), otteniamo:<br />

ξ − x n+1 = g (ξ) − g (x n ) = g ′ (ξ n )(ξ − x n )<br />

Possiamo scrivere questa relazione per n = 0,1,... ottenendo<br />

ξ − x 1 = g ′ (ξ 0 )(ξ − x 0 )<br />

ξ − x 2 = g ′ (ξ 1 )(ξ − x 1 )<br />

ξ − x 3 = g ′ (ξ 2 )(ξ − x 2 )<br />

. = . . .<br />

ξ − x n = g ′ (ξ n−1 )(ξ − x n−1 )<br />

41


4. ZERI DI FUNZIONE<br />

Figura 4.2: Il metodo <strong>di</strong> punto fisso: esempi con g (x) = cos(x) (a sinistra), e g (x) = 1 x + 2 (a destra)<br />

2<br />

Moltiplicando, ora, membro a membro e prendendo i valori assoluti, abbiamo:<br />

|ξ − x 1 | · |ξ − x 2 | · ... · |ξ − x n | =<br />

|g ′ (ξ 0 )| · |g ′ (ξ 1 )| · |g ′ (ξ 2 )| · ... · |g ′ (ξ n−1 )| · |ξ − x 0 | · |ξ − x 1 | · ... · |ξ − x n−1 |<br />

La relazione appena trovata può essere semplificata, <strong>di</strong>videndo ambo i membri per |ξ − x 1 | · |ξ − x 2 | · ... ·<br />

|ξ − x n−1 | ottenendo:<br />

|ξ − x n | = |g ′ (ξ 0 )| · |g ′ (ξ 1 )| · |g ′ (ξ 2 )| · ·... · |g ′ (ξ n−1 )||ξ − x 0 |<br />

Assumiamo, ora che |g ′ (x i )| ≤ m per i = 0,1,...,n − 1. Abbiamo dunque una relazione che lega l’errore<br />

assoluto al passo n con l’errore assoluto iniziale.<br />

|ξ − x n | ≤ m n |ξ − x 0 |<br />

Perchè il metodo converga, l’errore deve tendere a zero per n che tende all’infinito. Se m < 1 è assicurata la<br />

convergenza (quin<strong>di</strong>, se in un intorno del punto fisso, la derivata prima è minore <strong>di</strong> 1, lo schema converge).<br />

Se invece m > 1 in un intorno del punto fisso, lo schema non può convergere al punto fisso.<br />

Se vale m = 1 nulla si può <strong>di</strong>re a priori, ma bisogna vedere caso per caso cosa succede nell’intorno del<br />

punto fisso. ✔<br />

Negli esempi precedenti:<br />

g (x) g ′ (x)<br />

cos(x) −sin(x)<br />

1<br />

2 x + 2 1<br />

2<br />

x 2 2x<br />

Nel primo caso (esempio 4.3.1) −sin(0.7390851332) = −0.673612, perciò in un intorno del punto fisso la<br />

derivata è minore <strong>di</strong> 1 in valore assoluto e si ha convergenza.<br />

Nell’esempio 4.3.2 g ′ (x) = 1 qualunque sia x: si ha convergenza.<br />

2<br />

Nel terzo caso (esempio 4.3.3), g ′ (x) = 2x da cui g ′ (0) = 0 e g ′ (1) = 2. In un intorno del primo punto fisso,<br />

vale m < 1, in un intorno del secondo punto fisso m > 1 e non si potrà mai avere convergenza ad esso.<br />

Il bacino <strong>di</strong> attrazione si ha quin<strong>di</strong> se vale m < 1.<br />

Da un punto <strong>di</strong> vista grafico, le iterazioni dello schema <strong>di</strong> punto fisso si possono vedere sotto forma <strong>di</strong><br />

ragnatela. Le iterazioni, infatti, si muovono avanti e in<strong>di</strong>etro tra il grafico della y = g (x) e il grafico della<br />

bisettrice y = x. L’esempio 4.3.1, con g (x) = cos(x), è rappresentato in Figura 4.2 (a sinistra): partendo da<br />

(x 0 , x 0 ) sulla retta y = x, applicando l’algoritmo si ha x 1 = g (x 0 ). Perciò:<br />

42


4.3. Metodo del Punto Fisso<br />

Figura 4.3: Il metodo <strong>di</strong> punto fisso: esempio con g (x) = x 2 . Si noti la convergenza monotona a ξ = 0 (a<br />

sinistra) e la <strong>di</strong>vergenza monotona da ξ = 1 (a destra)<br />

G da (x 0 , x 0 ) si va su o giù fino a raggiungere (x 0 , x 1 ) sulla curva g ;<br />

G da (x 0 , x 1 ) si arriva a (x 1 , x 1 ) sulla bisettrice y = x.<br />

Questi due passi vengono ripetuti per tutte le altre iterazioni. Da x 1 si arriva sulla curva a g (x 1 ). Ora l’altezza<br />

è x 2 . Da qui si va sulla bisettrice al punto (x 2 , x 2 ). E così via. Lo scopo delle iterazioni, infatti, è <strong>di</strong> arrivare al<br />

punto (ξ,ξ) ≈ 0.7390851332 che è il punto <strong>di</strong> intersezione tra il grafico <strong>di</strong> g e la bisettrice y = x. Osserviamo<br />

che, per questo esempio, i valori della successione si avvicinano a ξ muovendosi a destra e a sinistra rispetto<br />

ad esso. Si parla <strong>di</strong> convergenza oscillante.<br />

Nell’esempio 4.3.2, si devono intersecare due linee rette. Notiamo, anche dalla Figura 4.2 (a destra), che i<br />

valori delle iterazioni si trovano tutti da un lato rispetto al punto fisso: si parla <strong>di</strong> convergenza monotona.<br />

In generale, quando 0 ≤ g ′ (x) < 1 in un intorno del punto fisso, si ha convergenza monotona. Se, invece,<br />

−1 < g ′ (x) < 0 in un intorno del punto fisso, si ha convergenza oscillante.<br />

Analogamente, in Figura 4.3, si possono osservare le conclusioni già viste per l’esempio 4.3.3, in cui g (x) =<br />

x 2 : si ha convergenza monotona verso ξ = 0 partendo da un punto iniziale in valore assoluto minore <strong>di</strong> uno,<br />

e <strong>di</strong>vergenza monotona a infinito, partendo da |x 0 | > 1.<br />

Esempio 4.3.4 Consideriamo ora g (x) = x−sin(x) nell’intervallo [0,2π]. Data la perio<strong>di</strong>cità della funzione<br />

seno, g ammette più <strong>di</strong> un punto fisso. Infatti da ξ = ξ − sin(ξ) si ha 0 = sin(ξ) da cui ξ = 0, ξ = π e ξ = 2π.<br />

Stu<strong>di</strong>amo ora la derivata prima g ′ (x) = 1 − cos(x). Si ha g ′ (0) = 1 − 1 = 0, g ′ (π) = 1 − (−1) = 2 e g ′ (2π) =<br />

1−1 = 0. Da queste informazioni, deduciamo che qualunque sia il punto iniziale x 0 la successione generata<br />

dallo schema del punto fisso non potrà mai convergere a π, come si vede anche dalla Figura 4.4.<br />

Nel caso in cui il metodo <strong>di</strong> punto fisso converge, si possono ricavare maggiorazioni per l’errore che si<br />

commette approssimando ξ me<strong>di</strong>ante x n . Vale infatti la <strong>di</strong>suguaglianza<br />

|ξ − x n | ≤ m<br />

1 − m |x n − x n−1 |<br />

dove m, come prima, è una maggiorazione <strong>di</strong> |g ′ (x)|.<br />

43


4. ZERI DI FUNZIONE<br />

Figura 4.4: Il metodo <strong>di</strong> punto fisso: esempio con g (x) = x − sin(x). ξ = 0 e ξ = 2π sono punti fissi attrattivi, al<br />

contrario <strong>di</strong> ξ = π in cui g ′ (ξ) = g ′ (π) = 2<br />

Proviamo questo risultato, scrivendo l’errore all’iterazione n come ξ − x n = g (ξ) − g (x n−1 )<br />

Applicando il teorema del valor me<strong>di</strong>o e considerando, come prima, |g ′ (x)| ≤ m < 1 in un<br />

intorno del punto fisso, si ha:<br />

|ξ − x n | ≤ m|ξ − x n−1 | (4.1)<br />

Possiamo scrivere ξ − x n−1 nel modo seguente aggiungendo e sottraendo x n :<br />

ξ − x n−1 = ξ − x n + x n − x n−1<br />

ξ − x n−1 = g (ξ) − g (x n−1 ) + x n − x n−1<br />

|ξ − x n−1 | ≤ m|ξ − x n−1 | + |x n − x n−1 |<br />

(1 − m)|ξ − x n−1 | ≤ |x n − x n−1 |<br />

|ξ − x n−1 | ≤ 1<br />

1 − m |x n − x n−1 |<br />

Andando a sostituire questa maggiorazione nella <strong>di</strong>suguaglianza (4.1), si ha<br />

|ξ − x n | ≤ m<br />

1 − m |x n − x n−1 |<br />

Abbiamo una maggiorazione dell’errore che lega l’errore al passo n con il valore assoluto della <strong>di</strong>fferenza<br />

tra due iterazioni successive |x n − x n−1 | (quest’ultima quantità prende il nome <strong>di</strong> scarto).<br />

Generalmente, per vedere se il metodo <strong>di</strong> punto fisso converge al punto fisso entro una certa tolleranza<br />

prestabilita, il controllo da fare è proprio sullo scarto d n = |x n − x n−1 |. Sfruttiamo questo fatto per vedere<br />

come implementare l’algoritmo dello schema <strong>di</strong> punto fisso (sotto forma <strong>di</strong> pseudo-co<strong>di</strong>ce; per i dettagli<br />

sull’implementazione in Fortran si vada a pag. 172):<br />

44


4.4. Il Metodo <strong>di</strong> Newton-Raphson<br />

Dati <strong>di</strong> input: x 0 , tol ,i tmax<br />

Dati <strong>di</strong> output: x n soluzione approssimata o messaggio <strong>di</strong> fallimento<br />

1 n ←− 1 contatore delle iterazioni;<br />

2 d n ←− 2tol (una quantità iniziale > tol ) ;<br />

3 Fintantochè n ≤ i tmax e d n > tol<br />

4 incrementa n <strong>di</strong> 1;<br />

5 applicare l’algoritmo <strong>di</strong> punto fisso x n = g (x n−1 ) ;<br />

6 aggiorna d n ;<br />

7 Fine-Fintantochè<br />

8 Se d n ≤ tol allora<br />

9 x n è la soluzione approssimata<br />

10 altrimenti<br />

11 n > i tmax ;<br />

12 il metodo è fallito dopo i tmax iterazioni ;<br />

13 Fine-Se<br />

4.4 Il Metodo <strong>di</strong> Newton-Raphson<br />

Il metodo <strong>di</strong> Newton-Raphson 1 è uno dei meto<strong>di</strong> più potenti e più famosi per risolvere equazioni non lineari.<br />

Ci sono <strong>di</strong>versi approcci per introdurre questo metodo – tra questi c’è anche quello <strong>di</strong> vedere il metodo<br />

<strong>di</strong> Newton-Raphson come un particolare schema <strong>di</strong> punto fisso, come vedremo in seguito.<br />

Supponiamo ora che la derivata prima e seconda <strong>di</strong> f esistano e siano continue e assumiamo che la<br />

derivata prima f ′ sia valutabile con sufficiente facilità.<br />

Lo schema <strong>di</strong> Newton-Raphson è uno schema iterativo che produce una successione <strong>di</strong> approssimazioni<br />

x 0 , x 1 ,..., x n della ra<strong>di</strong>ce della funzione f .<br />

Sia x n l’iterata corrente. Applicando la formula <strong>di</strong> Taylor <strong>di</strong> centro x n si ha:<br />

f (x) = f (x n ) + f ′ (x n )(x − x n ) + f ′′ (ξ x )(x − x n ) 2 /2<br />

dove ξ x è un punto (che non conosciamo) compreso tra x e x n .<br />

Sia x = ξ, dove ξ è ra<strong>di</strong>ce <strong>di</strong> f , f (ξ) = 0. Se f fosse lineare, avremmo f ′′ ≡ 0 e quin<strong>di</strong> potremmo trovare la<br />

ra<strong>di</strong>ce risolvendo <strong>di</strong>rettamente<br />

0 = f (ξ) = f (x n ) + f ′ (x n )(ξ − x n )<br />

Supponendo f ′ (x n ) ≠ 0, otterremmo, con semplici passaggi,<br />

ξ = x n − f (x n)<br />

f ′ (x n )<br />

Per una funzione non lineare, il <strong>di</strong>scorso da fare è molto simile.<br />

La nuova approssimazione x n+1 vogliamo che sia uguale al valore x n più una certa quantità h che ci<br />

permetta <strong>di</strong> arrivare alla soluzione desiderata.<br />

1 Il metodo fu descritto da Isaac Newton in due suoi scritti del 1669 e del 1671, anche se era riferito solo a polinomi (in particolare a<br />

x 3 − 2x − 5 = 0). Il metodo <strong>di</strong> Newton fu pubblicato per la prima volta nel 1685. Nel 1690 Joseph Raphson ne pubblicò una descrizione<br />

semplificata in termini <strong>di</strong> approssimazioni successive x n piuttosto che <strong>di</strong> sequenze <strong>di</strong> polinomi. Fu solo nel 1740 che Thomas Simpson<br />

descrisse il metodo <strong>di</strong> Newton come un metodo iterativo per risolvere equazioni non lineari (e non solo polinomi) e <strong>di</strong>ede una versione<br />

generalizzata per sistemi <strong>di</strong> due equazioni.<br />

Isaac Newton (1643-1727), inglese, fu fisico, matematico, astronomo, alchimista, inventore, filosofo naturalista. È visto come uno dei<br />

più gran<strong>di</strong> scienzati nella storia dell’umanità.<br />

Su Joseph Raphson (1648-1715) non si hanno molti dettagli. Pare che Newton stesso gli permettesse <strong>di</strong> vedere e stu<strong>di</strong>are i suoi scritti<br />

matematici. Il suo lavoro del 1690 Analysis aequationum universalis gli valse l’ingresso nella Royal Society, nel 1691 benchè fosse uno<br />

studente (si laureò nel 1692) piuttosto anziano (aveva 43 anni).<br />

45


4. ZERI DI FUNZIONE<br />

Applicando la formula <strong>di</strong> Taylor <strong>di</strong> centro x n , deve essere<br />

f (x n+1 ) = f (x n + h) = f (x n ) + f ′ (x n )h + f ′′ (ξ h )h 2 /2<br />

Vogliamo che sia f (x n+1 ) = 0, da cui, trascurando il termine in h 2 e considerando f ′ (x n ) ≠ 0, ricaviamo<br />

h = − f (x n)<br />

f ′ (x n )<br />

Utilizziamo questo valore <strong>di</strong> h per la nuova approssimazione x n+1 = x n + h ottenendo la formula<br />

x n+1 = x n − f (x n)<br />

f ′ , n = 0,1,2,... (4.2)<br />

(x n )<br />

L’interpretazione geometrica del metodo <strong>di</strong> Newton è che x n+1 è l’intercetta, sull’asse delle x, della<br />

tangente della f a x n (ve<strong>di</strong> figura 4.5).<br />

Figura 4.5: Il metodo <strong>di</strong> Newton-Raphson applicato alla funzione f (x) = (x/2) 2 − sin(x) con x 0 = 1.3<br />

Lo schema <strong>di</strong> Newton-Raphson si può vedere come un caso particolare dello schema del punto fisso applicato<br />

alla funzione g (x) = x − f (x)/f ′ (x). Perchè lo schema del punto fisso converga, deve essere |g ′ (x)| < 1<br />

in un intorno <strong>di</strong> ξ. Nel caso specifico abbiamo:<br />

|g ′ (x)| = |1 − f ′ (x) 2 − f (x)f ′′ (x)<br />

f ′ (x) 2 | = | f (x)f ′′ (x)<br />

f ′ (x) 2 |<br />

Supponendo f ′ (ξ) ≠ 0 (che è il caso in cui la ra<strong>di</strong>ce non è multipla), si ha |g ′ (ξ)| = 0, poichè al numeratore<br />

f (ξ) = 0 (essendo ξ ra<strong>di</strong>ce della f ). Per continuità, allora, vale |g ′ (x)| < 1 in un intorno <strong>di</strong> ξ. Pertanto il metodo<br />

<strong>di</strong> Newton-Raphson è generalmente convergente.<br />

Per vedere come si riduce l’errore via via che le approssimazioni si avvicinano a ξ, consideriamo l’errore<br />

cambiato <strong>di</strong> segno ɛ n , per cui x n = ξ + ɛ n . Sostituendo in (4.2) abbiamo<br />

ɛ n+1 + ξ = ɛ n + ξ − f (ξ + ɛ n)<br />

f ′ (ξ + ɛ n )<br />

ɛ n+1 = ɛ n − f (ξ + ɛ n)<br />

f ′ (ξ + ɛ n )<br />

46


4.5. Convergenza <strong>di</strong> un metodo iterativo<br />

Applicando la formula polinomiale <strong>di</strong> Taylor sia su f sia su f ′ <strong>di</strong> centro ξ, si ha:<br />

ɛ n+1 = ɛ n − f (ξ) + ɛ n f ′ (ξ) + ɛ 2 n f ′′ (ξ)/2 + ...<br />

f ′ (ξ) + ɛ n f ′′ (ξ) + ...<br />

Poichè f (ξ) = 0, raccogliendo i termini si ricava:<br />

ɛ n+1 = ɛ n f ′ (ξ) + ɛ 2 n f ′′ (ξ) − ɛ n f ′ (ξ) − ɛ 2 n f ′′ (ξ)/2 + ...<br />

f ′ (ξ) + ɛ n f ′′ (ξ) + ...<br />

= ɛ2 n f ′′ (ξ)/2 + ...<br />

f ′ (ξ) + ɛ n f ′′ (ξ) + ...<br />

Trascurando i termini ɛ n f ′′ (ξ)+... al denominatore e le potenze maggiori o uguali a ɛ 3 n al numeratore si trova:<br />

ɛ n+1 = f ′′ (ξ)<br />

2f ′ (ξ) ɛ2 n = Aɛ2 n<br />

ponendo A = f ′′ (ξ)<br />

2f ′ (ξ) .<br />

L’ultima relazione che abbiamo ottenuto ci <strong>di</strong>ce che l’errore al passo n + 1 è proporzionale, secondo il<br />

fattore A, al quadrato dell’errore al passo precedente. Perciò se partiamo da un errore iniziale dell’or<strong>di</strong>ne<br />

<strong>di</strong> 10 −2 , al passo successivo l’errore è proporzionale a 10 −4 e poi a 10 −8 fino a 10 −16 in tre sole iterazioni.<br />

Generalmente, quin<strong>di</strong>, il numero delle cifre significative raddoppia ad ogni passo del metodo. Si parla <strong>di</strong><br />

convergenza quadratica.<br />

Nel caso in cui ξ sia una ra<strong>di</strong>ce multipla, allora f ′ (ξ) = 0 e A = ∞: se il metodo converge, la convergenza<br />

non sarà più quadratica ma avremo una convergenza <strong>di</strong> tipo lineare, come vedremo meglio in seguito.<br />

Se in ξ vi è un punto <strong>di</strong> flesso, non orizzontale, per cui f (ξ) = 0, f ′ (ξ) ≠ 0, f ′′ (ξ) = 0, allora A = 0 e ci<br />

aspettiamo una convergenza superiore a quella quadratica.<br />

Sulla<br />

convergenza<br />

4.5 Convergenza <strong>di</strong> un metodo iterativo<br />

Un metodo iterativo si <strong>di</strong>ce:<br />

G linearmente convergente se esiste una costante M < 1 tale che, per n sufficientemente grande, vale<br />

|x n+1 − ξ| ≤ M|x n − ξ|<br />

G a convergenza quadratica se esiste una costante M tale che, per n sufficientemente grande, vale<br />

|x n+1 − ξ| ≤ M|x n − ξ| 2<br />

G a convergenza superlineare se esiste una successione <strong>di</strong> costanti M n → 0 tale che, per n<br />

sufficientemente grande, vale<br />

|x n+1 − ξ| ≤ M n |x n − ξ|.<br />

In generale un metodo ha or<strong>di</strong>ne <strong>di</strong> convergenza p se si possono definire due costanti p ≥ 1 e M > 0 tali<br />

che<br />

|x n+1 − ξ|<br />

lim<br />

n→∞ |x n − ξ| p = M<br />

La costante M prende il nome <strong>di</strong> costante asintotica dell’errore o fattore <strong>di</strong> convergenza.<br />

Nel caso del metodo <strong>di</strong> Newton-Raphson, generalmente vale p = 2 e la costante asintotica dell’errore è<br />

quella che abbiamo definito come A presa in valore assoluto, cioè M =<br />

f ′′ (ξ<br />

∣<br />

2f ′ (ξ)<br />

∣ .<br />

Nel metodo del punto fisso, la convergenza è lineare. Infatti, considerando l’errore cambiato <strong>di</strong> segno, la<br />

relazione x n+1 = g (x n ) si può scrivere, in modo equivalente, come<br />

ξ + ɛ n+1 = g (ξ + ɛ n ) e, applicando la formula (polinomiale) <strong>di</strong> Taylor si ha<br />

ξ + ɛ n+1 = g (ξ) + ɛ n g ′ (ξ) + ...<br />

ξ + ɛ n+1 = ξ + ɛ n g ′ (ξ) + ...<br />

ɛ n+1 = ɛ n g ′ (ξ) + ... e, al limite per n → ∞<br />

ɛ n+1 = g ′ (ξ)ɛ n<br />

47


4. ZERI DI FUNZIONE<br />

La costante asintotica per lo schema <strong>di</strong> punto fisso vale, dunque, M = |g ′ (ξ)|.<br />

Il metodo delle bisezioni, invece, può essere visto come un metodo lineare, con M = 1 2 (considerando<br />

che, ad ogni passo, si riduce della metà l’intervallo in cui viene cercata l’approssimazione della ra<strong>di</strong>ce).<br />

Esempio 4.5.1 Consideriamo l’equazione f (x) = 2x − cos(x) + 1 = 0 che ammette come unica ra<strong>di</strong>ce ξ = 0.<br />

Poichè f ′ (x) = 2 + sin(x), il metodo <strong>di</strong> Newton-Raphson <strong>di</strong>venta:<br />

x n+1 = x n − 2x n − cos(x n ) + 1<br />

2 + sin(x n )<br />

Partendo da x 0 = 0.5 e richiedendo una tolleranza pari a 10 −10 nei risultati (interrompiamo l’algoritmo<br />

quando d n < 10 −10 ), si ha:<br />

I valori generati dall’algoritmo tendono a ξ = 0.<br />

n x n d n<br />

0 0.5<br />

1 0.4730746270E-01 0.4526925E+00<br />

2 0.5462695134E-03 0.4676119E-01<br />

3 0.7458221874E-07 0.5461949E-03<br />

4 0.1395426403E-14 0.7458222E-07<br />

5 0.7647622253E-17 0.1387779E-14<br />

Considerando che f ′′ (x) = cos(x) possiamo valutare la costante asintotica M = |f ′′ (ξ)|<br />

2|f ′ (ξ)| = |cos(ξ)|<br />

2(|2 + sin(ξ)|) =<br />

1<br />

4 = 0.25<br />

Da un punto <strong>di</strong> vista teorico, applicando il teorema del valor me<strong>di</strong>o, si ha<br />

f (ξ) − f (x n ) = f ′ (ξ n )(ξ − x n )<br />

dove ξ n è un punto, che non conosciamo, compreso tra ξ e x n . Per x n vicino a ξ possiamo considerare<br />

ξ n ≈ x n , da cui ricaviamo (essendo f (ξ) = 0):<br />

−f (x n ) ≈ f ′ (x n )(ξ − x n )<br />

. Sostituendo questa espressione nell’iterazione <strong>di</strong> Newton-Raphson si ha:<br />

x n+1 = x n − f (x n)<br />

f ′ (x n ) ≈ x n + (ξ − x n )<br />

vale a <strong>di</strong>re<br />

x n+1 − x n = ξ − x n cioè d n+1 = ɛ n<br />

Ma in con<strong>di</strong>zioni <strong>di</strong> convergenza, d n+1 < d n da cui, per l’errore, vale la maggiorazione ɛ n < d n .<br />

Perciò gli scarti sono molto vicini agli errori e possono essere utilizzati sia per controllare il numero <strong>di</strong><br />

iterazioni da effettuare per approssimare la ra<strong>di</strong>ce entro una certa tolleranza sia per approssimare M.<br />

Nel nostro esempio<br />

d 2<br />

(d 1 ) 2 = 0.2282 d 3<br />

(d 2 ) 2 = 0.2498 d 4<br />

(d 3 ) 2 = 0.2500 d 5<br />

(d 4 ) 2 = 0.2495<br />

4.6 Complessità computazionale <strong>di</strong> uno schema<br />

Un altro elemento da considerare per valutare l’efficienza numerica <strong>di</strong> uno schema iterativo è la sua complessità<br />

computazionale. Un metodo, infatti, può avere un elevato or<strong>di</strong>ne <strong>di</strong> convergenza ma avere anche un<br />

costo computazionale molto elevato. Viceversa, un metodo può avere un basso or<strong>di</strong>ne <strong>di</strong> convergenza ma<br />

essere anche semplice computazionalmente e, quin<strong>di</strong>, molto vantaggioso da questo punto <strong>di</strong> vista.<br />

48


4.7. Il metodo delle secanti<br />

Si definisce in<strong>di</strong>ce <strong>di</strong> efficienza E dello schema iterativo la quantità<br />

E = p 1/s<br />

dove s in<strong>di</strong>ca il numero <strong>di</strong> volte in cui bisogna calcolare la funzione e la sua derivata prima ad ogni iterazione<br />

e p è l’or<strong>di</strong>ne <strong>di</strong> convergenza del metodo.<br />

4.7 Il metodo delle secanti<br />

La conoscenza della derivata prima della f per applicare il metodo <strong>di</strong> Newton-Raphson potrebbe essere<br />

semplice ma a volte potrebbe rivelarsi un’operazione molto costosa e alquanto complicata.<br />

Il metodo delle secanti è una variante del metodo <strong>di</strong> Newton-Raphson dove, al posto della derivata prima,<br />

si considera una sua approssimazione.<br />

Scriviamo la formula ricorsiva<br />

x n+1 = x n − f (x n)<br />

C n<br />

Per C n = f ′ (x n ) abbiamo la formula <strong>di</strong> Newton-Raphson, che possiamo anche chiamare della tangente<br />

variabile perchè è il coefficiente angolare della retta tangente a (x n , f (x n )) che interseca l’asse delle x in x n+1 .<br />

Ve<strong>di</strong>amo altre scelte <strong>di</strong> C n :<br />

G C n = f ′ (x 0 ): il valore <strong>di</strong> C n è costante e dà vita al metodo della tangente fissa.<br />

G C n = f (x 1) − f (x 0 )<br />

: abbiamo sempre una costante che approssima la derivata f ′ (x 0 ) utilizzando i valori<br />

x 1 − x 0<br />

<strong>di</strong> x 1 e x 0 . Lo schema è detto della secante fissa.<br />

G C n = f (x n) − f (x n−1 )<br />

. La derivata f ′ (x n ) è approssimata utilizzando il rapporto incrementale della f<br />

x n − x n−1<br />

valutata in x n e x n−1 . Abbiamo il metodo delle secante variabile, che chiameremo nel seguito anche<br />

metodo 2 della Regula Falsi.<br />

In forma estesa, l’iterazione n + 1 della Regula Falsi si scrive come:<br />

x n+1 = x n − f (x n)(x n − x n−1 )<br />

f (x n ) − f (x n−1 )<br />

Notiamo che, per innescare il metodo occorrono due valori iniziali, x 0 e x 1 . Ma è richiesta solo la<br />

valutazione della funzione f a ciascun passo (nessuna conoscenza della derivata prima).<br />

Da un punto <strong>di</strong> vista geometrico, nel metodo delle secanti il valore x n+1 è dato dall’intercetta sull’asse<br />

delle x della retta passante per x n , f (x n ) e x n−1 , f (x n−1 ). Per quanto riguarda l’accumulo <strong>degli</strong> errori <strong>di</strong> arrotondamento,<br />

conviene utilizzare la formula così come è stata scritta in quanto è più sicura rispetto alla forma<br />

compatta in cui vengono raccolti i termini, data da<br />

x n+1 = x n−1 f (x n ) − x n f (x n−1 )<br />

f (x n ) − f (x n−1 )<br />

in quanto in quest’ultima, si può avere il fenomeno della cancellazione numerica per x n ≈ x n−1 e<br />

f (x n )f (x n−1 ) > 0.<br />

Per quanto riguarda l’or<strong>di</strong>ne <strong>di</strong> convergenza si può <strong>di</strong>mostrare che si ha convergenza superlineare poichè<br />

vale la relazione<br />

p<br />

ɛ n+1 = M<br />

dove p = 1 + 5<br />

2<br />

p + 1 ɛ<br />

p<br />

n<br />

ɛ n+1 = M 0.618 ɛ 1.618<br />

n<br />

= 1.618 e A è la costante asitontica del metodo <strong>di</strong> Newton-Raphson, da cui<br />

2 Attenzione! In letteratura viene descritto un altro metodo (simile ma non lo stesso) con il nome della Regula Falsi o Falsa Posizione<br />

che genera i valori x n+1 in modo che la ra<strong>di</strong>ce ξ sia sempre compresa tra le iterazioni successive.<br />

49


4. ZERI DI FUNZIONE<br />

Figura 4.6: Il metodo della Regula Falsi applicato alla funzione f (x) = (x/2) 2 − sin(x) con x 0 = 1.3 e x 1 = 1.35<br />

4.8 Confronto tra i meto<strong>di</strong> <strong>di</strong> Newton-Raphson e la Regula Falsi<br />

Sebbene il metodo <strong>di</strong> Newton-Raphson abbia or<strong>di</strong>ne <strong>di</strong> convergenza più elevato della Regula Falsi,<br />

quest’ultimo è computazionalmente più efficiente. Si ha infatti<br />

Metodo p s E<br />

<br />

Newton-Raphson 2 2 2 ≈ 1.414<br />

Regula Falsi 1.618 1 1.618<br />

Ve<strong>di</strong>amo ora come applicare i due meto<strong>di</strong> e le <strong>di</strong>fferenze che si hanno.<br />

Esempio 4.8.1 Consideriamo la funzione f (x) = 0 con f (x) = (x/2) 2 − sin(x). La derivata prima è f ′ (x) =<br />

(x/2) − cos(x) Consideriamo come x 0 = 1.3 per entrambi i meto<strong>di</strong> e x 1 = 1.35 per la Regula Falsi. Come<br />

criterio <strong>di</strong> arresto, consideriamo una tolleranza tol = 1.e − 8, cioè andremo avanti con le iterazioni fino a<br />

quando troveremo che lo scarto d n = |x n − x n−1 | sarà minore <strong>di</strong> tol. Otteniamo i seguenti risultati per il<br />

metodo <strong>di</strong> Newton-Raphson<br />

n x n f (x n ) f ′ (x n ) d n d n /d<br />

n−1<br />

2<br />

0 1.3 -0.541058185 0.382501171<br />

1 2.714526871831 1.42796213 2.26744846 1.41452687<br />

2 2.084760792766 0.215754599 1.53401376 0.629766079 0.314743565<br />

3 1.944113685369 0.0137718957 1.33676314 0.140647107 0.35462739<br />

4 1.933811265085 7.60156095E-05 1.32199993 0.0103024203 0.520808008<br />

5 1.933753764621 2.37200355E-09 1.32191743 5.7500464E-05 0.541742396<br />

6 1.933753762827 -1.00668172E-16 1.79436599E-09 0.542710632<br />

50


4.8. Confronto tra i meto<strong>di</strong> <strong>di</strong> Newton-Raphson e la Regula Falsi<br />

Per la Regula Falsi:<br />

n x n f (x n )<br />

f (x n ) − f (x n−1 )<br />

d n d n /d<br />

x n − x n−1<br />

1.618<br />

n−1<br />

0 1.3 -0.541058185<br />

1 1.35 -0.520098358 0.419196552<br />

2 2.590702853065 1.15448972 1.34970922 1.24070285<br />

3 1.735341043061 -0.233640901 1.62285784 0.85536181 0.603386215<br />

4 1.879309845941 -0.0698346071 1.1377902 0.143968803 0.185374473<br />

5 1.940687248331 0.00919996444 1.28768192 0.0613774024 1.41231076<br />

6 1.933542654410 -0.000279035921 1.32673746 0.00714459392 0.653100215<br />

7 1.933752971771 -1.04570967E-06 1.3217654 0.000210317362 0.623935239<br />

8 1.933753762918 1.19824825E-10 1.32191686 7.91146198E-07 0.704441455<br />

9 1.933753762827 -1.00668172E-16 9.0644825E-11 0.676026603<br />

Attraverso gli scarti, abbiamo fatto una stima della costante asintotica dell’errore, considerando che, al<br />

limite per k → ∞, x n → ξ. Le ultime colonne delle tabelle, infatti, valutano i rapporti d n /dn−1 2 e d n/dn−1 1.618.<br />

Diamo un’ulteriore stima <strong>di</strong> tali costanti facendo uso della definizione teorica e considerando ξ ≈ x n .<br />

Per il metodo <strong>di</strong> Newton-Raphson dobbiamo calcolare M = |f ′′ (ξ)|<br />

2|f ′ mentre per la Regula Falsi dobbiamo<br />

(ξ)|<br />

considerare il valore M 0.618 .<br />

Poichè f ′′ (x) = 1/2+sin(x), abbiamo, per ξ ≈ x 6 (<strong>di</strong> Newton-Raphson) o, equivalentemente per ξ ≈ x 9 (della<br />

Regula Falsi), in pratica ξ ≈ 1.933753762827, f ′ (ξ) = 1.32191743 e f ′′ (ξ) = 1.4348509. Otteniamo quin<strong>di</strong>:<br />

M ≈ 0.542715784 e M 0.618 ≈ 0.685434221<br />

Esempio 4.8.2 Sia data f (x) = sin(x). Nell’intervallo ] − π/2,π/2[ la f ha esattamente una ra<strong>di</strong>ce, ξ = 0.<br />

Il metodo <strong>di</strong> Newton applicato alla funzione f , <strong>di</strong>venta:<br />

x n+1 = x n − tan(x n ), n = 0,1,2,...<br />

Se scegliamo come valore iniziale x 0 = x ∗ tale che tan(x ∗ ) = 2x ∗ , allora x 1 = −x 0 , x 2 = −x 1 = x 0 ... Si ha una<br />

situazione <strong>di</strong> stallo: i valori della successione saranno, alternativamente, x ∗ e −x ∗ e non avremo convergenza<br />

alla ra<strong>di</strong>ce ξ = 0. Il valore critico x ∗ vale 1.165561185207 e lo si può trovare numericamente applicando<br />

il metodo del punto fisso a alla funzione g (x) = arctan(2x).<br />

Ve<strong>di</strong>amo dunque cosa accade applicando il metodo <strong>di</strong> Newton-Raphson e la Regula Falsi utilizzando come<br />

x 0 = x ∗ ( e x 1 = −x 0 nella Regula Falsi). Facciamo i conti in singola precisione b , richiedendo un’accuratezza<br />

dell’or<strong>di</strong>ne ɛ = 10 −8 .<br />

a Se si considera g (x) = tan(x)/2 si trova il punto fisso 0 in quanto g ′ (x ∗ ) > 1 per g (x) = tan(x)/2.<br />

b Lavorando in doppia precisione non si riesce a osservare il comportamento ciclico ma si ha convergenza o <strong>di</strong>vergenza a<br />

seconda che si abbia un’iterata |x k | < o > x ∗ .<br />

51


4. ZERI DI FUNZIONE<br />

Abbiamo le seguenti tabelle.<br />

Per Newton-Raphson<br />

Per la Regula Falsi:<br />

n x n f (x n ) f ′ (x n ) d n<br />

0 1.1655612 0.919009745 0.394234866<br />

1 -1.1655612 -0.919009745 0.394234866 2.3311224<br />

2 1.1655612 0.919009745 0.394234866 2.3311224<br />

3 -1.1655612 -0.919009745 0.394234866 2.3311224<br />

.<br />

.<br />

.<br />

n 1.1655612 0.919009745 0.394234866 2.3311224<br />

n+1 -1.1655612 -0.919009745 0.394234866 2.3311224<br />

n x n f (x n )<br />

f (x n ) − f (x n−1 )<br />

x n − x n−1<br />

d n<br />

0 1.1655612 0.919009745<br />

1 -1.1655612 -0.919009745 0.788469732<br />

2 0.000000024087 0.000000024087 0.788469732 1.1655612<br />

3 -0.000000006462 -0.000000006462 3.05485912E-08 2.38417108E-08<br />

4 0.000000000000 0.0000000000000 6.46195142E-09<br />

Poche iterazioni sono necessarie perchè la Regula Falsi converga alla soluzione esatta.<br />

Perchè il metodo <strong>di</strong> Newton-Raphson converga il valore iniziale x 0 deve essere scelto tale che |x 0 | < x ∗ .<br />

.<br />

.<br />

Quando<br />

Newton-<br />

Raphson dà<br />

risultati<br />

scarsi<br />

Questo esempio ci permette <strong>di</strong> capire il significato <strong>di</strong> metodo generalmente convergente e il fatto che le proprietà<br />

<strong>di</strong> convergenza <strong>di</strong> un metodo possono valere localmente, cioè quando si è sufficientemente vicini alla<br />

ra<strong>di</strong>ce.<br />

Da un punto <strong>di</strong> vista pratico occorre prestare molta attenzione anche alla scelta del punto iniziale per il<br />

metodo <strong>di</strong> Newton-Raphson. Dal momento che la formula richiede una <strong>di</strong>visione per f ′ (x n ), occorre evitare<br />

<strong>di</strong> prendere un punto iniziale in cui la f abbia una tangente (e quin<strong>di</strong> f ′ ) con pendenza vicina allo zero. In tal<br />

caso, infatti, ci si può allontanare dalla ra<strong>di</strong>ce e il metodo può non convergere.<br />

Figura 4.7: Il metodo <strong>di</strong> Newton-Raphson applicato alla funzione f (x) = sin(x) con x 0 = x ∗ (a sinistra). La<br />

funzione f (x) = x 5 − 6 (a destra)<br />

52


4.9. Metodo <strong>di</strong> Newton-Raphson per ra<strong>di</strong>ci multiple<br />

Esempio 4.8.3 Consideriamo f (x) = x 5 − 6, per la quale f ′ (x) = 5x 4 , il cui grafico è in Figura 4.7 (a destra).<br />

Se partiamo da un punto iniziale prossimo allo zero, poichè la tangente alla f è quasi orizzontale, non si<br />

riesce ad avere convergenza se non dopo molte iterazioni: partendo da x 0 = 0.01 e richiedendo una tolleranza<br />

10 −8 , sono necessarie 88 iterazioni per arrivare a ξ = 1.430969081115725849. Ve<strong>di</strong>amo in tabella, come<br />

cambia il numero delle iterazioni al variare <strong>di</strong> x 0 :<br />

x 0 0.05 0.1 0.5 0.8 1.0 1.4 1.5 2. 3. 10. 20. 100.<br />

iterazioni 59 46 18 10 7 4 4 6 8 14 17 24<br />

4.9 Metodo <strong>di</strong> Newton-Raphson per ra<strong>di</strong>ci multiple<br />

Definizione 4.9.1 Data un’equazione f (x) = 0, una ra<strong>di</strong>ce ξ è multipla <strong>di</strong> molteplicità r se vale: f (ξ) = f ′ (ξ) =<br />

... = f r −1 (ξ) = 0 e f r (ξ) ≠ 0.<br />

Quando si ha una ra<strong>di</strong>ce multipla, il metodo <strong>di</strong> Newton-Raphson <strong>di</strong>venta un metodo del primo or<strong>di</strong>ne in<br />

quanto la formula che lega l’errore al passo n + 1 con l’errore al passo n <strong>di</strong>venta 3 :<br />

ɛ n+1 = r − 1 ɛ n<br />

r<br />

da cui la costante asintotica è M = r − 1 . Per poter avere un metodo che sia <strong>di</strong> nuovo a convergenza<br />

r<br />

quadratica, occorre mo<strong>di</strong>ficare l’algoritmo, ottenendo la formula <strong>di</strong> Newton-Raphson mo<strong>di</strong>ficata, nel modo<br />

seguente:<br />

x n+1 = x n − r f (x n)<br />

f ′ (x n )<br />

4.10 Controllo sugli scarti e grafici <strong>di</strong> convergenza<br />

Da un punto <strong>di</strong> vista pratico, il controllo per verificare la convergenza o meno della successione x n generata<br />

dallo schema iterativo viene effettuato sullo scarto d n = |x n − x n−1 | piuttosto che sull’errore (assoluto)<br />

ɛ n = |ξ − x n |, poichè, se avessimo informazioni sull’errore, conosceremmo anche il valore <strong>di</strong> ξ (che, in<br />

generale, non è noto).<br />

Nel caso del metodo <strong>di</strong> Newton-Raphson, quando è <strong>di</strong> or<strong>di</strong>ne 2, abbiamo visto che il controllo sullo scarto<br />

va bene (si veda quanto detto a pag. 48).<br />

Ve<strong>di</strong>amo cosa succede per meto<strong>di</strong> lineari. Sia tol l la tolleranza richiesta per approssimare ξ utilizzando<br />

gli scarti. Sappiamo che, per n grande e se il metodo converge, vale la relazione<br />

ɛ n+1 ≈ Mɛ n<br />

dove M < 1 è la costante asintotica.<br />

Riscriviamo la precedente formula come:<br />

Quin<strong>di</strong><br />

|ξ − x n+1 | ≈ M|ξ − x n | = M|ξ − x n + x n+1 − x n+1 | ≤ M (|ξ − x n+1 | + |x n+1 − x n |)<br />

ɛ n+1 ≤ M(ɛ n+1 + d n+1 )<br />

(1 − M)ɛ n+1 ≤ Md n+1<br />

3 Il proce<strong>di</strong>mento da seguire è del tutto simile a quanto è stato fatto nell’ipotesi in cui f ′ (ξ) ≠ 0. Come esercizio, si consiglia <strong>di</strong> provare<br />

a ricavare questo risultato.<br />

53


4. ZERI DI FUNZIONE<br />

Supponendo d n+1 ≤ tol l, vale<br />

ɛ n+1 ≤<br />

M<br />

1 − M d n+1 ≤ M<br />

1 − M tol l<br />

M<br />

Perciò, per<br />

1 − M < 1 (quin<strong>di</strong> per M < 1/2), se d n+1 ≤ tol l anche ɛ n+1 ≤ tol l. Se, invece, M ≥ 1/2, allora<br />

l’errore può essere più grande della tolleranza richiesta.<br />

Per quanto riguarda il metodo della secante variabile, poichè è superlineare, in base alla definizione,<br />

ɛ n+1 ≈ M n+1 ɛ n con M n+1 → 0, perciò si può vedere come un caso limite <strong>di</strong> convergenza lineare con fattore <strong>di</strong><br />

convergenza che tende a zero, e quin<strong>di</strong> il controllo dello scarto permette un buon controllo dell’errore.<br />

Quando si implementa un metodo iterativo, si può fare il grafico semilogaritmico <strong>di</strong> convergenza del<br />

metodo, ponendo sull’asse delle ascisse i valori delle iterazioni e sull’asse delle or<strong>di</strong>nate i logaritmi (in base<br />

10) <strong>degli</strong> scarti.<br />

Asintoticamente possiamo sostituire l’errore con lo scarto, nella definizione <strong>di</strong> or<strong>di</strong>ne <strong>di</strong> convergenza <strong>di</strong><br />

un metodo, per cui d n ≈ Md p n−1 .<br />

Nel caso in cui p = 1, si ha:<br />

d n ≈ Md n−1<br />

d n−1 ≈ Md n−2<br />

d n−2 ≈ Md n−3<br />

. . . .<br />

d 2 ≈ Md 1<br />

d 1 ≈ Md 0<br />

Partendo dalla prima relazione abbiamo:<br />

d n ≈ Md n−1 ≈ M 2 d n−2 ≈ M 3 d n−3 ≈ ... ≈ M n d 0<br />

Troviamo una relazione tra d n e d 0 . Passando ai logaritmi:<br />

log 10 (d n ) = n log 10 (M) + log 10 (d 0 )<br />

Abbiamo un’equazione del tipo y = ax + b dove y = log 10 (d n ) e x = n, che rappresenta l’equazione della retta<br />

nel nostro grafico semilogaritmico, e la pendenza della retta vale a = log 10 (M). Dalla pendenza della retta<br />

possiamo dunque risalire al valore della costante asintotica M.<br />

Nel caso in cui p ≠ 1 il <strong>di</strong>scorso si fa più complicato (e non staremo qui ad analizzarlo nei dettagli). Per<br />

esempio, per p = 2, si trova una curva che <strong>di</strong>pende da 2 n .<br />

Esempio 4.10.1 In Figura 4.8, riportiamo un esempio <strong>di</strong> grafico con i profili <strong>di</strong> convergenza per i meto<strong>di</strong><br />

<strong>di</strong> Newton-Raphson, secante variabile e punto fisso per trovare lo zero della funzione f (x) = x + ln(x)<br />

(applicando lo schema <strong>di</strong> punto fisso alla funzione g (x) = e −x ).<br />

54


4.11. <strong>Esercizi</strong><br />

Figura 4.8: Profili <strong>di</strong> convergenza a confronto<br />

4.11 <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 4.11.1 Si vuole risolvere l’equazione x = g (x) con lo schema del punto fisso; sapendo che<br />

g (x) = x 2 − 5x + 9<br />

(a) calcolare analiticamente il valore del punto fisso;<br />

(b) determinare il fattore <strong>di</strong> convergenza M dello schema del punto fisso;<br />

(c) calcolare le approssimazioni x 1 , x 2 e x 3 partendo prima da x 0 = 1 e poi da x 0 = 2.5 e giustificandone<br />

il <strong>di</strong>verso comportamento.<br />

Svolgimento<br />

(a) ξ è punto fisso della funzione g se verifica g (ξ) = ξ.<br />

Imponiamo dunque la con<strong>di</strong>zione g (ξ) = ξ. Ricaviamo ξ 2 − 5ξ + 9 = ξ, ovvero ξ 2 − 6ξ + 9 = 0, cioè<br />

(ξ − 3) 2 = 0, da cui ξ = 3 è punto fisso della g .<br />

(b) Il fattore <strong>di</strong> convergenza è M = g ′ (ξ).<br />

Poichè g ′ (x) = 2x − 5, si ha g ′ (ξ) = g ′ (3) = 1.<br />

Osserviamo che, a priori, non si può <strong>di</strong>re se lo schema del punto fisso converge o meno proprio<br />

perchè nel punto fisso la derivata prima vale esattamente 1, ma bisogna vedere caso per caso a seconda<br />

del punto iniziale da cui si fa partire il metodo.<br />

(c)<br />

Per x 0 = 1 si ha<br />

k x k g (x k )<br />

0 1 5<br />

1 5 9<br />

2 9 45<br />

3 45 1809<br />

Per x 0 = 2.5 si ha<br />

k x k g (x k )<br />

0 2.5 2.75<br />

1 2.75 2.8125<br />

2 2.8125 2.84765625<br />

3 2.84765625 2.870864868<br />

55


4. ZERI DI FUNZIONE<br />

Figura 4.9: <strong>Esercizi</strong>o sullo schema <strong>di</strong> punto fisso<br />

Per x 0 = 1 il metodo non converge, mentre per x 0 = 2.5 il metodo converge. La <strong>di</strong>versità <strong>di</strong> comportamento<br />

si giustifica graficamente, come si può vedere dalla Figura 4.9, osservando che per x 0 = 1 i<br />

valori ottenuti dallo schema si allontanano sempre più dal punto fisso. Nel secondo caso, al contrario,<br />

i valori si avvicinano con monotonia al punto fisso.<br />

<strong>Esercizi</strong>o 4.11.2 Si vuole risolvere l’equazione f (x) = 0 con f (x) = (x − 1) 2 + 3ln(x), nell’intervallo [0.5,2]<br />

con gli schemi <strong>di</strong> Newton-Raphson e della Regula Falsi.<br />

(a) Dimostrare esistenza e unicità della soluzione nell’intervallo considerato.<br />

(b) Calcolare le approssimazioni x 1 , x 2 e x 3 con lo schema <strong>di</strong> Newton-Raphson, partendo da x 0 = 0.5;<br />

(c) Calcolare le approssimazioni x 2 e x 3 con lo schema della Regula-Falsi partendo da x 0 = 0.5 e x 1<br />

calcolato al punto b).<br />

Stimare, inoltre il fattore <strong>di</strong> convergenza del metodo <strong>di</strong> Newton-Raphson assumendo ξ ≈ x 3 .<br />

Svolgimento<br />

(a) La funzione ammette valori opposti all’estremo dell’intervallo. Infatti f (0.5) = −1.82944154 e f (2) =<br />

3.07944154. Quin<strong>di</strong>, per il teorema del valor interme<strong>di</strong>o, esiste almeno una ra<strong>di</strong>ce. Inoltre f ′ (x) = 2(x −<br />

1) + 3 x = 2x2 − 2x + 3<br />

è sempre positivo nell’intervallo dato, (la parabola 2x 2 − 2x + 3 ha <strong>di</strong>scriminante<br />

x<br />

negativo e quin<strong>di</strong> è sempre positiva). Perciò, da f ′ (x) > 0 conclu<strong>di</strong>amo che la f è crescente. Di qui<br />

l’unicità della ra<strong>di</strong>ce.<br />

(b) Partendo da x 0 = 0.5, il metodo <strong>di</strong> Newton-Raphson fornisce i seguenti valori:<br />

56<br />

k x k f (x k ) f ′ (x k )<br />

0 0.50000000E+00 -0.18294415E+01 0.50000000E+01<br />

1 0.86588831E+00 -0.41401211E+00 0.31964267E+01<br />

2 0.99541173E+00 -0.13775443E-01 0.30046517E+01<br />

3 0.99999643E+00<br />

Dalla tabella sembra che i valori della successione tendano a 1. E, infatti, si vede facilmente che<br />

f (1) = 0 e quin<strong>di</strong> 1 è il valore che stiamo cercando. Per stimare la costante asintotica dell’errore del


4.11. <strong>Esercizi</strong><br />

metodo <strong>di</strong> Newton-Raphson assumendo ξ ≈ x 3 , occorre usare la formula<br />

M ≈ |f ′′ (x 3 )|<br />

2|f ′ (x 3 )|<br />

dove, nel caso specifico, vale f ′ (x) = 2(x − 1) + 3 x e f ′′ (x) = 2 − 3 x 2 .<br />

Usando il valore trovato per x 3 si ricava M ≈ 0.16667004E + 00.<br />

(c) Partendo da x 0 e x 1 del metodo <strong>di</strong> Newton-Raphson, la Regula Falsi dà:<br />

k x k f (x k )<br />

f (x n ) − f (x n−1 )<br />

x n − x n−1<br />

0 0.50000000E+00 -0.18294415E+01 -<br />

1 0.86588831E+00 -0.41401211E+00 0.38684741E+01<br />

2 0.97291038E+00 -0.81656072E-01 0.31054906E+01<br />

3 0.99920448E+00<br />

<strong>Esercizi</strong>o 4.11.3 Provare, anche solo graficamente, che l’equazione<br />

f (x) = sin(x) + x − 1 = 0<br />

ammette una sola ra<strong>di</strong>ce ξ nell’intervallo [0,1].<br />

(a) Dire se lo schema del punto fisso con g (x) = arcsin(1 − x) può convergere.<br />

(b) Partendo da x 0 = 0.1 calcolare le approssimazioni x 1 , x 2 e x 3 con lo schema <strong>di</strong> Newton-Raphson;<br />

(c) Dare una stima del fattore <strong>di</strong> convergenza.<br />

Svolgimento<br />

Graficamente, da f (x) = 0 si ha sin(x) = 1 − x. Se si stu<strong>di</strong>a l’intersezione delle due curve, sin(x) e 1 − x<br />

nell’intervallo [0,1], si può osservare una sola intersezione, cioè una sola ra<strong>di</strong>ce della f (fare il grafico delle<br />

due funzioni).<br />

Analiticamente, la funzione f (x) assume valori <strong>di</strong> segno opposto agli estremi dell’intervallo dato:<br />

f (0) = sin(0) + 0 − 1 = −1<br />

f (1) = sin(1) + 1 − 1 = 0.8414709848<br />

La derivata prima della f è f ′ = cos(x)+1: è funzione continua e sempre positiva nell’intervallo [0,1]. Quin<strong>di</strong><br />

f è una funzione crescente e interseca l’asse delle x solo una volta in [0,1], vale a <strong>di</strong>re ammette un’unica<br />

ra<strong>di</strong>ce.<br />

(a) Da f (x) = 0 si ha sin(x) + x − 1 = 0 o, equivalentemente, sin(x) = 1 − x, da cui x = arcsin(1 − x).<br />

Consideriamo perciò lo schema del punto fisso con g (x) data da g (x) = arcsin(1 − x). La derivata <strong>di</strong><br />

g (x) è g ′ 1<br />

(x) = √ .<br />

1 − (1 − x)<br />

2<br />

Nell’intervallo [0,1] valgono le seguenti <strong>di</strong>suguaglianze:<br />

0 ≤ x ≤ 1 =⇒ 0 ≥ −x ≥ −1 =⇒ 1 ≥ 1 − x ≥ 0 =⇒<br />

=⇒ 1 ≥ (1 − x) 2 ≥ 0 =⇒ −1 ≤ −(1 − x) 2 ≤ 0 =⇒ 0 ≤ 1 − (1 − x) 2 ≤ 1 =⇒<br />

√<br />

=⇒ 0 ≤ 1 − (1 − x) 2 1<br />

≤ 1 =⇒ 1 ≤ √<br />

1 − (1 − x)<br />

2<br />

Perciò g ′ (x) è sempre maggiore <strong>di</strong> 1 e lo schema del punto fisso non può convergere.<br />

(b) Da f (x) = sin(x) + x − 1 si ha f ′ (x) = cos(x) + 1 e f ′′ (x) = −sin(x). Il metodo <strong>di</strong> Newton-Raphson è:<br />

x k+1 = x k − sin(x) + x − 1<br />

cos(x) + 1 . 57


4. ZERI DI FUNZIONE<br />

Utilizziamo la notazione M 1 e M 2 per in<strong>di</strong>care la stima della costante asintotica dell’errore me<strong>di</strong>ante le<br />

formule<br />

M 1 = |x k+1 − x k |<br />

|x k − x k−1 | 2 o M 2 = |f ′′ (x k )|<br />

2|f ′ (x k )|<br />

Partendo da x 0 = 0.1 si ottengono i seguenti valori:<br />

k x k f (x k ) f ′ (x k ) |x k − x k−1 |<br />

0 0.1 -0.80016658E+00 0.19950042E+01 -<br />

1 0.50108517E+00 -0.18537249E-01 0.18770618E+01 0.40108517E+00<br />

2 0.51096084E+00 -0.23565955E-04 0.18722750E+01 0.98756733E-02<br />

3 0.51097343E+00 -0.38737166E-10 - 0.12586802E-04<br />

(c) La stima del fattore <strong>di</strong> convergenza è dato da M 1 = 0.12905712E+00 o da M 2 = 0.13059731E+00, a<br />

seconda della strada scelta per dare la stima.<br />

<strong>Esercizi</strong>o 4.11.4 Data l’equazione f (x) = ln(x) + x 2 − x = 0,<br />

(a) si provi, anche solo graficamente, che l’equazione ammette l’unica ra<strong>di</strong>ce ξ = 1 nell’intervallo<br />

[0.7,2.3];<br />

(b) si applichino due iterazioni del metodo <strong>di</strong>cotomico (o delle bisezioni) a partire dall’intervallo dato,<br />

chiamando con x 0 l’ultimo valore ottenuto con tale metodo;<br />

(c) a partire da x 0 del punto (b) si calcoli l’approssimazione x 1 con il metodo <strong>di</strong> Newton-Raphson;<br />

(d) a partire da x 0 e x 1 del punto (c) si calcolino le approssimazioni x 2 e x 3 con il metodo della Regula<br />

Falsi;<br />

(e) considerata la ra<strong>di</strong>ce esatta ξ = 1, si calcoli la costante asintotica <strong>di</strong> convergenza del metodo della<br />

Regula Falsi.<br />

Svolgimento<br />

(a) Da f (x) = 0 si ricava ln(x) = x − x 2 , per cui graficamente si può vedere che le due curve si intersecano<br />

in un solo punto, che vale ξ = 1.<br />

Analiticamente, invece, la funzione f (x) assume valori <strong>di</strong> segno opposto agli estremi dell’intervallo<br />

dato:<br />

f (0.7) = −0.566674943938732<br />

f (2.3) = 3.8229091229351<br />

Inoltre f è continua, quin<strong>di</strong> ammette almeno una ra<strong>di</strong>ce nell’intervallo dato. La derivata prima è:<br />

f ′ (x) = 1 x + 2x − 1, che possiamo anche scrivere come f ′ (x) = 1 + 2x2 − x<br />

: numeratore e denominatore<br />

x<br />

sono entrambi sempre positivi nell’intervallo dato, (la parabola 2x 2 − x + 1 ha <strong>di</strong>scriminante negativo<br />

∆ = −7, <strong>di</strong> conseguenza, per ogni x reale si ha 2x 2 − x + 1 > 0). Da f ′ (x) > 0 per ogni x segue che f è<br />

crescente e, quin<strong>di</strong>, ammette un’unica ra<strong>di</strong>ce.<br />

(b) Applichiamo il metodo delle bisezioni a partire dall’intervallo dato (utilizziamo la notazione x s per<br />

in<strong>di</strong>care l’estremo sinistro dell’intervallo, x d per in<strong>di</strong>care l’estremo destro dell’intervallo, x c , il punto<br />

me<strong>di</strong>o dell’intervallo considerato):<br />

iter. x s f (x s ) segno x d f (x d ) segno x c f (x c )<br />

1 0.7 -0.566674944 - 2.3 3.822909123 + 1.5 1.155465108<br />

2 0.7 -0.566674944 - 1.5 1.155465108 + 1.1 0.205310180<br />

Il valore x 0 è dunque x 0 = 1.1.<br />

(c) Il metodo <strong>di</strong> Newton-Rapshon è x k+1 = x k − f (x k)<br />

f ′ (x k ) dove f ′ = 1/x +2x −1. Partendo da x 0 = 1.1, si ricava<br />

x 1 = 1.1 − 0.20531018<br />

2.1090909 = 1.002654656<br />

58


4.11. <strong>Esercizi</strong><br />

(d) Applicando il metodo della Regula Falsi si ha:<br />

k x k f (x k )<br />

f (x k ) − f (x k−1 )<br />

x k − x k−1<br />

1 1.002654656 0.5312842078E-02 0.2054513650E+01<br />

2 1.000068720 0.1374413812E-03 0.2001364094E+01<br />

3 1.000000046<br />

(e) Considerato che la ra<strong>di</strong>ce esatta è ξ = 1, la costante asintotica <strong>di</strong> convergenza della Regula Falsi si calcola<br />

utilizzando l’espressione M = | f ′′ (ξ)<br />

2f ′ (ξ) |0.618 . Da f ′ (x) = 1 x + 2x − 1 segue f ′ (1) = 2 e f ′′ (x) = − 1 x 2 + 2,<br />

da cui f ′′ (1) = 1, per cui M = 1 0.618<br />

= 0.4245481.<br />

4<br />

59


C A P I T O L O<br />

5<br />

INTERPOLAZIONE<br />

Non vi è alcuna incompatibilità fra<br />

l’esatto e il poetico. Il numero è<br />

nell’arte come nella scienza.<br />

L’algebra è nell’astronomia e<br />

l’astronomia confina con la poesia.<br />

L’anima dell’uomo ha tre chiavi che<br />

aprono tutto: la cifra, la lettera, la<br />

nota. Sapere, pensare, sognare.<br />

Victor Hugo<br />

5.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />

5.2 Interpolazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />

5.3 Interpolazione polinomiale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

5.3.1 Funzioni base monomiali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

5.3.2 Polinomi <strong>di</strong> Lagrange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65<br />

5.3.3 Formula dell’errore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />

5.3.4 Differenze <strong>di</strong>vise e formula <strong>di</strong> Newton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68<br />

5.4 Considerazioni sull’interpolazione polinomiale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

5.4.1 Fenomeno <strong>di</strong> Runge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

5.4.2 Malcon<strong>di</strong>zionamento nell’interpolazione con funzioni base monomiali . . . . . . . . . . 72<br />

5.5 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />

5.1 Introduzione<br />

Il censimento della popolazione italiana, dall’unità d’Italia al 2001, ha visto un incremento della<br />

popolazione, come si può vedere in Tabella 5.1. Gli stessi dati sono riportati in Figura 5.1.<br />

Ci si può chiedere se questi dati possono essere utili (considerandoli tutti o solo una parte) per dare una<br />

ragionevole stima della popolazione nel 1975 o nel 1995 o per pre<strong>di</strong>re a quanto ammonterà nel 2015. Per far<br />

ciò, possiamo seguire due strade:<br />

G cercare una funzione che passi esattamente per i dati assegnati (detti anche punti <strong>di</strong> appoggio): questo<br />

proce<strong>di</strong>mento prende il nome <strong>di</strong> interpolazione ed è il soggetto <strong>di</strong> questo Capitolo;<br />

61


5. INTERPOLAZIONE<br />

Anno 1861 1871 1881 1901 1911 1921 1931<br />

Popolazione 22176 27300 28952 32963 35842 39397 41043<br />

Anno 1936 1951 1961 1971 1981 1991 2001<br />

Popolazione 42398 47516 50624 54137 56557 56778 56996<br />

Tabella 5.1: Dati forniti dall’ISTAT, tratti da http://dawinci.istat.it/daWinci/jsp/dawinci.jsp:<br />

popolazione residente dell’Italia ai confini ai confini attuali ai censimenti dal 1861 al 2001. Popolazione in<br />

migliaia.<br />

Figura 5.1: Censimento della popolazione residente in Italia.<br />

G cercare una funzione che, “in qualche modo” passi vicino ai dati assegnati: si parla <strong>di</strong> approssimazione<br />

(che vedremo nel prossimo Capitolo).<br />

In particolare, dato l’insieme dei punti (x i , y i ), i = 0,1,...,n, dove y i è il valore assunto da una funzione f<br />

in x i o il valore <strong>di</strong> un dato sperimentale, cerchiamo una funzione v(x) che, in maniera ragionevole si ad<strong>di</strong>ca<br />

all’insieme dei dati. Se i dati sono accurati, ha senso richiedere che la funzione interpoli i dati (cioè passi<br />

esattamente per le coppie <strong>di</strong> punti): v(x i ) = y i . Nell’approssimazione, invece, si cerca una funzione più<br />

semplice v(x) che sia vicina ad una funzione più complicata f (x) o ad una serie <strong>di</strong> dati.<br />

5.2 Interpolazione<br />

Una funzione <strong>di</strong> interpolazione v(x) serve per vari scopi.<br />

G Possiamo usare la v(x) per trovare valori approssimati y in punti x <strong>di</strong>versi da quelli assegnati<br />

x 0 , x 1 ,... x n . Se x si trova all’interno dell’intervallo che contiene le ascisse dei dati assegnati si parla<br />

<strong>di</strong> interpolazione. Se invece x si trova all’esterno dell’intervallo si ha estrapolazione. Nell’esempio della<br />

popolazione italiana, si interpolano i dati per stimare la popolazione nel 1975 o nel 1995, si applica<br />

invece un proce<strong>di</strong>mento <strong>di</strong> estrapolazione se si vuole stimare la popolazione del 2012.<br />

G Se le coppie <strong>di</strong> dati assegnati si riferiscono ad una funzione f (x), la funzione <strong>di</strong> interpolazione può<br />

essere utile per approssimare le derivate o gli integrali della f .<br />

Assumiamo che la funzione v <strong>di</strong> interpolazione sia una combinazione lineare <strong>di</strong> funzioni base <strong>di</strong> un<br />

qualche appropriato spazio <strong>di</strong> funzioni, cioè si possa scrivere come<br />

62<br />

v(x) = c 0 φ 0 (x) + ... + c n φ n (x)


5.3. Interpolazione polinomiale<br />

dove c i , i = 0,1,...,n sono i coefficienti incogniti (o parametri) da determinare in base ai dati in possesso,<br />

mentre φ i sono le funzioni base che assumiamo linearmente in<strong>di</strong>pendenti 1 .<br />

Esempi <strong>di</strong> interpolazione sono dati dall’interpolazione polinomiale, dall’interpolazione polinomiale a<br />

tratti, dall’interpolazione trigonometrica. Noi ci limitiamo a stu<strong>di</strong>are l’interpolazione polinomiale: date n +1<br />

coppie <strong>di</strong> punti (x i , y i ), per i = 0,1,...,n, andremo a cercare un polinomio p(x) <strong>di</strong> grado n per cui p(x i ) = y i .<br />

Parleremo, dunque, <strong>di</strong> polinomio <strong>di</strong> interpolazione p(x) (v(x) ≡ p(x)).<br />

Il processo <strong>di</strong> interpolazione si basa su due sta<strong>di</strong>:<br />

G costruire la funzione interpolante, cioè determinare i coefficienti c 0 , c 1 ,...,c n per un’assegnata base<br />

φ 0 ,φ 1 ,...,φ n ;<br />

G valutare la funzione interpolante in un assegnato punto x.<br />

Il primo punto è fatto una volta per tutte, una volta fissata la base e noto l’insieme dei punti da interpolare. Il<br />

secondo punto può essere applicato tutte le volte che si vuole valutare la funzione interpolante.<br />

5.3 Interpolazione polinomiale<br />

L’interpolazione polinomiale è il tipo <strong>di</strong> interpolazione più semplice. I polinomi, infatti, sono facili da<br />

costruire e da valutare, sono facili da sommare e moltiplicare (e il risultato è sempre un polinomio) e sono<br />

altrettanto facili da <strong>di</strong>fferenziare e integrare (e il risultato è sempre un polinomio).<br />

Sia p(x) = p n (x) un polinomio <strong>di</strong> grado n dato da<br />

p n (x) = c 0 + c 1 x + ... + c n x n<br />

Date n + 1 coppie <strong>di</strong> punti (x 0 , y 0 ), (x 1 , y 1 ), ..., (x n , y n ), vogliamo trovare gli n + 1 coefficienti c 0 ,c 1 ,...c n<br />

tali che p(x i ) = y i , i = 0,...,n.<br />

Ricor<strong>di</strong>amo che, un polinomio <strong>di</strong> grado n ha n+1 coefficienti e che, date n+1 coppie <strong>di</strong> punti, il polinomio<br />

interpolatore sarà <strong>di</strong> grado n.<br />

Assumiamo, inoltre, che le ascisse delle coppie dei punti siano <strong>di</strong>stinte, cioè x i ≠ x j , per i ≠ j .<br />

5.3.1 Funzioni base monomiali<br />

Utilizziamo come funzioni base i monomi x 0 , x 1 , x 2 ,..., x n .<br />

Esempio 5.3.1 Sia n + 1 = 2: abbiamo quin<strong>di</strong> due coppie <strong>di</strong> dati<br />

x i 1 2<br />

y i 1 3<br />

Cerchiamo quin<strong>di</strong> un polinomio <strong>di</strong> primo grado (una retta) che passi per i punti assegnati, della forma<br />

p(x) = p 1 (x) = c 0 + c 1 x.<br />

Le con<strong>di</strong>zioni <strong>di</strong> interpolazione <strong>di</strong>ventano:<br />

p 1 (x 0 ) = y 0 ⇐⇒ c 0 + 1c 1 = 1<br />

p 1 (x 1 ) = y 1 ⇐⇒ c 0 + 2c 1 = 3<br />

Abbiamo due equazioni in due incognite c 0 e c 1 . Risolvendo il sistema 2 × 2 otteniamo c 1 = 2 e c 0 = −1,<br />

quin<strong>di</strong> p 1 (x) = 2x − 1.<br />

1 Le funzioni φ 0 ,φ 1 ,...,φ n si <strong>di</strong>cono linearmente in<strong>di</strong>pendenti se vale: c 0 φ 0 (x) + ...c n φ n (x) ≡ 0 per ogni x se e solo se tutti i<br />

coefficienti sono nulli c 0 = ... = c n = 0.<br />

63


5. INTERPOLAZIONE<br />

Figura 5.2: Interpolazione lineare e quadratica<br />

Esempio 5.3.2 Consideriamo adesso un ulteriore coppia <strong>di</strong> punti per cui i dati che abbiamo sono n + 1 = 3<br />

e<br />

x i 1 2 4<br />

y i 1 3 3<br />

Il problema è ora <strong>di</strong>verso rispetto a quello appena risolto, perchè la terza coppia <strong>di</strong> punti specifica una<br />

valore y 2 ben <strong>di</strong>verso da quello predetto da p 1 in x 2 = 4. Difatti p 1 (x 2 ) = 7, nell’esempio precedente, mentre<br />

ora al valore <strong>di</strong> x 2 = 4 deve corrispondere y 2 = 3.<br />

Cerchiamo il polinomio <strong>di</strong> grado 2, quin<strong>di</strong>, della forma p 2 (x) = c 0 + c 1 x + c 2 x 2 che passa attraverso i punti<br />

dati.<br />

Le con<strong>di</strong>zioni <strong>di</strong> interpolazione adesso sono:<br />

⎧<br />

⎪⎨ p 2 (x 0 ) = c 0 + 1c 1 + 1c 2 = 1<br />

p 2 (x 1 ) = c 0 + 2c 1 + 4c 2 = 3<br />

⎪⎩<br />

p 2 (x 2 ) = c 0 + 4c 1 + 16c 2 = 3<br />

Abbiamo un sistema lineare <strong>di</strong> 3 equazioni in 3 incognite, la cui soluzione è:<br />

c 0 = − 7 3 , c 1 = 4, c 2 = − 2 3 .<br />

Il polinomio è p 2 (x) = (−2x 2 + 12x − 7)/3. Per x = 3 si ha p 2 (3) = 11 = 3.666666667, valore ben <strong>di</strong>verso da<br />

3<br />

p 1 (3) = 5. Del resto le curve che abbiamo ottenuto coincidono solo nei punti d’appoggio comuni a entrambe,<br />

una è una retta, l’altra è un polinomio <strong>di</strong> secondo grado (si veda Figura 5.2).<br />

Generalizzando gli esempi precedenti, date n + 1 coppie <strong>di</strong> punti, il polinomio <strong>di</strong> interpolazione <strong>di</strong> grado<br />

n sarà costruito risolvendo un sistema lineare <strong>di</strong> n equazioni nelle n incognite c 0 ,c 1 ,...,c n :<br />

⎧<br />

p n (x 0 ) = y 0 ⇐⇒ c 0 + c 1 x 0 + c 2 x0 2 + ... + c n x0 n = y 0<br />

64<br />

p ⎪⎨ n (x 1 ) = y 1 ⇐⇒ c 0 + c 1 x 1 + c 2 x1 2 + ... + c n x1 n = y 1<br />

p n (x 2 ) = y 2 ⇐⇒ c 0 + c 1 x 2 + c 2 x2 2 + ... + c n x2 n = y 2<br />

.<br />

⎪⎩<br />

p n (x n ) = y n ⇐⇒ c 0 + c 1 x n + c 2 xn 2 + ... + c n xn n = y n


5.3. Interpolazione polinomiale<br />

In forma compatta, sotto forma matriciale 2 le equazioni del sistema si possono scrivere come<br />

⎛<br />

1 x 0 x0 2 ... x n ⎞<br />

⎛ ⎞ ⎛ ⎞<br />

0<br />

1 x 1 x1 2 ... x1<br />

n c 0 y 0<br />

1 x 2 x 2 2<br />

... x2<br />

n c 1<br />

⎜<br />

⎝<br />

.<br />

.<br />

⎜<br />

.<br />

⎟⎝<br />

⎟<br />

. ⎠ = y 1<br />

⎜<br />

⎝<br />

⎟<br />

. ⎠<br />

. ⎠<br />

1 x n xn 2 ... xn<br />

n c n y n<br />

La matrice dei coefficienti è una matrice ben nota in letteratura e prende il nome <strong>di</strong> matrice <strong>di</strong> Vandermonde.<br />

3 È una matrice con determinante <strong>di</strong>verso da zero, e quin<strong>di</strong> il sistema ammette una ed una sola<br />

soluzione. Osserviamo che la prima colonna ha tutti gli elementi uguali a 1, la seconda colonna ha le ascisse<br />

dei punti <strong>di</strong> appoggio, la terza colonna ha i quadrati <strong>di</strong> esse, e così via.<br />

Perciò, date n+1 coppie <strong>di</strong> punti <strong>di</strong> appoggio (x i , y i ), i = 0,...,n, con ascisse <strong>di</strong>stinte<br />

x i , esiste un unico polinomio interpolatore p(x) <strong>di</strong> grado al più n tale che p(x i ) = y i ,<br />

i = 0,...,n.<br />

Tuttavia, la matrice <strong>di</strong> Vandermonde non ha buone proprietà: <strong>di</strong>fatti è una matrice malcon<strong>di</strong>zionata, e<br />

questo lo si osserva al crescere <strong>di</strong> n in quanto la soluzione del sistema <strong>di</strong>venta inaccurata 4 , qualunque metodo<br />

venga utilizzato per risolverlo.<br />

Questo approccio ci è servito per <strong>di</strong>mostrare che il polinomio <strong>di</strong> interpolazione esiste ed è unico, ma<br />

non è utile nella pratica a causa del malcon<strong>di</strong>zionamento. Sarebbe preferibile, quin<strong>di</strong>, poter usare funzioni<br />

base <strong>di</strong>verse dai monomi in modo da evitare il malcon<strong>di</strong>zionamento, avere meno operazioni dal punto <strong>di</strong><br />

vista computazionale e poter manipolare in maniera più efficiente le funzioni basi φ i in vista <strong>di</strong> una loro<br />

applicazione nella <strong>di</strong>fferenziazione e integrazione numerica.<br />

5.3.2 Polinomi <strong>di</strong> Lagrange<br />

Scriviamo il polinomio p(x) con i coefficienti c i uguali alle or<strong>di</strong>nate dei punti d’appoggio y i , c i ≡ y i :<br />

p(x) = p n (x) = y 0 φ 0 (x) + ... y n φ n (x)<br />

Una base <strong>di</strong> funzioni che ci permette una simile rappresentazione è data dai polinomi <strong>di</strong> Lagrange. 5<br />

I polinomi <strong>di</strong> Lagrange L j (x), per j = 0,1,...,n sono polinomi <strong>di</strong> grado n che, nei no<strong>di</strong> x i , sod<strong>di</strong>sfano la<br />

relazione<br />

{<br />

0 se i ≠ j<br />

L j (x i ) =<br />

1 se i = j<br />

Allora il polinomio p n (x) = ∑ n<br />

j =0 L j (x) · y j è tale che p n (x i ) = y i cioè sod<strong>di</strong>sfa la con<strong>di</strong>zione <strong>di</strong><br />

interpolazione, per ogni i = 0,...,n.<br />

2 Questo argomento verrà approfon<strong>di</strong>to nel Capitolo 7, dove riman<strong>di</strong>amo per i dettagli.<br />

3 Alexandre-Theophile Vandermonde, (1735-1796), abbandonò una carriera da violinista per de<strong>di</strong>carsi alla matematica quando<br />

aveva 35 anni. Si occupò <strong>di</strong> vari problemi <strong>di</strong> algebra, <strong>di</strong> topologia, calcolo combinatoriale, e teoria dei determinanti.<br />

4 Una matrice A è malcon<strong>di</strong>zionata quando, a piccole variazioni sui coefficienti della matrice, corrispondono gran<strong>di</strong> variazioni nella<br />

soluzione del sistema lineare Ax = b<br />

5 Joseph Louis Lagrange (1736-1813) nacque a Torino (come Giuseppe Luigi Lagrangia) e si trasferì in Francia, a Parigi, dove <strong>di</strong>venne<br />

citta<strong>di</strong>no francese adottando la traduzione francese del suo nome. Matematico e astronomo, <strong>di</strong>ede un importante contributo alla<br />

meccanica classica e celeste e alla teoria dei numeri.<br />

65


5. INTERPOLAZIONE<br />

I polinomi <strong>di</strong> Lagrange sono definiti dalla relazione: 6<br />

L j (x) =<br />

n∏<br />

k=0<br />

k≠j<br />

(x − x k )<br />

(x j − x k )<br />

In forma estesa abbiamo<br />

L j (x) = (x − x 0)···(x − x j −1 )(x − x j +1 )···(x − x n )<br />

(x j − x 0 )···(x j − x j −1 )(x j − x j +1 )···(x j − x n ) = n∏<br />

k=0<br />

k≠j<br />

x − x k<br />

x j − x k<br />

Esempio 5.3.3 Siano date le tre coppie <strong>di</strong> punti dell’esempio precedente (1,1), (2,3), (4,3). I polinomi <strong>di</strong><br />

Lagrange sono:<br />

(x − 2)(x − 4) (x − 2)(x − 4)<br />

L 0 (x) = =<br />

(1 − 2)(1 − 4) 3<br />

(x − 1)(x − 4) (x − 1)(x − 4)<br />

L 1 (x) = = −<br />

(2 − 1)(2 − 4) 2<br />

(x − 1)(x − 2) (x − 1)(x − 2)<br />

L 2 (x) = =<br />

(4 − 1)(4 − 2) 6<br />

Il polinomio si scrive, quin<strong>di</strong>, come<br />

p 2 (x) = L 0 (x) · 1 + L 1 (x) · 3 + L 2 (x) · 3 = 1 3 (x − 2)(x − 4) − 3 2 (x − 1)(x − 4) + 3 (x − 1)(x − 2)<br />

6<br />

Raccogliendo i termini ritroviamo p 2 (x) = (−2x 2 + 12x − 7)/3, lo stesso polinomio ottenuto con le funzioni<br />

base monomiali, e ciò è dovuto all’unicità del polinomio interpolatore.<br />

Formula<br />

dell’errore<br />

5.3.3 Formula dell’errore<br />

Supponiamo, ora, che le or<strong>di</strong>nate y i siano i valori <strong>di</strong> una funzione f valutata nei punti <strong>di</strong> appoggio x i . Conosciamo,<br />

quin<strong>di</strong>, una funzione f e <strong>di</strong> questa funzione vogliamo fare l’interpolazione sostituendola me<strong>di</strong>ante<br />

un polinomio <strong>di</strong> grado n tale che p(x i ) = f (x i ) = y i , i = 0,...,n.<br />

L’errore che si commette interpolando la funzione f con un polinomio p(x) <strong>di</strong> grado n vale<br />

f (x) − p(x) = f (n+1) (ξ(x))<br />

(n + 1)!<br />

n∏<br />

(x − x i )<br />

i=0<br />

6 Ricor<strong>di</strong>amo che, dati n valori w 1 , w 2 ,..., w n usiamo la seguente simbologia per in<strong>di</strong>care la loro somma e il loro prodotto, rispettivamente:<br />

.<br />

n∑<br />

w i = w 1 + w 2 + w 3 + ... + w n<br />

i=1<br />

n∏<br />

w i = w 1 · w 2 · w 3 · ... · w n<br />

i=1<br />

66


5.3. Interpolazione polinomiale<br />

Figura 5.3: Polinomi <strong>di</strong> Lagrange L 0 (x), L 1 (x), L 2 (x), con x 0 = 1, x 1 = 2, x 2 = 4.<br />

Proviamo questo risultato introducendo il polinomio F (x) <strong>di</strong> grado n + 1 che si annulla<br />

nelle n + 1 ascisse dei dati assegnati.<br />

F (x) =<br />

n∏<br />

(x − x k )<br />

k=0<br />

Consideriamo, inoltre, un punto t <strong>di</strong>stinto dai punti <strong>di</strong> appoggio e compreso nell’intervallo<br />

I in<strong>di</strong>viduato dai valori minimo e massimo delle ascisse dei punti <strong>di</strong> appoggio.<br />

f (t) − p(t)<br />

Definiamo la quantità S che <strong>di</strong>pende da t, data da S = e la funzione G(x) = f (x)− p(x)−SF (x).<br />

F (t)<br />

La funzione G si annulla non solo negli n +1 punti d’appoggio poichè G(x i ) = f (x i )− p(x i )−SF (x i ) = 0 per<br />

i = 0,...,n ma anche in t a causa <strong>di</strong> come è stato definito S. Si annulla, quin<strong>di</strong>, in n + 2 punti.<br />

Per il teorema <strong>di</strong> Rolle, la derivata prima si annulla n + 1 volte in I . Applicando ripetutamente il teorema<br />

<strong>di</strong> Rolle sulle derivate successive, si arriva alla derivata n + 1-sima <strong>di</strong> G, che si annulla almeno 1 volta in I .<br />

Sia ξ il punto in cui G (n+1) (ξ) = 0. Ma a<br />

G (n+1) (ξ) = f (n+1) (ξ) − S(n + 1)!<br />

Si ha perciò:<br />

f (n+1) f (t) − p(t)<br />

(ξ) − S(n + 1)! = 0 ovvero<br />

= S = f (n+1) (ξ)<br />

F (t)<br />

(n + 1)!<br />

Considerando, ora, x al posto <strong>di</strong> t, e scrivendo ξ come funzione <strong>di</strong> x (in quanto il valore <strong>di</strong> ξ <strong>di</strong>pende da x)<br />

e scrivendo in forma estesa il polinomio F (x), otteniamo<br />

f (x) − p(x) = f (n+1) (ξ(x)) n∏<br />

(x − x i )<br />

(n + 1)!<br />

i=0<br />

a La derivata n +1-sima <strong>di</strong> un polinomio <strong>di</strong> grado n è una quantità nulla, mentre la derivata n +1-sima <strong>di</strong> un polinomio <strong>di</strong> grado<br />

n + 1, quale è F (x), vale (n + 1)!.<br />

Abbiamo quin<strong>di</strong> una formula per l’errore, detta anche formula del resto. Il resto normalmente è incognito<br />

ma se conosciamo la f e una maggiorazione della f (n+1) , allora possiamo maggiorare il resto.<br />

Allo stesso modo, possiamo limitare l’errore <strong>di</strong> interpolazione se troviamo un limite superiore per |F (x)|.<br />

67


5. INTERPOLAZIONE<br />

Differenze<br />

<strong>di</strong>vise e<br />

formula <strong>di</strong><br />

Newton<br />

5.3.4 Differenze <strong>di</strong>vise e formula <strong>di</strong> Newton<br />

Uno dei punti forti della rappresentazione <strong>di</strong> Lagrange è che se alcuni dati cambiano (ad esempio il valore<br />

<strong>di</strong> y j per un certo j ) allora il cambiamento è imme<strong>di</strong>atamente visibile nell’intero polinomio <strong>di</strong> interpolazione.<br />

Uno dei punti deboli, invece, è la procedura per valutare p n (x). Con la formula <strong>di</strong> Newton abbiamo un utile<br />

compromesso.<br />

Le funzioni base che ora consideriamo sono<br />

j∏<br />

−1<br />

φ j (x) = (x − x i ) j = 0,1,...,n<br />

i=0<br />

Quin<strong>di</strong> vogliamo scrivere il polinomio <strong>di</strong> interpolazione come:<br />

p(x) = c 0 + c 1 (x − x 0 ) + c 2 (x − x 0 )(x − x 1 ) + ... + c n (x − x 0 )(x − x 1 ) · ...(x − x n−1 )<br />

dove c 0 , c 1 ...c n sono delle costanti da definire in modo opportuno.<br />

Esempio 5.3.4 Consideriamo sempre le tre coppie <strong>di</strong> punti <strong>degli</strong> esempi precedenti, (1,1), (2,3) e (4,3).<br />

Per costruire p 2 (x) abbiamo bisogno <strong>di</strong> φ 0 , φ 1 e φ 2 :<br />

φ 0 (x) = 1<br />

φ 1 (x) = (x − x 0 ) = (x − 1)<br />

φ 2 (x) = (x − x 0 )(x − x 1 ) = (x − 1)(x − 2)<br />

La con<strong>di</strong>zione <strong>di</strong> interpolazione in x 0 = 1 porta a:<br />

f (x 0 ) = 1 = p 2 (x 0 ) = p 2 (1) = c 0 φ 0 (1) + c 1 φ 1 (1) + c 2 φ 2 (1) = c 0 · 1 + c 1 · 0 + c 2 · 0<br />

Quin<strong>di</strong> c 1 = 1 = f (x 0 ).<br />

In x 1 = 2 abbiamo:<br />

f (x 1 ) = 3 = p 2 (x 1 ) = p 2 (3) = f (x 0 ) + c 1 φ 1 (2) + c 2 φ 2 (2) = f (x 0 ) + c 1 · 1 + c 2 · 0<br />

Ricaviamo quin<strong>di</strong> c 1 = f (x 1) − f (x 0 )<br />

= 3 − 1 = 2. Chiamiamo questa quantità <strong>di</strong>fferenza <strong>di</strong>visa del primo<br />

x 1 − x 0 2 − 1<br />

or<strong>di</strong>ne tra x 0 e x 1 e la in<strong>di</strong>chiamo con f [x 0 , x 1 ]. Quin<strong>di</strong><br />

f [x 0 , x 1 ] = f (x 1) − f (x 0 )<br />

x 1 − x 0<br />

Infine,<br />

f (x 2 ) = 3 = p 2 (x 2 ) = p 2 (4) = f (x 0 ) + f [x 0 , x 1 ]φ 1 (4) + c 2 φ 2 (4)<br />

= f (x 0 ) + f [x 0 , x 1 ](4 − 1) + c 2 (4 − 1)(4 − 2)<br />

Per ottenere una formula per c 2 che abbia carattere generale, riscriviamo l’equazione precedente utilizzando<br />

i simboli x 0 , x 1 , x 2 per le ascisse.<br />

In x 1 si ha f (x 1 ) = p 2 (x 1 ) = f (x 0 ) + f [x 0 , x 1 ](x 1 − x 0 ).<br />

In x 2 si ha f (x 2 ) = p 2 (x 2 ) = f (x 0 ) + f [x 0 , x 1 ](x 2 − x 0 ) + c 2 (x 2 − x 0 )(x 2 − x 1 ).<br />

Sottraendo membro a membro la prima equazione dalla seconda si ricava:<br />

f (x 2 ) − f (x 1 ) = f [x 0 , x 1 ](x 2 − x 0 − x 1 + x 0 ) + c 2 (x 2 − x 0 )(x 2 − x 1 )<br />

f (x 2 ) − f (x 1 ) = f [x 0 , x 1 ](x 2 − x 1 ) + c 2 (x 2 − x 0 )(x 2 − x 1 )<br />

Quin<strong>di</strong><br />

f (x 2 ) − f (x 1 ) − f [x 0 , x 1 ](x 2 − x 1 ) = c 2 (x 2 − x 0 )(x 2 − x 1 )<br />

f (x 2 ) − f (x 1 )<br />

x 2 − x 1<br />

− f [x 0 , x 1 ] x 2 − x 1<br />

x 2 − x 1<br />

= c 2 (x 2 − x 0 )<br />

f (x 2 ) − f (x 1 )<br />

x 2 − x 1<br />

− f [x 0 , x 1 ] = c 2 (x 2 − x 0 )<br />

68


5.3. Interpolazione polinomiale<br />

Ma f (x 2) − f (x 1 )<br />

x 2 − x 1<br />

= f [x 1 , x 2 ] è la <strong>di</strong>fferenza <strong>di</strong>visa del primo or<strong>di</strong>ne tra x 1 e x 2 da cui<br />

f [x 1 , x 2 ] − f [x 0 , x 1 ] = c 2 (x 2 − x 0 ) =⇒ c 2 = f [x 1, x 2 ] − f [x 0 , x 1 ]<br />

x 2 − x 0<br />

La quantità chiamata c 2 prende il nome <strong>di</strong> <strong>di</strong>fferenza <strong>di</strong>visa del secondo or<strong>di</strong>ne e si in<strong>di</strong>ca con<br />

f [x 0 , x 1 , x 2 ] = f [x 1, x 2 ] − f [x 0 , x 1 ]<br />

x 2 − x 0<br />

.<br />

Facendo le opportune sostituzioni si ricava c 2 = − 4 6 = − 2 3 . Quin<strong>di</strong>, p 2(x) = f (x 0 ) + f [x 0 , x 1 ](x − x 0 ) +<br />

f [x 0 , x 1 , x 2 ](x − x 0 )(x − x 1 ) Nell’esempio considerato: p 2 (x) = 1 + 2(x − 1) − 2 (x − 1)(x − 2)<br />

3<br />

Date le stesse coppie <strong>di</strong> punti, abbiamo visto come cambia la rappresentazione (usando come funzioni<br />

base i monomi, poi i polinomi <strong>di</strong> Lagrange e ora la formulazione <strong>di</strong> Newton) ma il polinomio finale è sempre<br />

lo stesso essendo unico il polinomio interpolatore.<br />

Da questo esempio, si può vedere come la rappresentazione secondo Newton sia <strong>di</strong> tipo ricorsivo: il polinomio<br />

p 1 (x) = f (x 0 ) + f [x 0 , x 1 ](x − x 0 ) (che si ha arrestandosi ai primi due passi del proce<strong>di</strong>mento appena<br />

effettuato) è un polinomio, in tal caso una retta, che interpola i dati (x 0 , y 0 ), e (x 1 , y 1 ). Il polinomio p 2 (x) è dato<br />

dalla somma <strong>di</strong> p 1 (x) e del termine f [x 0 , x 1 , x 2 ](x − x 0 )(x − x 1 ). Quin<strong>di</strong>, una volta determinato il polinomio<br />

p n−1 che interpola i primi n dati, possiamo usare questa rappresentazione per costruire p n che interpola i<br />

dati precedenti cui si aggiunge la coppia (x n , y n ).<br />

Il coefficiente c j del polinomio interpolatore <strong>di</strong> Newton si chiama <strong>di</strong>fferenza <strong>di</strong>visa <strong>di</strong> or<strong>di</strong>ne j e viene<br />

in<strong>di</strong>cata con f [x 0 , x 1 ,..., x j ].<br />

Perciò:<br />

f [x 0 ] = c 0 , f [x 0 , x 1 ] = c 1 , ..., f [x 0 , x 1 ,..., x n ] = c n<br />

La notazione utilizzata ci permette <strong>di</strong> capire anche da quali coppie <strong>di</strong> punti <strong>di</strong>pende il coefficiente c j .<br />

Dati i punti x 0 , x 1 ,..., x n , per in<strong>di</strong>ci i e j arbitrari con 0 ≤ i ≤ j ≤ n, si ha<br />

f [x i ] = f (x i )<br />

f [x i ,..., x j ] = f [x i+1,... x j ] − f [x i ,..., x j −1 ]<br />

x j − x i<br />

La formula interpolatoria alle <strong>di</strong>fferenze <strong>di</strong>vise <strong>di</strong> Newton è dunque data da<br />

p n (x) = f [x 0 ] + f [x 0 , x 1 ](x − x 0 ) + f [x 0 , x 1 , x 2 ](x − x 0 )(x − x 1 ) + ...<br />

+ f [x 0 , x 1 ,..., x n ](x − x 0 )(x − x 1 )···(x − x n−1 )<br />

Da un punto <strong>di</strong> vista computazionale i coefficienti si ricavano me<strong>di</strong>ante la tabella delle <strong>di</strong>fferenze <strong>di</strong>vise,<br />

tenendo presente che per calcolare f [x 0 , x 1 ,..., x n ] dobbiamo aver calcolato tutte le <strong>di</strong>fferenze <strong>di</strong>vise<br />

f [x j −k ,..., x j ], con 0 ≤ k ≤ j ≤ n.<br />

69


5. INTERPOLAZIONE<br />

x i f [·] f [·,·] f [·,·,·] f [·,·,·,·] f [·,·,·,·,·]<br />

x 0 f (x 0 )<br />

f [x 0 , x 1 ]<br />

x 1 f (x 1 ) f [x 0 , x 1 , x 2 ]<br />

f [x 1 , x 2 ] f [x 0 , x 1 , x 2 , x 3 ]<br />

x 2 f (x 2 ) f [x 1 , x 2 , x 3 ] f [x 0 , x 1 , x 2 , x 3 , x 4 ]<br />

f [x 2 , x 3 ] f [x 1 , x 2 , x 3 , x 4 ]<br />

x 3 f (x 3 ) f [x 2 , x 3 , x 4 ]<br />

x 4 f (x 4 )<br />

.<br />

.<br />

f [x 3 , x 4 ]<br />

.<br />

.<br />

I coefficienti della <strong>di</strong>agonale principale sono i coefficienti c j del polinomio interpolatore <strong>di</strong> Newton.<br />

.<br />

.<br />

Esempio 5.3.5 Costruiamo la tabella delle <strong>di</strong>fferenze <strong>di</strong>vise per i dati (1,1), (2,3) e (4,3).<br />

x i f [·] f [·,·] f [·,·,·]<br />

1 1<br />

2<br />

2 3 − 2 3<br />

0<br />

4 3<br />

Il polinomio p 2 (x) si scrive: p 2 (x) = 1 + 2(x − 1) − 2 (x − 1)(x − 2).<br />

3<br />

Se vogliamo aggiungere altri dati, per esempio, la coppia (5,4), dobbiamo aggiungere una riga alla tabella<br />

della <strong>di</strong>fferenza <strong>di</strong>visa e un termine al polinomio che abbiamo già ricavato per ottenere quello <strong>di</strong> grado<br />

superiore interpolante tutti i dati che abbiamo a <strong>di</strong>sposizione.<br />

x i f [·] f [·,·] f [·,·,·] f [·,·,·,·]<br />

1 1<br />

2<br />

2 3 − 2 3<br />

0<br />

1<br />

4 3<br />

3<br />

1<br />

5 4<br />

1<br />

4<br />

Il polinomio p 3 (x) è p 3 (x) = p 2 (x) + 1 (x − 1)(x − 2)(x − 4).<br />

4<br />

Il concetto <strong>di</strong> <strong>di</strong>fferenza <strong>di</strong>visa può essere visto come un’estensione del concetto <strong>di</strong> derivata <strong>di</strong> una funzione.<br />

Si ha, infatti, che, per f derivabile, la <strong>di</strong>ffenza <strong>di</strong>visa del primo or<strong>di</strong>ne f [x 0 , x 1 ] può essere vista come<br />

un rapporto incrementale e quin<strong>di</strong>, al limite per x 1 → x 0 , si ha f ′ (x 0 ).<br />

70


5.4. Considerazioni sull’interpolazione polinomiale<br />

Derivata<br />

k-sima della<br />

f<br />

La <strong>di</strong>fferenza <strong>di</strong>visa k-sima e la derivata k-sima <strong>di</strong> f sono legate tra loro. Si può provare, infatti, per k ≥ 1<br />

che vale la relazione<br />

f [x 0 , x 1 ,..., x k ] = f (k) (ξ)<br />

k!<br />

dove ξ è un punto appartente all’interno dell’intervallo in<strong>di</strong>viduato dagli estremi <strong>di</strong> x 0 ,..., x k . Quando i punti<br />

coincidono, si ha<br />

f [ x 0,x 0 ,...,x 0<br />

} {{ }<br />

] = f (k) (x 0 )<br />

k!<br />

k+1 volte<br />

Questa formula serve per calcolare il polinomio <strong>di</strong> interpolazione che interpola non solo una certa funzione<br />

f ma anche le sue derivate in alcuni punti assegnati (si veda l’esercizio 5.5.3 a fine Capitolo).<br />

Se al polinomio p n (x) aggiungiamo la coppia <strong>di</strong> dati (x, f (x)) si ha p n+1 (x) = f (x) = p n (x) +<br />

f [x 0 , x 1 ,..., x n , x](x − x 0 )(x − x 1 ) · ...(x − x n ). L’ultima <strong>di</strong>fferenza <strong>di</strong>visa non si può calcolare, poichè <strong>di</strong>pende<br />

da x (che è la nostra variabile), ma ci è utile per capire quanto vale l’errore che commettiamo nell’approssimare<br />

f (x) me<strong>di</strong>ante il polinomio interpolatore, applicando la rappresentazione <strong>di</strong> Newton. Inoltre, dato che<br />

il polinomio interpolatore è unico (fissate le coppie <strong>di</strong> dati del problema), anche l’errore che si commette è lo<br />

stesso, qualunque sia la strategia utilizzata per arrivare ad esso. Quin<strong>di</strong> possiamo eguagliare l’errore trovato<br />

utilizzando i polinomi <strong>di</strong> Lagrange con l’errore trovato nella rappresentazione <strong>di</strong> Newton, ottenendo:<br />

f (n+1) (ξ(x)) n∏<br />

n∏<br />

(x − x i ) = f [x 0 , x 1 ,..., x n , x] (x − x i )<br />

(n + 1)!<br />

i=0<br />

5.4 Considerazioni sull’interpolazione polinomiale<br />

5.4.1 Fenomeno <strong>di</strong> Runge<br />

i=0<br />

Formula<br />

dell’errore<br />

Data una funzione f , si pensa che il polinomio <strong>di</strong> interpolazione possa approssimare bene la funzione,<br />

soprattutto se si aumenta il numero dei punti <strong>di</strong> appoggio. In realtà questo non è sempre vero e un semplice<br />

e famoso esempio ce lo fa capire. Sia data la funzione <strong>di</strong> Runge 7 1<br />

f (x) = e consideriamo il polino- Fenomeno <strong>di</strong><br />

1 + x2 Runge<br />

mio <strong>di</strong> interpolazione <strong>di</strong> questa funzione per valori crescenti <strong>di</strong> n prendendo punti <strong>di</strong> appoggio equi<strong>di</strong>stanti<br />

nell’intervallo [−5,5]. Partiamo da n + 1 = 2 con i punti equi<strong>di</strong>stanti x 0 = −5, x 1 = 0 e x 2 = 5. Si ha la tabella<br />

x i −5 0 5<br />

y i = f (x i ) 3.846154e − 2 1. 3.846154e − 2<br />

Costruiamo quin<strong>di</strong> il polinomio <strong>di</strong> interpolazione p 2 (x) (utilizzando l’approccio <strong>di</strong> Lagrange o <strong>di</strong> Newton, i<br />

risultati non cambiano). Raddoppiamo il numero dei punti aggiungendo un punto tra x 0 e x 1 e uno tra x 1 e<br />

x 2 . Abbiamo n + 1 = 5 e i valori della tabella<br />

x i −5 −2.5 0 2.5 5<br />

y i = f (x i ) 3.846154e − 2 1.379310e − 1 1. 1.379310e − 1 3.846154e − 2<br />

Con lo stesso proce<strong>di</strong>mento, costruiamo i polinomi <strong>di</strong> interpolazione <strong>di</strong> grado 8 e 16. In Figura 5.4 sono riportati<br />

i grafici della funzione <strong>di</strong> Runge (in nero) e dei polinomi interpolanti <strong>di</strong> grado 2, 4 e 8. Si può osservare<br />

che solo in un sottointervallo <strong>di</strong> [−5,5] al crescere <strong>di</strong> n, i polinomi convergono alla funzione. Agli estremi<br />

dell’intervallo [−5,5] si hanno oscillazioni che aumentano sempre più al crescere <strong>di</strong> n. Infatti in Figura 5.5<br />

(a sinistra) non si riesce più a <strong>di</strong>stinguere il profilo della funzione <strong>di</strong> Runge perchè il polinomio <strong>di</strong> interpolazione<br />

<strong>di</strong> grado 16 ha delle oscillazioni molto alte. Tuttavia, se restringiamo questo grafico in un intorno<br />

dell’origine, possiamo vedere come il polinomio p 16 si avvicini bene alla funzione – si veda la Figura 5.5 (a<br />

destra)! L’esempio <strong>di</strong> Runge è utile per capire che la scelta dei no<strong>di</strong> equi<strong>di</strong>stanti non si rivela sempre la scelta<br />

giusta e che altri tipi <strong>di</strong> interpolazione possono dare risultati migliori. Per indagare ulteriormente su questo<br />

problema, si rimanda alla letteratura specializzata del settore.<br />

7 Carl Runge (1856-1927) fu un matematico tedesco. Fu studente <strong>di</strong> Weierstrass, Kirchhoff, Helmholtz. Iniziò poi a collaborare con<br />

Kronecker e poi si de<strong>di</strong>cò in particolare allo stu<strong>di</strong>o della soluzione numerica <strong>di</strong> equazioni algebriche e alla spettroscopia.<br />

71


5. INTERPOLAZIONE<br />

Figura 5.4: Funzione <strong>di</strong> Runge e polinomi interpolanti <strong>di</strong> grado 2, 4 e 8.<br />

Figura 5.5: Funzione <strong>di</strong> Runge e polinomio interpolante <strong>di</strong> grado 16 su tutto l’intervallo [−5,5] (a sinistra) e in<br />

un sottointervallo (a destra)<br />

5.4.2 Malcon<strong>di</strong>zionamento nell’interpolazione con funzioni base monomiali<br />

All’inizio <strong>di</strong> questo Capitolo, abbiamo introdotto il polinomio <strong>di</strong> interpolazione me<strong>di</strong>ante funzioni base<br />

monomiali: il problema dell’interpolazione veniva risolto me<strong>di</strong>ante un sistema lineare la cui matrice, <strong>di</strong><br />

Vandermonde, è malcon<strong>di</strong>zionata.<br />

Ve<strong>di</strong>amo <strong>di</strong> capire questo malcon<strong>di</strong>zionamento me<strong>di</strong>ante un esempio. Si voglia stu<strong>di</strong>are l’interpolazione<br />

dei seguenti dati<br />

x i 1010.5 1011.5 1012.5 1013 1014 1015<br />

y i 4 2.5 2.5 2 2 0<br />

Confrontando i vari algoritmi <strong>di</strong> interpolazione, osserveremo che gli algoritmi <strong>di</strong> Lagrange e delle <strong>di</strong>fferenze<br />

<strong>di</strong>vise <strong>di</strong> Newton danno buoni risultati. Al contrario, il metodo che porta alla costruzione della matrice<br />

<strong>di</strong> Vandermonde dà risultati <strong>di</strong>sastrosi, come si può vedere in Figura 5.6. Eppure, dal punto <strong>di</strong> vista teorico i<br />

risultati dovrebbero essere identici.<br />

72


5.5. <strong>Esercizi</strong><br />

Figura 5.6: Effetti del malcon<strong>di</strong>zionamento<br />

Perchè si hanno questi risultati? Bisogna tener conto <strong>di</strong> tre aspetti: il calcolo della matrice <strong>di</strong> Vandermonde;<br />

la soluzione del sistema lineare per ricavare i coefficienti del polinomio con funzioni base monomiali; il<br />

calcolo dei valori del polinomio.<br />

La matrice <strong>di</strong> Vandermonde consiste <strong>di</strong> colonne che crescono <strong>di</strong> colonna in colonna - 1, x i , x 2 i , x3 i , ...,<br />

x 5 i . Per questo caso test, si va da 1 a elementi dell’or<strong>di</strong>ne <strong>di</strong> 1015 . La matrice è molto mal con<strong>di</strong>zionata.<br />

Perciò la soluzione del sistema lineare non può dare risultati affidabili e il vettore che fornisce i coefficienti del<br />

polinomio interpolatore è completamente errato. Ciò porta anche al fenomeno della cancellazione numerica<br />

nel calcolo del polinomio <strong>di</strong> interpolazione, per cui si ha una significativa per<strong>di</strong>ta <strong>di</strong> accuratezza e il grafico<br />

risultante presenta un profilo altamente oscillante.<br />

5.5 <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 5.5.1 Sia data la tabella seguente:<br />

x i -1 0 2 3 4<br />

f (x i ) 9 0 0 15 84<br />

(a) Scrivere la tabella delle <strong>di</strong>fferenze <strong>di</strong>vise.<br />

(b) Trovare il polinomio interpolatore (con la formula <strong>di</strong> Newton) <strong>di</strong> grado non superiore a 4.<br />

Svolgimento<br />

(a) La tabella delle <strong>di</strong>fferenza <strong>di</strong>vise è:<br />

(b) Il polinomio <strong>di</strong> Newton <strong>di</strong> grado 4 che interpola i dati assegnati è dunque (prendendo i valori della<br />

73


5. INTERPOLAZIONE<br />

x i f (x i ) f (·,·) f (·,·,·) f (·,·,·,·) f (·,·,·,·,·)<br />

-1 9<br />

0 0<br />

0 − 9<br />

0 − (−1) = −9<br />

2 0<br />

3 15<br />

4 84<br />

0 − 0<br />

2 − 0 = 0 0 + 9<br />

2 − (−1) = 3<br />

15 − 0<br />

3 − 2 = 15 15 − 0<br />

3 − 0 = 5 5 − 3<br />

3 − (−1) = 0.5<br />

84 − 15<br />

4 − 3 = 69 69 − 15<br />

4 − 2 = 27 27 − 5<br />

4 − 0 = 11 2<br />

11/2 − 1/2<br />

= 1<br />

4 − (−1)<br />

<strong>di</strong>agonale principale della tabella)<br />

p(x) = 9 − 9(x + 1) + 3(x + 1)x + 0.5(x + 1)x(x − 2) + (x + 1)x(x − 2)(x − 3) =<br />

= x 4 − 3.5x 3 + 3.5x 2 − x<br />

<strong>Esercizi</strong>o 5.5.2 Sia data la tabella seguente:<br />

x i 0 0.1 0.8 1.2<br />

f (x i ) 1 0.48 1.32 5.32<br />

(a) Scrivere la tabella delle <strong>di</strong>fferenze <strong>di</strong>vise.<br />

(b) Usando i quattro punti in successione, scrivere i polinomi interpolanti (<strong>di</strong> Newton) p n (x) <strong>di</strong> grado<br />

non superiore ad n (con n=0,1,2,3); commentare il risultato.<br />

(c) Usando p n (x) stimare, per ogni n, f (0.6) e f ′ (0.6).<br />

(d) scrivere il polinomio p 2 (x) con la formula <strong>di</strong> Lagrange.<br />

Svolgimento<br />

(a) La tabella delle <strong>di</strong>fferenza <strong>di</strong>vise è:<br />

x i f (x i ) f (·,·) f (·,·,·) f (·,·,·,·)<br />

0 1<br />

0.1 0.48<br />

0.48 − 1<br />

= −5.2<br />

0.1<br />

0.8 1.32<br />

1.32 − 0.48<br />

= 1.2<br />

0.7<br />

1.2 + 5.2<br />

= 8<br />

0.8<br />

1.2 5.32<br />

5.32 − 1.32<br />

= 10<br />

0.4<br />

10 − 1.2<br />

= 8<br />

1.1<br />

8 − 8<br />

1.2 = 0<br />

74


5.5. <strong>Esercizi</strong><br />

(b) I polinomi <strong>di</strong> Newton <strong>di</strong> grado 0,1,2 e 3 sono:<br />

p 0 (x) = 1<br />

p 1 (x) = 1 − 5.2x<br />

p 2 (x) = 1 − 5.2x + 8x(x − 0.1) = 8x 2 − 6x + 1<br />

p 3 (x) = 1 − 5.2x + 8x(x − 0.1) + 0x(x − 0.1)(x − 0.8) = 1 − 5.2x + 8x(x − 0.1) = p 2 (x)<br />

Il polinomio p 3 (x) coincide con p 2 (x) in quanto p 2 (x 3 ) = p 2 (1.2) = f (1.2) = f (x 3 ) cioè il polinomio<br />

<strong>di</strong> grado 2 interpola non solo i dati (x 0 , f (x 0 )), (x 1 , f (x 1 )) e (x 2 , f (x 2 )) ma anche (x 3 , f (x 3 )).<br />

(c) Per le derivate <strong>di</strong> p n (x), n = 0,1,2 si ha<br />

p ′ 0 (x) = 0<br />

p 1 ′ (x) = −5.2<br />

p 2 ′ (x) = 16x − 6<br />

La stima <strong>di</strong> f (0.6) e f ′ (0.6) è:<br />

n p n (0.6) p n ′ (0.6)<br />

0 1 0<br />

1 -2.12 -5.2<br />

2 0.28 3.6<br />

(d) I polimoni <strong>di</strong> Lagrange per ricavare il polinomio p 2 sono dati considerando i valori x 0 , x 1 e x 2 :<br />

(x − 0.1)(x − 0.8)<br />

L 0 (x) =<br />

(−0.1)(−0.8)<br />

L 1 (x) =<br />

L 2 (x) =<br />

x(x − 0.8)<br />

0.1(0.1 − 0.8) = x2 − 0.8x<br />

−0.07<br />

x(x − 0.1)<br />

0.8(0.8 − 0.1) = x2 − 0.1x<br />

0.56<br />

= x2 − 0.9x + 0.08<br />

0.08<br />

Il polinomio è:<br />

p 2 (x) = 1L 0 (x) + 0.48L 1 (x) + 1.32L 2 (x)<br />

= x2 − 0.9x + 0.08<br />

− 0.48 x2 − 0.8x<br />

+ 1.32 x2 − 0.1x<br />

0.08<br />

0.07<br />

0.56<br />

= 12.5(x 2 − 0.9x + 0.08) − 6.857142857(x 2 − 0.8x) + 2.357142857(x 2 − 0.1x)<br />

e raccogliendo i termini<br />

p 2 (x) = 8x 2 − 6x + 1<br />

<strong>Esercizi</strong>o 5.5.3 Trovare il polinomio <strong>di</strong> grado non superiore a 4 che interpola i dati seguenti: f (0) =<br />

2, f ′ (0) = 7, f ′′ (0) = 18, f (1) = 27 f ′ (1) = 60. Stimare f (0.2) e f ′ (0.2).<br />

Svolgimento<br />

75


5. INTERPOLAZIONE<br />

Costruiamo la tabella delle <strong>di</strong>fferenze <strong>di</strong>vise tenendo presente che le derivate <strong>di</strong> una funzione f si possono<br />

avere come limite delle <strong>di</strong>fferenze <strong>di</strong>vise:<br />

f [0,0] = f ′ (0) = 7 f [0,0,0] = f ′′ (0)<br />

2!<br />

= 9 f [1,1] = f ′ (1) = 60<br />

Tenendo conto <strong>di</strong> queste relazioni tra <strong>di</strong>fferenze <strong>di</strong>vise e derivate, nella tabella delle <strong>di</strong>fferenzi <strong>di</strong>vise,<br />

dobbiamo ripetere per tre volte l’ascissa 0 e due volte l’ascissa 1. Si ottiene:<br />

0 2<br />

f ′ (0)=7<br />

0 2 f ′′ (0)/2=9<br />

0 2<br />

1 27<br />

1 27<br />

f ′ (0)=7<br />

18 − 9<br />

1 − 0 =9<br />

25 − 7<br />

1 − 0 =18 17 − 9<br />

1 − 0 =8<br />

27 − 2<br />

1 − 0 =25 35 − 18<br />

1 − 0 =17<br />

60 − 25<br />

1 − 0 =35<br />

f ′ (1)= 60<br />

Il polinomio è dunque p(x) = 2 + 7x + 9x 2 + 9x 3 + 8x 3 (x − 1), vale a <strong>di</strong>re<br />

p(x) = 8x 4 + x 3 + 9x 2 + 7x + 2.<br />

La stima <strong>di</strong> f (0.2) è data da: f (0.2) ≈ p(0.2) = 3.7808.<br />

Per stimare f ′ (0.2) dobbiamo prima calcolare la derivata prima <strong>di</strong> p. Si ha<br />

p ′ (x) = 32x 3 + 3x 2 + 18x + 7,<br />

da cui f ′ (0.2) ≈ p ′ (0.2) = 12.056.<br />

76


C A P I T O L O<br />

6<br />

APPROSSIMAZIONE<br />

I numeri governano il mondo.<br />

Platone<br />

6.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

6.2 Retta <strong>di</strong> regressione lineare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />

6.3 Approssimazione polinomiale ai minimi quadrati . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80<br />

6.4 Approssimazioni <strong>di</strong> tipo esponenziale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />

6.5 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />

6.1 Introduzione<br />

La legge <strong>di</strong> Hooke stabilisce che l’allungamento subito da una molla, costruita con materiale uniforme,<br />

è <strong>di</strong>rettamente proporzionale alla forza applicata: F (x) = kx dove k è la costante <strong>di</strong> proporzionalità, detta<br />

costante elastica, e x rappresenta l’allungamento della molla.<br />

Supponiamo <strong>di</strong> voler determinare k per una molla che, quando è a riposo, esercita una forza <strong>di</strong><br />

1.4724811N . Se applichiamo una forza pari a 2.418165N si misura un allungamento pari a 0.042m. Siano<br />

effettuate <strong>di</strong>verse misure, ricavando i dati <strong>di</strong> Tabella 6.1. I dati raccolti non giacciono esattamente su una<br />

x 0.00000 0.04200 0.08000 0.11800 0.15600<br />

F 1.472481 2.418165 3.363849 4.309533 5.255217<br />

Tabella 6.1: Dati sperimentali per la legge <strong>di</strong> Hooke<br />

linea retta. Per approssimare la costante elastica k, potremmo prendere una qualunque coppia <strong>di</strong> dati e fare<br />

il rapporto tra la forza e l’allungamento. In questo modo, tuttavia, non terremmo conto <strong>di</strong> tutte le misure<br />

effettuate. È più ragionevole trovare la linea retta che meglio approssima tutti i dati sperimentali e utilizzarla<br />

per approssimare il valore <strong>di</strong> k. Questo tipo <strong>di</strong> approssimazione sarà l’argomento <strong>di</strong> questo Capitolo.<br />

A <strong>di</strong>fferenza dell’interpolazione, in cui si cerca una funzione che passi esattamente per i dati assegnati,<br />

nell’approssimazione si cerca una funzione (più semplice <strong>di</strong> quella data, se vi è una funzione <strong>di</strong> partenza) che<br />

approssimi al meglio i dati assegnati, senza passare esattamente per questi.<br />

Alcuni dei motivi che spingono a cercare una funzione <strong>di</strong> approssimazione piuttosto che <strong>di</strong> interpolazione<br />

sono questi:<br />

77


6. APPROSSIMAZIONE<br />

Figura 6.1: Legge <strong>di</strong> Hooke: i dati sperimentali<br />

x i 1 2 3 4 5 6 7 8 9 10<br />

y i 1.2 2.3 4.5 5.1 7 8.5 10.2 13.1 12.5 16.5<br />

Tabella 6.2: Dati sperimentali<br />

G i dati a <strong>di</strong>sposizione sono affetti da errore;<br />

G siamo interessati a vedere l’andamento dei dati su lunga scala, in una visione globale 1<br />

G vogliamo che la funzione <strong>di</strong>penda da pochi parametri, sebbene questi siano determinati considerando<br />

tutti i dati a <strong>di</strong>sposizione.<br />

Nel seguito stu<strong>di</strong>eremo l’approssimazione ai minimi quadrati.<br />

6.2 Retta <strong>di</strong> regressione lineare<br />

Supponiamo <strong>di</strong> avere i 10 dati sperimentali della Tabella 6.2 (quin<strong>di</strong> n + 1 = 10). La Figura 6.2 (a sinistra)<br />

mostra il grafico delle coppie <strong>di</strong> punti: appare evidente che la relazione tra x e y è <strong>di</strong> tipo lineare. Il motivo<br />

per cui i dati non sono esattamente su una retta è dovuto ad errori nei dati. Non ha senso, quin<strong>di</strong>, cercare una<br />

funzione che passi esattamente per i dati assegnati (come accade nell’interpolazione), perchè una funzione<br />

del genere introdurrebbe oscillazioni prive <strong>di</strong> significato fisico: lo ve<strong>di</strong>amo andando a costruire il polinomio<br />

<strong>di</strong> interpolazione <strong>di</strong> grado 9 che passa esattamente per i dati e che ve<strong>di</strong>amo in Figura 6.2 (a destra). Cerchiamo<br />

allora una retta (funzione lineare, poichè abbiamo visto che i dati hanno una relazione <strong>di</strong> tipo lineare) che<br />

meglio approssima i dati senza dover coincidere con essi. Sia p 1 (x) = a 0 + a 1 x la retta che an<strong>di</strong>amo cercando<br />

(dobbiamo quin<strong>di</strong> capire come trovare i due coefficienti a 0 e a 1 ). Allora p 1 (x i ) = a 0 + a 1 x i , per i = 0,1,...,n<br />

rappresenta il valore sulla retta che deve approssimare il valore y i dato dal problema. Per ogni dato sperimentale,<br />

per i = 0,1,...,n, possiamo misurare lo scarto che scaturisce dall’approssimare y i me<strong>di</strong>ante a 0 + a 1 x i .<br />

Nell’approccio ai minimi quadrati, si cerca <strong>di</strong> minimizzare la somma dei quadrati delle <strong>di</strong>fferenze tra i valori<br />

dati y i e i valori corrispondenti p 1 (x i ) sulla retta; si cerca, cioè, <strong>di</strong> minimizzare la somma dei quadrati <strong>degli</strong><br />

1 Se si hanno a <strong>di</strong>sposizione n = 100 dati, anche molto accurati, una funzione interpolante può dare una buona idea localmente,<br />

mentre una funzione approssimante data da una retta fornisce una migliore idea del comportamento su lunga scala dei dati.<br />

78


6.2. Retta <strong>di</strong> regressione lineare<br />

Figura 6.2: Dati sperimentali (a sinistra) della Tabella 6.2 e polinomio <strong>di</strong> interpolazione (a destra).<br />

scarti. Introduciamo, quin<strong>di</strong> la funzione che <strong>di</strong>pende dai coefficienti incogniti a 0 e a 1 .<br />

S(a 0 , a 1 ) =<br />

n∑ [ ] 2<br />

(a0 + a 1 x i ) − y i<br />

i=0<br />

Per minimizzare questa funzione, occorre porre le derivate parziali della S rispetto ad a 0 e a 1 uguali a zero. 2<br />

Si pone dunque<br />

0 = ∂S(a 0, a 1 )<br />

∂a 0<br />

= ∂<br />

∂a 0<br />

0 = ∂S(a 0, a 1 )<br />

∂a 1<br />

= ∂<br />

∂a 1<br />

n∑ [ ] 2<br />

n∑ [ ]<br />

(a0 + a 1 x i ) − y i = 2 (a0 + a 1 x i ) − y i<br />

i=0<br />

i=0<br />

n∑ [ ] 2<br />

n∑ [ ]<br />

(a0 + a 1 x i ) − y i = 2 (a0 + a 1 x i ) − y i xi<br />

i=0<br />

Queste equazioni si semplificano nel sistema delle cosiddette equazioni normali:<br />

{<br />

(n + 1)a0 + a 1<br />

∑ n<br />

i=0 x i = ∑ n<br />

i=0 y i<br />

a 0<br />

∑ n<br />

i=0 x i + a 1<br />

∑ n<br />

i=0 x2 i = ∑ n<br />

i=0 x i y i<br />

i=0<br />

Introducendo la notazione A 12 = ∑ n<br />

i=0 x i , A 22 = ∑ n<br />

i=0 x2 i , b 1 = ∑ n<br />

i=0 y i e b 2 = ∑ n<br />

i=0 x i y i e osservando che la<br />

matrice del sistema è simmetrica (A 12 = A 21 ), la soluzione è data da:<br />

a 0 = A 22b 1 − A 12 b 2<br />

(n + 1)A 22 − A 2 12<br />

a 1 = (n + 1)b 2 − A 12 b 1<br />

(n + 1)A 22 − A 2 12<br />

Nell’esempio proposto, per calcolare la retta <strong>di</strong> approssimazione ai minimi quadrati, dobbiamo calcolare<br />

i coefficienti delle equazioni normali. In Tabella 6.3 poniamo i valori che servono per risolvere il sistema: la<br />

soluzione è a 0 = −0.87333333 e a 1 = 1.62969697. La retta è rappresentata in Figura 6.3.<br />

La retta che abbiamo appena costruito è la retta che minimizza gli scarti verticali, supponendo affetti<br />

da errore le or<strong>di</strong>nate delle coppie <strong>di</strong> punti a <strong>di</strong>sposizione. Essa prende pure il nome <strong>di</strong> retta <strong>di</strong> regressione<br />

lineare sugli scarti verticali.<br />

Osserviamo che il baricentro dei punti assegnati giace sulla retta ai minimi quadrati, in quanto considerando<br />

la prima equazione del sistema si ha, per X = ∑ n<br />

i=0 x i /(n + 1) e Y = ∑ n<br />

i=0 y i /(n + 1) (le coor<strong>di</strong>nate del<br />

baricentro dei punti assegnati):<br />

Sul<br />

baricentro<br />

a 0 + a 1 X = Y<br />

2 Per funzioni f (x) <strong>di</strong> una variabile reale, i punti <strong>di</strong> massimo o minimo si trovano tra i punti critici della f , per i quali f ′ (x) = 0,<br />

stu<strong>di</strong>ando il segno della f ′′ . Analogo proce<strong>di</strong>mento si segue per funzioni <strong>di</strong> due variabili. Per la funzione S(a 0 , a 1 ) che stiamo stu<strong>di</strong>ando,<br />

si può provare che i valori (a 0 , a 1 ) che annullano le derivate parziali della S rappresentano i valori che minimizzano la S stessa. Questo<br />

argomento viene approfon<strong>di</strong>to nei corsi <strong>di</strong> Analisi Matematica.<br />

79


6. APPROSSIMAZIONE<br />

x i y i x 2 x<br />

i i y i<br />

1 1.2 1 1.2<br />

2 2.3 4 4.6<br />

3 4.5 9 13.5<br />

4 5.1 16 20.4<br />

5 7 25 35<br />

6 8.5 36 51<br />

7 10.2 49 71.4<br />

8 13.1 64 104.8<br />

9 12.5 81 112.5<br />

10 16.5 100 165<br />

A 12 = 55 b 1 = 80.9 A 22 = 385 b 2 = 579.4<br />

Tabella 6.3: Tabella per il calcolo della retta <strong>di</strong> approssimazione ai minimi quadrati<br />

Figura 6.3: Retta <strong>di</strong> approssimazione sugli scarti verticali.<br />

Se invece sono affetti da errore le ascisse delle coppie <strong>di</strong> punti, si può cercare la retta che minimizza gli<br />

scarti orizzontali, detta anche retta <strong>di</strong> regressione lineare sugli scarti orizzontali, (basta scambiare il ruolo<br />

delle x con quello delle y per ricavare, con lo stesso proce<strong>di</strong>mento, la retta p 1 (y) = b 0 + b 1 y). Il baricentro dei<br />

punti assegnati giace anche su questa retta, da cui possiamo concludere che esso è il punto <strong>di</strong> intersezione<br />

delle due rette che minimizzano gli scarti verticali e orizzontali.<br />

6.3 Approssimazione polinomiale ai minimi quadrati<br />

In generale, avendo a <strong>di</strong>sposizione n+1 coppie <strong>di</strong> punti, il problema <strong>di</strong> approssimazione si può ricondurre<br />

alla ricerca <strong>di</strong> un polinomio <strong>di</strong> approssimazione <strong>di</strong> grado m, p m (x) = a 0 + a 1 x + a 2 x 2 + ...+ a m x m con m < n.<br />

Quando n = m il polinomio d’approssimazione coincide con quello d’interpolazione.<br />

80


6.4. Approssimazioni <strong>di</strong> tipo esponenziale<br />

La funzione da minimizzare è<br />

n∑ [<br />

S(a 0 , a 1 ,..., a m ) = (a0 + a 1 x i + a 2 x 2 i + ... + a m x m ] 2<br />

i<br />

) − y i<br />

i=0<br />

La procedura seguita per la retta viene generalizzata. Questa volta bisogna porre uguali a zero le m+1 derivate<br />

parziali della S rispetto ai coefficienti del polinomio p m .<br />

∂S<br />

∂a j<br />

= 0<br />

Ricaviamo, quin<strong>di</strong><br />

2<br />

j = 0,1,...,m<br />

n∑<br />

(a 0 + a 1 x i + ... + a m x m i<br />

− y i )x j = 0 per j = 0,1,...,m<br />

i<br />

i=0<br />

In forma estesa possiamo scrivere<br />

n∑<br />

n∑<br />

x j i + a 1<br />

a 0<br />

i=0<br />

x j +1<br />

i=0<br />

i<br />

+ ... + a m<br />

n∑<br />

x j +m =<br />

i<br />

i=0<br />

i=0<br />

n∑<br />

x j i y i<br />

per j = 0,1,...,m<br />

Poichè queste equazioni si hanno per j = 0,1...,m, si ha da risolvere un sistema, che, scritto in forma<br />

matriciale, è:<br />

A T Aa = A T b<br />

dove A è una matrice rettangolare (n + 1) × (m + 1), data da<br />

⎛<br />

1 x 0 x0 2 ... x m ⎞<br />

0<br />

1 x 1 x1 2 ... x m 1<br />

A =<br />

⎜<br />

⎝<br />

.<br />

.<br />

.<br />

⎟<br />

. ⎠<br />

1 x n xn 2 ... xn<br />

m<br />

Le equazioni del sistema sono dette equazioni normali. Si può provare che la matrice Q = A T A è<br />

simmetrica, definita positiva 3 ed è non singolare, quin<strong>di</strong> il sistema ammette soluzione.<br />

6.4 Approssimazioni <strong>di</strong> tipo esponenziale<br />

Può capitare che i dati sperimentali abbiano un andamento <strong>di</strong> tipo esponenziale o ricor<strong>di</strong>no una funzione<br />

potenza della variabile x. Allora si può richiedere che la funzione approssimante abbia una delle due forme<br />

seguenti (e, a seconda della rappresentazione, si ha un <strong>di</strong>verso modello):<br />

y(x) = ae bx<br />

y(x) = ax b<br />

modello esponenziale<br />

modello potenza<br />

con a e b opportune costanti. Per ricavare a e b si passa ai logaritmi ricavando l’equazione <strong>di</strong> una retta i cui<br />

coefficienti sono ottenuti con la procedura <strong>di</strong> minimizzazione ai minimi quadrati. Da questi, si ritorna poi ai<br />

coefficienti delle funzioni <strong>di</strong> partenza. Ve<strong>di</strong>amo come.<br />

G Nel caso del modello esponenziale, passando ai logaritmi (in base naturale) si ha:<br />

ln(y) = ln(a) + bx<br />

Ponendo X = x, Y = ln(y), a 0 = ln(a) e a 1 = b, si ha un’equazione del tipo Y = a 0 + a 1 X .<br />

Quin<strong>di</strong>, dalle coppie <strong>di</strong> dati (x i , y i ) i = 0,1,...,n, si deve passare alle coppie (X i = x i , Y i = ln(y i ))<br />

e su queste coppie si costruisce la retta <strong>di</strong> approssimazione ai minimi quadrati con la procedura che<br />

abbiamo stu<strong>di</strong>ato in Sezione 6.2. Una volta ricavati i coefficienti a 0 e a 1 , si ha a = e a 0<br />

e b = a 1 .<br />

3 Le definizioni <strong>di</strong> matrice simmetrica e matrice definita positiva sono date nel Capitolo 7.<br />

81


6. APPROSSIMAZIONE<br />

G Nel caso del modello potenza, passando ai logaritmi (qualunque sia la base usata, il risultato non<br />

cambia) si ha:<br />

log(y) = log(a) + b log(x)<br />

Ponendo X = log(x), Y = log(y), a 0 = log(a) e a 1 = b, si ha un’equazione del tipo Y = a 0 + a 1 X .<br />

Quin<strong>di</strong>, dalle coppie <strong>di</strong> dati (x i , y i ) i = 0,1,...,n, si deve passare alle coppie (X i = log(x i ), Y i =<br />

log(y i )) e su queste coppie si costruisce la retta <strong>di</strong> approssimazione ai minimi quadrati. Una volta<br />

ricavati i coefficienti a 0 e a 1 , si ha b = a 1 mentre, con gli opportuni passaggi, si trova il valore <strong>di</strong> a.<br />

6.5 <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 6.5.1 Sia data la tabella seguente:<br />

x i -1 0 2 3 4<br />

f (x i ) 9 0 0 15 84<br />

(a) Trovare la retta ai minimi quadrati che minimizza la somma dei quadrati <strong>degli</strong> scarti verticali.<br />

(b) Trovare la retta ai minimi quadrati che minimizza la somma dei quadrati <strong>degli</strong> scarti orizzontali.<br />

(c) Calcolare il punto <strong>di</strong> intersezione delle due rette e <strong>di</strong>re <strong>di</strong> che punto si tratta.<br />

Svolgimento<br />

(a) Il sistema da risolvere per ottenere la retta <strong>di</strong> approssimazione ai minimi quadrati è:<br />

{<br />

(n + 1)a0 + ∑ n<br />

i=0 x i a 1 = ∑ n<br />

i=0 y i<br />

∑ n<br />

i=0 x i a 0 + ∑ n<br />

i=0 x2 i a 1 = ∑ n<br />

i=0 x i y i<br />

dove n + 1 = 5. Poichè ∑ 4<br />

i=0 x i = 8, ∑ 4<br />

i=0 x2 i = 30, ∑ 4<br />

i=0 y i = 108 e ∑ 4<br />

i=0 x i y i = 372, si ha il sistema<br />

{<br />

5a0 + 8a 1 = 108<br />

8a 0 + 30a 1 = 372<br />

La soluzione è a 0 = 3.069767442, a 1 = 11.581395349. La retta ai minimi quadrati che minimizza gli<br />

scarti verticali è: y = 3.069767442 + 11.581395349x.<br />

(b) Ricaviamo la retta <strong>di</strong> approssimazione che minimizza gli scarti orizzontali.<br />

{<br />

(n + 1)b0 + ∑ n<br />

i=0 y i b 1 = ∑ n<br />

i=0 x i<br />

∑ n<br />

i=0 y i b 0 + ∑ n<br />

i=0 y 2 i b 1 = ∑ n<br />

i=0 y i x i<br />

dove n + 1 = 5. Poichè ∑ 4<br />

i=0 y i = 108, ∑ 4<br />

i=0 y 2 i = 7362, ∑ 4<br />

i=0 x i = 8 e ∑ 4<br />

i=0 x i y i = 372, si ha il sistema<br />

{<br />

5b0 + 108b 1 = 8<br />

108b 0 + 7362b 1 = 372<br />

La soluzione è b 0 = 0.744452398, b 1 = 0.03960868528. La retta ai minimi quadrati che minimizza gli<br />

scarti orizzontali è: x = 0.744452398 + 0.03960868528y.<br />

82


6.5. <strong>Esercizi</strong><br />

(c) Troviamo il punto <strong>di</strong> intersezione delle due rette:<br />

{<br />

y = 3.069767442 + 11.581395349x<br />

x = 0.744452398 + 0.03960868528y<br />

Ricaviamo x = 1.6 e y = 21.6<br />

Se calcoliamo il baricentro dei punti assegnati, troviamo<br />

∑ 4<br />

i=0<br />

X =<br />

x i<br />

= −1 + 2 + 3 + 4<br />

∑ 4<br />

i=0<br />

= 1.6 Y =<br />

y i 9 + 15 + 84<br />

= ) = 21.6<br />

5<br />

5<br />

5<br />

5<br />

Il punto <strong>di</strong> intersezione delle due rette è il baricentro dei punti assegnati.<br />

<strong>Esercizi</strong>o 6.5.2 Sono assegnati i seguenti dati sperimentali<br />

x i 4.0 4.2 4.5 4.7 5.1 5.5 5.9 6.3 6.8 7.1<br />

y i 102.56 113.18 131.2 142 168 196.2 225 256.8 299.51 325.6<br />

Costruire la curva <strong>di</strong> approssimazione ai minimi quadrati della forma ax b .<br />

Svolgimento Per trovare la curva <strong>di</strong> approssimazione del tipo y = ax b , dobbiamo prima passare ai logaritmi:<br />

log(y) = log(ax b ) = log(a) + b log(x)<br />

In questo modo ci riconduciamo ad una retta <strong>di</strong> approssimazione ai minimi quadrati sui logaritmi dei punti<br />

assegnati. Consideriamo il logaritmo naturale (ma i risultati non cambiano con i logaritmi in un’altra base).<br />

I dati su cui lavorare sono dunque:<br />

log(x i ) log(y i )<br />

1.386294361 4.630447993<br />

1.435084525 4.728979472<br />

1.504077397 4.876722876<br />

1.547562509 4.955827058<br />

3.931825633 5.123963980<br />

1.704748092 5.279134547<br />

1.774952351 5.416100402<br />

1.840549633 5.548297572<br />

1.916922612 5.702147806<br />

1.960094784 5.785669634<br />

Calcoliamo la retta <strong>di</strong> approssimazione ai minimi quadrati, ponendo X i = log(x i ) e Y i = log(y i ). Il sistema<br />

da risolvere è<br />

{<br />

(n + 1)a0 + ∑ n<br />

i=0 X i a 1 = ∑ n<br />

i=0 Y i<br />

∑ n<br />

i=0 X i a 0 + ∑ n<br />

i=0 X 2 i a 1 = ∑ n<br />

i=0 X i Y i<br />

dove n + 1 = 10.<br />

Si ha ∑ n<br />

i=0 X i = 16.6995268, ∑ n<br />

i=0 X 2 = 28.2537116, ∑ n<br />

i i=0 Y i = 52.0472913, ∑ n<br />

i=0 X i Y i = 87.6541085<br />

Il sistema da risolvere <strong>di</strong>venta<br />

{<br />

10a0 + 16.6995268a 1 = 52.0472913<br />

16.6995268a 0 + 28.2537116a 1 = 87.6541085<br />

che ha come soluzione a 0 = 1.84197978 e a 1 = 2.013679425.<br />

Ora a 0 = log(a) da cui a = e a 0<br />

= 6.30901637 Invece a 1 = b. Il modello y = ax b <strong>di</strong>venta quin<strong>di</strong> y =<br />

6.30901637x 2.013679425 .<br />

83


C A P I T O L O<br />

7<br />

METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

All’inizio e alla fine abbiamo il<br />

mistero. Potremmo <strong>di</strong>re che<br />

abbiamo il <strong>di</strong>segno <strong>di</strong> Dio. A questo<br />

mistero la matematica si avvicina,<br />

senza penetrarlo.<br />

Ennio De Giorgi<br />

7.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85<br />

7.2 Elementi <strong>di</strong> Algebra Lineare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86<br />

7.3 Metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />

7.3.1 Sostituzione all’in<strong>di</strong>etro e in avanti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />

7.3.2 Eliminazione <strong>di</strong> Gauss: esempio particolare . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />

7.3.3 Eliminazione <strong>di</strong> Gauss: caso generale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93<br />

7.4 Strategie <strong>di</strong> pivoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />

7.5 Fattorizzazione triangolare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

7.5.1 Fattorizzazione LDU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

7.5.2 Fattorizzazione <strong>di</strong> Gauss senza pivoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98<br />

7.5.3 Fattorizzazione <strong>di</strong> Cholesky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />

7.6 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />

7.1 Introduzione<br />

Si consideri la capacità C <strong>di</strong> un conduttore. Dall’elettrostatica, sappiamo che vale q = Cφ dove q rappresenta<br />

la carica del conduttore e φ il suo potenziale elettrostatico, quando il conduttore è isolato. Nel caso in<br />

cui il conduttore non sia isolato, la situazione cambia. Supponiamo <strong>di</strong> avere 4 conduttori in equilibrio elettrostatico<br />

all’interno <strong>di</strong> una cavità collegata a terra (a terra il potenziale elettrostatico vale zero). Supponendo<br />

<strong>di</strong> collegare i conduttori 2, 3 e 4 a terra, si ha φ 2 = φ 3 = φ 4 = 0 e φ 1 ≠ 0. Il conduttore 1 induce carica sugli altri<br />

conduttori, per cui, per ciascun conduttore vale, rispettivamente:<br />

85


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

q 1 = C 11 φ 1<br />

q 2 = C 21 φ 1<br />

q 3 = C 31 φ 1<br />

q 4 = C 41 φ 1<br />

Si ripete lo stesso <strong>di</strong>scorso supponendo φ 2 ≠ 0 e tutti gli altri potenziali nulli. Poi sia φ 3 ≠ 0 e gli altri potenziali<br />

nulli. Infine φ 4 ≠ 0 e tutti gli altri nulli.<br />

La sovrapposizione dei 4 stati considerati corrisponde alla situazione in cui φ 1 ,φ 2 ,φ 3 ,φ 4 sono tutti <strong>di</strong>versi<br />

da zero. Si ha perciò:<br />

q 1 = C 11 φ 1 +C 12 φ 2 +C 13 φ 3 +C 14 φ 4<br />

q 2 = C 21 φ 1 +C 22 φ 2 +C 23 φ 3 +C 24 φ 4<br />

q 3 = C 31 φ 1 +C 32 φ 2 +C 33 φ 3 +C 34 φ 4<br />

q 4 = C 41 φ 1 +C 42 φ 2 +C 43 φ 3 +C 44 φ 4<br />

I coefficienti C i i si chiamano coefficienti <strong>di</strong> capacità, mentre i coefficienti C i j , con j ≠ i si chiamano<br />

coefficienti <strong>di</strong> induzione.<br />

Si può presentare il problema inverso: note le cariche q i , si vuole determinare il valore dei φ i . Si deve<br />

quin<strong>di</strong> risolvere un sistema lineare <strong>di</strong> 4 equazioni in 4 incognite.<br />

In questo Capitolo stu<strong>di</strong>eremo meto<strong>di</strong> <strong>di</strong>retti per la soluzione <strong>di</strong> sistemi lineari del tipo<br />

⎧<br />

a 11 x 1 + a 12 x 2 + ... + a 1n x n = b 1<br />

a ⎪⎨ 21 x 1 + a 22 x 2 + ... + a 2n x n = b 2<br />

a 31 x 1 + a 32 x 2 + ... + a 3n x n = b 3<br />

(7.1)<br />

. = . .<br />

⎪⎩<br />

a n1 x 1 + a n2 x 2 + ... + a nn x n = b n<br />

dove a i j , per i , j = 1,2,...,n e b i , per i = 1,2,...,n sono assegnati e le incognite da determinare sono<br />

x 1 , x 2 ,..., x n . I meto<strong>di</strong> <strong>di</strong>retti sono meto<strong>di</strong> che risolvono il problema in un numero fissato <strong>di</strong> passi,<br />

introducendo un errore dovuto solo all’arrotondamento.<br />

7.2 Elementi <strong>di</strong> Algebra Lineare<br />

Matrice<br />

Sia dato un sistema lineare come in (7.1). Per poterlo semplificare, possiamo eseguire le seguenti<br />

operazioni (trasformazioni elementari) :<br />

G L’i -sima equazione del sistema può essere moltiplicata per una qualunque costante λ ≠ 0 e l’equazione<br />

risultante può essere usata al posto <strong>di</strong> quella <strong>di</strong> partenza: la soluzione del sistema non cambia.<br />

G L’equazione j -sima, moltiplicata per una qualunque costante λ ≠ 0 e sommata all’equazione i -sima,<br />

può essere usata al posto dell’equazione i -sima <strong>di</strong> partenza: la soluzione del sistema non cambia.<br />

G Le equazioni i -sima e j -sima possono essere scambiate: la soluzione del sistema non cambia.<br />

In questa maniera, un sistema lineare può essere trasformato in uno <strong>di</strong> più facile soluzione, come<br />

vedremo nell’algoritmo <strong>di</strong> eliminazione <strong>di</strong> Gauss.<br />

Poichè le operazioni da fare coinvolgono i coefficienti a i j e b i , conviene scrivere il sistema <strong>di</strong> equazioni<br />

lineari utilizzando una forma compatta me<strong>di</strong>ante matrici e vettori.<br />

Definizione 7.2.1 Una matrice n × m è una griglia rettangolare (o array) <strong>di</strong> elementi <strong>di</strong>sposti su n righe e m<br />

colonne.<br />

86


7.2. Elementi <strong>di</strong> Algebra Lineare<br />

Generalmente, una matrice si denota con una lettera maiuscola, per esempio A, mentre i suoi valori si<br />

in<strong>di</strong>cano con la corrispondente lettera minuscola e i pe<strong>di</strong>ci che si riferiscono alla riga e colonna in cui si trova<br />

quel valore, per esempio a i j si riferisce all’elemento <strong>di</strong> riga i e colonna j della matrice A.<br />

⎛<br />

⎞<br />

a 11 a 12 a 13 ... a 1n<br />

A = [ a 21 a 22 a 23 ... a 2n<br />

] a i j = a 31 a 32 a 33 ... a 3n<br />

⎜<br />

⎝<br />

.<br />

.<br />

. ...<br />

⎟<br />

. ⎠<br />

a n1 a n2 a n3 ... a nn<br />

Esempio 7.2.1<br />

( )<br />

2 10 5<br />

A =<br />

3 1 0<br />

è una matrice 2 × 3 con elementi a 11 = 2, a 12 = 10, a 13 = 5, a 21 = 3, a 22 = 1 e a 23 = 0.<br />

Per in<strong>di</strong>care che una matrice A ha n righe e m colonne, <strong>di</strong>remo che A ha <strong>di</strong>mensione n × m. Quando<br />

lavoreremo con matrici quadrate <strong>di</strong> n righe e n colonne, parleremo <strong>di</strong> <strong>di</strong>mensione n della matrice per in<strong>di</strong>care<br />

che il numero <strong>di</strong> righe è uguale al numero <strong>di</strong> colonne e vale n.<br />

I vettori si possono vedere come un caso particolare delle matrici. Si parla <strong>di</strong> vettore riga se ci riferiamo a<br />

una matrice 1 × n e si parla <strong>di</strong> vettore colonna se ci si riferisce a una matrice n × 1.<br />

Per in<strong>di</strong>care un vettore colonna e un vettore riga si usa, rispettivamente, la notazione<br />

⎛ ⎞<br />

x 1<br />

x 2<br />

x =<br />

x 3<br />

⎜<br />

⎝<br />

⎟<br />

. ⎠<br />

x n<br />

x = ( x 1 x 2 x 3 ... x n<br />

)<br />

Vettori<br />

Ve<strong>di</strong>amo, nel seguito, alcune importanti definizioni e proprietà delle matrici.<br />

G Due matrici A e B, <strong>di</strong> <strong>di</strong>mensione n × m, sono uguali se hanno lo stesso numero <strong>di</strong> righe e <strong>di</strong> colonne,<br />

e, inoltre, vale, a i j = b i j per i ,= 1,2,...,n e j = 1,2,...,m.<br />

G Date due matrici A e B, entrambe n × m, si definisce la matrice somma <strong>di</strong> A e B la matrice n × m A + B<br />

i cui elementi sono dati da a i j + b i j , per i ,= 1,2,...,n e j = 1,2,...,m.<br />

G Se A è una matrice n ×m e λ è un numero reale, la moltiplicazione scalare <strong>di</strong> λ per A, denotata con λA,<br />

è una matrice n × m i cui elementi sono λa i j per i ,= 1,2,...,n e j = 1,2,...,m.<br />

G In<strong>di</strong>chiamo con O la matrice i cui elementi sono tutti uguali a zero.<br />

G Data la matrice A, n × m, in<strong>di</strong>chiamo con −A la matrice i cui elementi sono −a i j .<br />

Teorema 7.2.1 Date A, B e C tre matrici n × m, e λ e µ due numeri reali, valgono le seguenti proprietà:<br />

G A + B = B + A G(A + B) +C = A + (B +C )<br />

G A +O = O + A = A G A + (−A) = −A + A = O<br />

Gλ(A + B) = λA + λB G(λ + µ)A = λA + µA<br />

Gλ(µA) = (λµ)A G1A = A<br />

87


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Matrice<br />

prodotto<br />

G Date due matrici A <strong>di</strong> <strong>di</strong>mensione n×m e B <strong>di</strong> <strong>di</strong>mensione m×p, la matrice prodotto <strong>di</strong> A e B, denotata<br />

con C = AB, è una matrice i cui elementi c i j sono dati da:<br />

c i j =<br />

m∑<br />

a i k b k j = a i 1 b 1j + a i 2 b 2j + ... + a i m b m j<br />

k=1<br />

per i = 1,2,...,n e j = 1,2,..., p.<br />

Prodotto<br />

matricevettore<br />

G Data una matrice A <strong>di</strong> <strong>di</strong>mensione n e un vettore colonna x <strong>di</strong> lunghezza n, si definisce il vettore y = Ax<br />

prodotto della matrice A per il vettore x, il vettore le cui componenti sono date da<br />

n∑<br />

y i = a i j x j per i = 2,...,n<br />

j =1<br />

Dati due vettori x e y si definisce prodotto scalare x T y = ∑ n<br />

Prodotto<br />

i=1 x i y i .<br />

scalare tra<br />

G In generale, AB ≠ B A.<br />

vettori<br />

Matrice<br />

<strong>di</strong>agonale<br />

G Una matrice D si <strong>di</strong>ce <strong>di</strong>agonale se è quadrata con d i j = 0 per i ≠ j . Gli elementi <strong>di</strong>versi da zero si<br />

trovano quin<strong>di</strong> sulla <strong>di</strong>agonale (detta <strong>di</strong>agonale principale) che si può tracciare partendo dall’elemento<br />

in alto a sinistra (<strong>di</strong> posto 11) e arrivando all’elemento in basso a destra (<strong>di</strong> posto nn).<br />

Esempio:<br />

⎛<br />

⎞<br />

1 0 0 0<br />

D = ⎜0 2 0 0<br />

⎟<br />

⎝0 0 5 0 ⎠<br />

0 0 0 −1<br />

Matrice<br />

Identità<br />

Matrice<br />

tri<strong>di</strong>agonale<br />

Matrice<br />

triangolare<br />

superiore<br />

Matrice<br />

triangolare<br />

inferiore<br />

G Si chiama matrice identità e si in<strong>di</strong>ca con I , una matrice <strong>di</strong>agonale i cui elementi <strong>di</strong>agonali valgono 1.<br />

Esempio:<br />

⎛<br />

⎞<br />

1 0 0 0<br />

I = ⎜0 1 0 0<br />

⎟<br />

⎝0 0 1 0⎠<br />

0 0 0 1<br />

G Una matrice si <strong>di</strong>ce tri<strong>di</strong>agonale se gli elementi non nulli si trovano sulla <strong>di</strong>agonale principale e sugli<br />

elementi delle <strong>di</strong>agonali che si trovano sopra e sotto la <strong>di</strong>agonale principale.<br />

Esempio:<br />

⎛<br />

⎞<br />

−2 1 0 0 0<br />

1 −2 1 0 0<br />

A =<br />

⎜ 0 1 −2 1 0<br />

⎟<br />

⎝ 0 0 1 −2 1 ⎠<br />

0 0 0 1 −2<br />

G Una matrice si <strong>di</strong>ce triangolare se ha tutti gli elementi nulli ad eccezione <strong>di</strong> quelli che si trovano tutti<br />

sopra (o tutti sotto) la <strong>di</strong>agonale principale.<br />

– Si definisce matrice triangolare superiore U (U sta per upper) <strong>di</strong> <strong>di</strong>mensione n, la matrice per la<br />

quale, per j = 1,2,...,n, si ha<br />

u i j = 0 per i = j + 1, j + 2,...,n<br />

– Si definisce matrice triangolare inferiore L (L sta per lower) <strong>di</strong> <strong>di</strong>mensione n, la matrice per la<br />

quale, per i = 1,2,...,n, si ha<br />

l i j = 0 per j = i + 1,i + 2,...,n<br />

88


7.2. Elementi <strong>di</strong> Algebra Lineare<br />

Esempi<br />

⎛<br />

1 −2<br />

⎞<br />

5.3<br />

⎛<br />

1 0<br />

⎞<br />

0<br />

U = ⎝0 3.2 −4⎠ L = ⎝ 2 −21 0 ⎠<br />

0 0 10<br />

−3.4 5.7 −4<br />

Teorema 7.2.2 Date A matrice n × m, B matrice m × s, C matrice s × p, D matrice m × s, I m e I s le matrici<br />

identità, rispettivamente <strong>di</strong> <strong>di</strong>mensione m e s, e λ e µ due numeri reali, valgono le seguenti proprietà:<br />

G A(BC ) = (AB)C G A(B + D) = AB + AD<br />

GI m B = B B I s = B Gλ(AB) = (λA)B = A(λB).<br />

A questo punto, il sistema lineare (7.1) può essere scritto in forma matriciale come<br />

Ax = b<br />

Collegata alla soluzione <strong>di</strong> un sistema lineare è l’inversa <strong>di</strong> una matrice.<br />

Definizione 7.2.2 Data una matrice A <strong>di</strong> <strong>di</strong>mensione n, A si <strong>di</strong>ce nonsingolare (o invertibile o regolare) se<br />

esiste una matrice, che in<strong>di</strong>chiamo come A −1 <strong>di</strong> <strong>di</strong>mensione n tale che<br />

Matrice<br />

inversa<br />

A A −1 = A −1 A = I<br />

La matrice A −1 si chiama matrice inversa della A. Una matrice che non ha inversa si <strong>di</strong>ce, invece, singolare (o<br />

non invertibile).<br />

Teorema 7.2.3 Per ogni matrice A <strong>di</strong> <strong>di</strong>mensione n nonsingolare si ha:<br />

G A −1 è unica<br />

G A −1 è nonsigolare e (A −1 ) −1 = A<br />

G Se B è non singolare, <strong>di</strong> <strong>di</strong>mensione n, allora (AB) −1 = B −1 A −1<br />

Dato il sistema Ax = b, se A è nonsingolare, si ha x = A −1 b.<br />

Un’altra importante matrice associata ad un’assegnata matrice A è la sua trasposta.<br />

Definizione 7.2.3 La trasposta <strong>di</strong> una matrice A <strong>di</strong> <strong>di</strong>mensione n × m è la matrice in<strong>di</strong>cata con A T , <strong>di</strong> <strong>di</strong>mensione<br />

m × n, per la quale la colonna i della trasposta coincide con la riga i della matrice A <strong>di</strong> partenza:<br />

a T i j = a j i .<br />

Trasposta <strong>di</strong><br />

una matrice<br />

Esempio:<br />

A =<br />

( 1 2<br />

) 3<br />

2 5 6<br />

⎛<br />

1<br />

⎞<br />

2<br />

A T = ⎝2 5⎠<br />

3 6<br />

Legata alla trasposta <strong>di</strong> una matrice è la seguente definizione.<br />

Definizione 7.2.4 Una matrice quadrata si <strong>di</strong>ce simmetrica se A = A T .<br />

Esempio:<br />

⎛<br />

1 4<br />

⎞<br />

8<br />

⎛<br />

1 4<br />

⎞<br />

8<br />

A = ⎝4 2 6⎠ A T = ⎝4 2 6⎠<br />

8 6 5<br />

8 6 5<br />

Teorema 7.2.4 Valgono le seguenti proprietà (per matrici per cui è possibile eseguire le seguenti operazioni):<br />

89


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Determinante<br />

<strong>di</strong> una<br />

matrice<br />

G(A T ) T = A<br />

G(AB) T = B T A T<br />

G(A + B) T = A T + B T<br />

GSe esiste A −1 allora (A −1 ) T = (A T ) −1<br />

Il determinante <strong>di</strong> una matrice permette <strong>di</strong> stabilire esistenza e unicità della soluzione nei sistemi lineari.<br />

Data una matrice quadrata A, il suo determinante si in<strong>di</strong>ca me<strong>di</strong>ante la notazione det(A) o |A|.<br />

G Se A = [a] è una matrice 1 × 1, allora det(A) = a.<br />

G Se A è una matrice <strong>di</strong> <strong>di</strong>mensione n, si definisce minore M i j il determinante della sottomatrice <strong>di</strong><br />

<strong>di</strong>mensione n − 1 ottenuta cancellando la i -sima riga e la j -sima colonna da A.<br />

G Il determinante <strong>di</strong> A è dato dalla formula<br />

det(A) =<br />

det(A) =<br />

n∑<br />

(−1) i+j a i j M i j<br />

j =1<br />

n∑<br />

(−1) i+j a i j M i j<br />

i=1<br />

(fissato un qualunque i = 1,2,...,n)<br />

(fissato un qualunque j = 1,2,...,n)<br />

Il calcolo del determinante <strong>di</strong> una matrice <strong>di</strong> <strong>di</strong>mensione n richiede O (n!) moltiplicazioni. Quin<strong>di</strong>, anche per<br />

valori piccoli <strong>di</strong> n, le operazioni da fare <strong>di</strong>ventanto proibitive.<br />

Teorema 7.2.5 Sia assegnata A una matrice quadrata <strong>di</strong> <strong>di</strong>mensione n.<br />

Se una riga o una colonna <strong>di</strong> A ha elementi tutti nulli, allora det(A) = 0.<br />

Se A ha due righe o due colonne con gli stessi elementi, allora det(A) = 0.<br />

G Denotata con à la matrice ottenuta scambiando due righe <strong>di</strong> A, si ha det(Ã) = −det(A).<br />

G Denotata con à la matrice ottenuta da A moltiplicando una sua riga per un numero reale λ, si ha<br />

det(Ã) = λdet(A).<br />

G Denotata con à la matrice ottenuta da A sommando una sua riga per un’altra che è stata moltiplicata<br />

per λ, si ha det(Ã) = det(A).<br />

G Se B è un’altra matrice <strong>di</strong> <strong>di</strong>mensione n, si ha det(AB) = det(A)det(B)<br />

G det(A T ) = det(A)<br />

G Se esiste A −1 , si ha det(A −1 1<br />

) =<br />

det(A)<br />

G Se A è una matrice trangolare superiore o trangolare inferiore o <strong>di</strong>agonale, allora det(A) = ∏ n<br />

i=1 a i i<br />

7.3 Metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss<br />

Ritorniamo al sistema <strong>di</strong> equazioni (7.1), che possiamo scrivere in forma matriciale come Ax = b.<br />

Nel metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss 1 il sistema lineare <strong>di</strong> partenza viene trasformato in uno equivalente<br />

<strong>di</strong> più facile soluzione in quanto la matrice del nuovo sistema ha forma triangolare (superiore o inferiore) e<br />

può essere risolto facilmente me<strong>di</strong>ante sostituzione (all’in<strong>di</strong>etro o in avanti).<br />

Ve<strong>di</strong>amo nel dettaglio come si risolve un sistema lineare con queste tecniche.<br />

7.3.1 Sostituzione all’in<strong>di</strong>etro e in avanti<br />

La matrice A sia nonsingolare e triangolare superiore, cioè<br />

⎛<br />

⎞<br />

a 11 a 12 ... a 1n<br />

. a .. 22 a2n<br />

A =<br />

⎜<br />

.<br />

⎝<br />

..<br />

. .. ⎟<br />

⎠<br />

a nn<br />

1 Carl Friedrich Gauss fu un matematico e fisico tedesco (1777-1855) che ha dato il suo contribuito in maniera significativa in<br />

numerosi campi: teoria dei numeri, analisi, geometria <strong>di</strong>fferenziale, geodesia, magnetismo, astronomia, ottica. Al pari <strong>di</strong> Eulero, Newton<br />

e Archimede è considerato uno dei più gran<strong>di</strong> matematici della storia.<br />

In suo onore è stato dato il suo nome a una nave <strong>di</strong> ricerca tedesca, a una montagna (Gaussberg) in Antartide, a un cratere sulla luna,<br />

e all’unità <strong>di</strong> misura della densità <strong>di</strong> flusso magnetico o <strong>di</strong> induzione magnetica.<br />

90


7.3. Metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss<br />

La soluzione del sistema Ax = b può dunque procedere dal basso verso l’alto, a partire dall’ultima riga. Le<br />

equazioni, infatti, sono<br />

a 11 x 1 + a 12 x 2 + a 13 x 3 + ... a 1n x n = b 1<br />

a 22 x 2 + a 23 x 3 + ... a 2n x n = b 2<br />

a 33 x 3 + ... a 3n x n = b 2<br />

. = . . .<br />

a nn x n = b n<br />

L’ultima riga si legge come a nn x n = b n . Quin<strong>di</strong> possiamo ricavare x n = b n /a nn .<br />

Noto il valore <strong>di</strong> x n , possiamo ricavare x n−1 dalla riga n − 1 del sistema:<br />

1<br />

a n−1n−1 x n−1 + a n−1n x n = b n−1 . Si ha x n−1 = (b n−1 − a n−1n x n ).<br />

a n−1n−1<br />

Si procede a ritroso in questo modo arrivando fino alla prima equazione che ci permette <strong>di</strong> calcolare il valore<br />

<strong>di</strong> x 1 . Osserviamo che tutte le <strong>di</strong>visioni per i coefficienti a i i sono possibili in quanto stiamo supponendo<br />

A non singolare e, poichè det(A) = ∏ n<br />

i=1 a i i ≠ 0, necessariamente ciascun a i i ≠ 0.<br />

Possiamo dunque scrivere l’algoritmo <strong>di</strong> sostituzione all’in<strong>di</strong>etro:<br />

Per i = n fino a i = 1, procedendo all’in<strong>di</strong>etro con passo −1<br />

x i =<br />

b i − ∑ n<br />

j =i+1 a i j x j<br />

a i i<br />

Un analogo algoritmo si ricava quando la matrice è triangolare inferiore. In tal caso, si parte dalla prima<br />

equazione per ricavare x 1 e poi si va avanti nell’equazione successiva.<br />

Si ha l’algoritmo <strong>di</strong> sostituzione in avanti:<br />

Per i = 1 fino a i = n, procedendo in avanti con passo 1<br />

x i =<br />

b i − ∑ i−1<br />

j =1 a i j x j<br />

a i i<br />

7.3.2 Eliminazione <strong>di</strong> Gauss: esempio particolare<br />

Il metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss trasforma il sistema <strong>di</strong> partenza in uno ad esso equivalente ma più<br />

facile da risolvere, perchè la matrice del sistema è <strong>di</strong> forma triangolare superiore, in modo da poter applicare<br />

il metodo <strong>di</strong> sostituzione all’in<strong>di</strong>etro.<br />

Per capire come si applica questo metodo consideriamo un semplice esempio <strong>di</strong> sistema <strong>di</strong> 3 equazioni<br />

in 3 incognite, Ax = b dove<br />

⎛ ⎞ ⎛ ⎞<br />

2 1 2<br />

10<br />

A = ⎝<br />

4 1 2<br />

1 2 5<br />

⎠ b = ⎝<br />

12<br />

20<br />

Le equazioni del sistema sono, dunque,<br />

2x 1 + x 2 + 2x 3 = 10<br />

4x 1 + x 2 + 2x 3 = 12<br />

x 1 + 2x 2 + 5x 3 = 20<br />

⎠<br />

91


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

G Al primo passo del metodo, cerchiamo <strong>di</strong> annullare tutti i coefficienti dell’incognita x 1 nella seconda e<br />

terza equazione.<br />

– Divi<strong>di</strong>amo il coefficiente 4 che moltiplica x 1 nella seconda equazione con il coefficiente 2 che<br />

moltiplica x 1 nella prima equazione. Otteniamo il valore 4 = 2. Adesso moltiplichiamo per questo<br />

2<br />

valore (2) la prima equazione, ricavando<br />

2(2x 1 + x 2 + 2x 3 = 10) =⇒ 4x 1 + 2x 2 + 4x 3 = 20<br />

Se ora facciamo la sottrazione tra la seconda equazione del sistema e questa che abbiamo ricavato<br />

otteniamo<br />

4x 1 + x 2 + 2x 3 = 12<br />

−<br />

4x 1 + 2x 2 + 4x 3 = 20 =<br />

−x 2 − 2x 3 = −8<br />

Sostituiamo questa equazione alla seconda del sistema (il sistema rimane equivalente), ricavando<br />

2x 1 + x 2 + 2x 3 = 10<br />

−x 2 − 2x 3 = −8<br />

x 1 + 2x 2 + 5x 3 = 20<br />

Abbiamo eliminato, in questo modo, il coefficiente <strong>di</strong> x 1 nella seconda equazione.<br />

– Alla stessa maniera, <strong>di</strong>vi<strong>di</strong>amo il coefficiente <strong>di</strong> x 1 nella terza equazione (che vale 1) con il coefficiente<br />

<strong>di</strong> x 1 nella prima equazione: abbiamo 1 2 . Moltiplichiamo la prima equazione per 1 2 e poi<br />

facciamo la sottrazione tra la terza equazione e la prima moltiplicata per 1 2 :<br />

x 1 + 2x 2 + 5x 3 = 20<br />

1<br />

2 (2x 1 + x 2 + 2x 3 = 10) ⇐⇒x 1 + 1 2 x 2 + x 3 = 5 =<br />

3<br />

2 x 2 + 4x 3 = 15<br />

Sostituiamo questa equazione alla terza del sistema.<br />

– A questo punto il sistema è<br />

2x 1 + x 2 + 2x 3 = 10<br />

−x 2 − 2x 3 = −8<br />

3<br />

2 x 2 + 4x 3 = 15<br />

−<br />

Nella seconda e terza equazione non c’è più l’incognita x 1 .<br />

G Per poter arrivare ad un sistema <strong>di</strong> equazioni triangolare inferiore, dobbiamo eliminare il coefficiente <strong>di</strong><br />

x 2 nella terza equazione del sistema. Ripetiamo il ragionamento appena fatto, lavorando sulla seconda<br />

e terza equazione.<br />

– Consideriamo il coefficiente <strong>di</strong> x 2 della terza equazione ( 3 ) e lo <strong>di</strong>vi<strong>di</strong>amo per il coefficiente<br />

2<br />

<strong>di</strong> x 2 della seconda equazione ( che vale −1). Moltiplichiamo la seconda equazione per questo<br />

92


7.3. Metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss<br />

coefficiente (cioè per − 3 2 ) e poi sottraiamo la terza equazione dalla seconda moltiplicata per − 3 2 :<br />

3<br />

2 x 2 + 4x 3 = 15 −<br />

− 3 2 (−x 2 − 2x 3 = −8) ⇐⇒ 3 2 x 2 + 3x 3 = 12 =<br />

x 3 = 3<br />

– Sostituiamo questa equazione alla terza del sistema, ricavando il sistema equivalente<br />

2x 1 + x 2 + 2x 3 = 10<br />

−x 2 − 2x 3 = −8<br />

x 3 = 3<br />

Con tutte le trasformazioni effettuate, abbiamo trasformato il sistema <strong>di</strong> partenza in uno equivalente, che<br />

si può risolvere facilmente me<strong>di</strong>ante sostituzioni all’in<strong>di</strong>etro. Dall’ultima equazione abbiamo x 3 = 3. Sostituendo<br />

questo valore nella seconda equazione otteniamo −x 2 − 6 = −8 da cui x 2 = 2. Infine, sostituendo i<br />

valori <strong>di</strong> x 3 e x 2 nella prima equazione abbiamo 2x 1 + 2 + 6 = 10 da cui x 1 = 1.<br />

7.3.3 Eliminazione <strong>di</strong> Gauss: caso generale<br />

Sia dato un sistema <strong>di</strong> n equazioni, in cui la matrice A è piena (o densa, cioè abbia quasi tutti gli elementi<br />

non nulli). Applichiamo trasformazioni elementari per riga in modo da ridurre il sistema <strong>di</strong> partenza in uno<br />

equivalente <strong>di</strong> forma triangolare superiore, che potremo risolvere me<strong>di</strong>ante sostituzione all’in<strong>di</strong>etro.<br />

La soluzione del problema Ax = b, infatti, non cambia se moltiplichiamo una riga per una costante, se<br />

sottraiamo il multiplo <strong>di</strong> una riga da un’altra riga o se facciamo scambi <strong>di</strong> righe, come abbiamo detto all’inizio<br />

della Sezione 7.2.<br />

Supponiamo, per il momento, che tutti gli elementi della <strong>di</strong>agonale principale <strong>di</strong> A siano non nulli.<br />

G Al primo passo vogliamo eliminare gli elementi della prima colonna al <strong>di</strong> sotto della <strong>di</strong>agonale<br />

principale:<br />

– sottraiamo la prima equazione moltiplicata per a 21<br />

a 11<br />

dalla seconda equazione:<br />

a 21 x 1 + a 22 x 2 + a 23 x 3 + ... + a 2n x n = b 2 −<br />

a 21<br />

(a 11 x 1 + a 12 x 2 + a 13 x 3 + ... + a 1n x n ) = a 21<br />

b 1 =<br />

a 11 a 11<br />

(a 22 − a 21<br />

a 11<br />

a 12 )x 2 + (a 23 − a 21<br />

a 11<br />

a 13 )x 3 + ... + (a 2n − a 21<br />

a 11<br />

a 1n )x n = b 2 − a 21<br />

a 11<br />

b 1<br />

– sottraiamo la prima equazione moltiplicata per a 31<br />

a 11<br />

dalla terza equazione.<br />

– ...<br />

– sottraiamo la prima equazione moltiplicata per a n1<br />

a 11<br />

dalla n-sima equazione.<br />

Come risultato <strong>di</strong> questa operazione avremo una nuova matrice con gli elementi della prima<br />

colonna, eccetto quello <strong>di</strong> posto 11, tutti uguali a zero.<br />

⎛<br />

⎞⎛<br />

⎞ ⎛ ⎞<br />

a 11 a 12 ... a 1n x 1 b 1<br />

0 a (1)<br />

22<br />

... a (1)<br />

2n<br />

x 2<br />

⎜<br />

⎝<br />

.<br />

. ...<br />

⎟⎜<br />

. ⎠⎝<br />

⎟<br />

. ⎠ = b (1)<br />

2 ⎜ ...<br />

⎟<br />

⎝ ⎠<br />

0 a (1)<br />

n2<br />

... a nn<br />

(1) x n b n<br />

(1)<br />

93


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

G Al secondo passo, consideriamo il sistema ridotto che si ha ignorando la prima equazione del sistema<br />

e la prima colonna della nuova matrice che abbiamo ottenuta (che ha tutti 0 al <strong>di</strong> sotto dell’elemento<br />

<strong>di</strong>agonale).<br />

A questa sottomatrice applichiamo lo stesso proce<strong>di</strong>mento <strong>di</strong> prima, sottraendo, quin<strong>di</strong>, la prima<br />

equazione della sottomatrice moltiplicata per a(1) 32<br />

a (1)<br />

22<br />

via.<br />

Dopo questo passo, il sistema sarà equivalente a:<br />

⎛<br />

⎞<br />

a 11 a 12 ... ... a ⎛ ⎞ ⎛ ⎞<br />

1n<br />

0 a (1)<br />

22<br />

a (1)<br />

23<br />

... a (1) x 1<br />

b 1<br />

2n<br />

x 2<br />

b (1)<br />

2<br />

. 0 a (2)<br />

33<br />

... a (2)<br />

3n<br />

x 3<br />

⎜<br />

⎝<br />

.<br />

.<br />

. ...<br />

⎟⎜<br />

=<br />

b (2)<br />

3 . ⎠⎝<br />

⎟ ⎜ ... ⎟<br />

. ⎠ ⎝ ⎠<br />

0 0 a (2)<br />

n3<br />

... a nn<br />

(2) x n b n<br />

(1)<br />

dalla seconda equazione della sottomatrice, e così<br />

G Dopo aver applicato questo proce<strong>di</strong>mento n − 1 volte, avremo un sistema triangolare superiore<br />

semplice da risolvere utilizzando l’algoritmo <strong>di</strong> sostituzione all’in<strong>di</strong>etro.<br />

⎛<br />

⎞<br />

a 11 a 12 ... ... a ⎛ ⎞ ⎛<br />

1n<br />

0 a (1)<br />

22<br />

a (1)<br />

23<br />

... a (1) x 1<br />

2n<br />

x 2<br />

. 0 a (2)<br />

33<br />

... a (2)<br />

3n<br />

x 3<br />

⎜<br />

⎝<br />

.<br />

. ... ...<br />

⎟⎜<br />

=<br />

. ⎠⎝<br />

⎟ ⎜<br />

. ⎠ ⎝<br />

0 0 ... 0 a nn<br />

(n−1) x n<br />

7.4 Strategie <strong>di</strong> pivoting<br />

b 1<br />

b (1)<br />

2<br />

b (2)<br />

3<br />

...<br />

b (n−1)<br />

n<br />

Gli elementi <strong>di</strong>agonali generati ad ogni passo del metodo <strong>di</strong> eliminazione a (k) sono detti elementi<br />

i i<br />

pivotali.<br />

Nel descrivere il metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss abbiamo supposto, per semplicità, che tutti gli elementi<br />

<strong>di</strong>agonali fossero <strong>di</strong>versi da zero. Ma una matrice può essere non singolare senza che gli elementi della<br />

<strong>di</strong>agonale principale siano tutti <strong>di</strong>versi da zero.<br />

Inoltre, andando avanti nel proce<strong>di</strong>mento <strong>di</strong> eliminazione, può succedere che un elemento pivotale <strong>di</strong>venti<br />

nullo – e quin<strong>di</strong> la corrispondente incognita non può essere eliminata attraverso quella equazione nel<br />

proce<strong>di</strong>mento <strong>di</strong> sostituzione all’in<strong>di</strong>etro.<br />

C’è, infine, da considerare il fatto che si possono avere grossi errori numerici quando un elemento<br />

pivotale è molto piccolo.<br />

Cosa fare in queste circostanze? In che modo applicare l’eliminazione <strong>di</strong> Gauss?<br />

Si hanno le cosiddette strategie <strong>di</strong> pivoting:<br />

G pivoting parziale<br />

Mano mano che si va avanti nell’eliminazione, per i = 1,2,...,n −1 a ciascuno sta<strong>di</strong>o si sceglie il più<br />

piccolo intero q tale che<br />

|a (i−1) | = max<br />

qi<br />

i≤j ≤n |a(i−1) |<br />

j i<br />

e si scambiano le righe i e q.<br />

Si opera, dunque, un controllo sulla colonna i -sima dalla posizione i fino alla posizione n, andando<br />

a cercare il coefficiente massimo in modulo.<br />

G pivoting totale<br />

Nel pivoting totale, invece, la ricerca dell’elemento più grande avviene in tutta la sottomatrice che<br />

si ha considerando le colonne e le righe rispettivamente a destra e sotto l’elemento <strong>di</strong>agonale i -simo.<br />

⎞<br />

⎟<br />

⎠<br />

94


7.4. Strategie <strong>di</strong> pivoting<br />

Si vanno quin<strong>di</strong> a cercare i più piccoli interi q e r tali che<br />

|a qr<br />

(i−1) | = max<br />

i≤k,j ≤n |a(i−1) j k<br />

|<br />

Si opera, quin<strong>di</strong>, uno scambio non solo <strong>di</strong> righe ma anche <strong>di</strong> colonne in modo da portare l’elemento<br />

pivotale dalla riga e colonna qr al posto i i . Di questo scambio <strong>di</strong> colonne bisogna conservare<br />

traccia perchè vengono scambiate anche le componenti del vettore soluzione, in modo da effettuare lo<br />

scambio inverso una volta risolto il sistema.<br />

Il maggiore sforzo computazionale garantisce maggiore accuratezza e stabilità nei risultati, nel senso che<br />

gli errori <strong>di</strong> arrotondamento non sono così amplificati come potrebbe succedere senza l’adozione <strong>di</strong> una<br />

tecnica <strong>di</strong> pivoting.<br />

Esempio 7.4.1 Consideriamo il sistema<br />

x 1 + x 2 +x 3 = 1<br />

x 1 + 1.0001x 2 + 2x 3 = 2<br />

x 1 + 2x 2 + 2x 3 = 1<br />

L’esatta soluzione, corretta a 4 cifre decimali, è x = (1, −1.0001, 1.0001) T .<br />

L’eliminazione <strong>di</strong> Gauss senza pivoting porta al sistema<br />

x 1 + x 2 +x 3 = 1<br />

0.0001x 2 + 1x 3 = 1<br />

1x 2 + 1x 3 = 0<br />

e, infine, a<br />

x 1 + x 2 +x 3 = 1<br />

0.0001x 2 + 1x 3 = 1<br />

−9999x 3 = −10000<br />

Se usiamo un’aritmetica in base 10 con 3 cifre decimali, allora la sostituzione all’in<strong>di</strong>etro ci darà<br />

x 3 = −10000<br />

−9999 = 1.000, quad x 2 = 1 − 1<br />

0.0001 = 0, x 1 = 0.<br />

La soluzione è completamente sbagliata.<br />

Se, invece, facciamo lo scambio della seconda e terza riga adottando il pivoting parziale, allora avremo il<br />

sistema:<br />

x 1 + x 2 +x 3 = 1<br />

1x 2 + 1x 3 = 0<br />

0.0001x 2 + 1x 3 = 1<br />

e, infine,<br />

x 1 + x 2 +x 3 = 1<br />

1x 2 + 1x 3 = 0<br />

0.9999x 3 = 1<br />

Questa volta si ha (sempre lavorando con 3 cifre decimali) x 3 = 1.000, x 2 = −1.000, x 1 = 1.000, che è la<br />

soluzione corretta a 3 cifre decimali.<br />

95


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

7.5 Fattorizzazione triangolare<br />

Il metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss, visto in forma matriciale, decompone la matrice A nel<br />

prodotto LU <strong>di</strong> due matrici L, trangolare inferiore, e U , triangolare superiore.<br />

Basta considerare,<br />

⎛<br />

ad ogni passo, la matrice<br />

⎞<br />

1<br />

0 1<br />

⎜<br />

.<br />

⎟<br />

. 0 1<br />

.<br />

. 0 1<br />

M (k) .<br />

.<br />

. − a(k−1) k+1k<br />

=<br />

a (k−1)<br />

kk<br />

.<br />

.<br />

. − a(k−1) k+2k<br />

a (k−1)<br />

kk<br />

.<br />

.<br />

.<br />

.<br />

⎜<br />

⎝<br />

.<br />

.<br />

. − a(k−1) n k<br />

a (k−1)<br />

kk<br />

1<br />

Si considera quin<strong>di</strong> la matrice A (k) = M (k) A (k−1) = M (k) M (k−1) ... M (1) A e il vettore b (k) =<br />

M (k) b (k−1) = M (k) M (k−1) ··· M (1) b.<br />

Dopo n − 1 passi, avremo<br />

U = A (n−1) = M (n−1) ... M (2) M (1) A<br />

con U matrice triangolare superiore. Otteniamo quin<strong>di</strong> A = LU , con<br />

L = (M (n−1) ··· M (2) M (1) ) −1 = [M (1) ] −1 ···[M (n−2) ] −1 [M (n−1) ] −1<br />

L è triangolare inferiore con elementi dati dal prodotto delle matrici M (k) generate durante l’eliminazione<br />

<strong>di</strong> Gauss.<br />

. ..<br />

. ..<br />

⎟<br />

1<br />

⎠<br />

7.5.1 Fattorizzazione LDU<br />

L’eliminazione <strong>di</strong> Gauss è un caso particolare <strong>di</strong> fattorizzazione LDU , nella quale la matrice A viene decomposta<br />

nel prodotto <strong>di</strong> 3 matrici, la L che è triangolare inferiore con elementi sulla <strong>di</strong>agonale principale<br />

(elementi <strong>di</strong>agonali) uguali a 1, la D che è una matrice <strong>di</strong>agonale e la U che è una triangolare superiore con<br />

elementi <strong>di</strong>agonali uguali a 1.<br />

Nell’eliminazione <strong>di</strong> Gauss vista prima, nella U abbiamo inglobato anche la matrice D, per cui abbiamo<br />

una fattorizzazione LU .<br />

La decomposizione LDU è assicurata dal teorema LDU . Prima <strong>di</strong> vedere il teorema, definiamo i minori<br />

principali <strong>di</strong> una matrice A.<br />

Minore Definizione 7.5.1 Data una matrice A si definisce minore principale <strong>di</strong> <strong>di</strong>mensione k (con 1 ≤ k ≤ n), la<br />

principale sottomatrice che si ha prendendo le prime k righe e k colonne <strong>di</strong> A.<br />

⎡<br />

⎤<br />

a 11 ... a 1k<br />

⎢<br />

⎣<br />

.<br />

⎥<br />

. ⎦<br />

a k1 ... a kk<br />

Teorema 7.5.1 (LDU ) Nell’ipotesi che tutti i minori principali <strong>di</strong> A, (per i = 1,2,...,n) siano non-singolari,<br />

allora la matrice A è decomponibile in maniera univoca nel prodotto A = LDU<br />

96


7.5. Fattorizzazione triangolare<br />

Qualsiasi matrice non singolare può essere condotta sotto una forma tale da sod<strong>di</strong>sfare il teorema LDU<br />

me<strong>di</strong>ante opportuni scambi <strong>di</strong> righe e <strong>di</strong> colonne (abbiamo visto cosa fare quando un elemento pivotale è<br />

nullo). Fare uno scambio <strong>di</strong> righe o <strong>di</strong> colonne significa moltiplicare la matrice A con un’opportuna matrice<br />

<strong>di</strong> permutazione.<br />

Una matrice <strong>di</strong> permutazione P è una matrice ottenuta dalla matrice identità operando scambi <strong>di</strong> righe o<br />

<strong>di</strong> colonne in modo che la matrice risultante abbia esattamente un unico valore <strong>di</strong>verso da zero su ogni riga<br />

e colonna, e tale valore sia uguale a 1.<br />

Matrice <strong>di</strong><br />

permutazione<br />

Esempio 7.5.1 Si consideri la matrice <strong>di</strong> permutazione P <strong>di</strong> <strong>di</strong>mensione 3 data da<br />

⎛ ⎞<br />

1 0 0<br />

P = ⎝0 0 1⎠<br />

0 1 0<br />

Qualunque sia la matrice A, <strong>di</strong> <strong>di</strong>mensione 3, moltiplicandola a sinistra per P si ottiene lo scambio della<br />

seconda e terza riga <strong>di</strong> A; invece, moltiplicandola a destra per P si ottiene lo scambio della seconda e terza<br />

colonna <strong>di</strong> A:<br />

⎛ ⎞⎛<br />

⎞ ⎛<br />

⎞<br />

1 0 0 a 11 a 12 a 13 a 11 a 12 a 13<br />

PA = ⎝0 0 1⎠⎝a 21 a 22 a 23<br />

⎠ = ⎝a 31 a 32 a 33<br />

⎠<br />

0 1 0 a 31 a 32 a 33 a 21 a 22 a 23<br />

⎛<br />

⎞⎛<br />

⎞ ⎛<br />

⎞<br />

a 11 a 12 a 13 1 0 0 a 11 a 13 a 12<br />

AP = ⎝a 21 a 22 a 23<br />

⎠⎝0 0 1⎠ = ⎝a 21 a 23 a 22<br />

⎠<br />

a 31 a 32 a 33 0 1 0 a 31 a 33 a 32<br />

Quin<strong>di</strong>, il teorema LDU si può applicare alla matrice A o ad un’opportuna matrice PA, se si effettua il pivoting<br />

parziale, o a PAQ se si effettua il pivoting totale (e quin<strong>di</strong> si considerano due matrici <strong>di</strong> permutazioni P e Q).<br />

In genere, la matrice D viene inglobata nella L o nella U (post-moltiplicando o pre-moltiplicando le L e le<br />

U definite prima per la D).<br />

G Nel caso in cui la matrice D viene inglobata nella matrice L, la L ha elementi <strong>di</strong>agonali l i i ≠ 0, mentre<br />

la U ha elementi <strong>di</strong>agonali unitari. Si parla <strong>di</strong> fattorizzazione <strong>di</strong> Crout.<br />

G Nel caso in cui la matrice D viene inglobata nella matrice U , la U ha elementi <strong>di</strong>agonali u i i ≠ 0, mentre<br />

la L ha elementi <strong>di</strong>agonali unitari. Si parla <strong>di</strong> fattorizzazione <strong>di</strong> Doolittle.<br />

Scriviamo in forma estesa il prodotto tra matrici, nell’ipotesi <strong>di</strong> operare la fattorizzazione <strong>di</strong> Crout:<br />

⎛<br />

⎞ ⎛<br />

⎞⎛<br />

⎞<br />

a 11 a 12 ... a 1n l 11 0 ... 0 1 u 12 ... u 1n<br />

a 21 a 22 ... a 2n<br />

⎜<br />

⎝<br />

.<br />

.<br />

⎟<br />

. ⎠ = l 21 l 22 ... 0<br />

0 1 ... u 2n<br />

⎜<br />

⎝<br />

.<br />

.<br />

⎟⎜<br />

. ⎠⎝<br />

.<br />

.<br />

⎟<br />

. ⎠<br />

a n1 a n2 ... a nn l n1 l n2 ... l nn 0 0 ... 1<br />

Moltiplichiamo la prima riga <strong>di</strong> L per le colonne <strong>di</strong> U ed eguagliamo i termini con gli elementi della prima<br />

riga <strong>di</strong> A. Otteniamo:<br />

l 11 · 1 = a 11<br />

l 11 · u 1k = a 1k , k = 2,...,n<br />

Quin<strong>di</strong>: l 11 = a 11 e u 1k = a 1k /l 11 . Abbiamo ricavato gli elementi della prima riga <strong>di</strong> L e U .<br />

Moltiplicando le successive righe <strong>di</strong> L per le colonne <strong>di</strong> U ed uguagliando i termini ai corrispondenti<br />

termini <strong>di</strong> A, abbiamo:<br />

l i j = a i j −<br />

j −1 ∑<br />

m=1<br />

u i j = 1 (a i j −<br />

l i i<br />

l i m u m j i = 1,2,...n j = 1,2,...,i<br />

i−1 ∑<br />

m=1<br />

l i m u m j ) i = 1,2,...,n − 1 j = i + 1,...n<br />

97


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Si calcolano prima gli elementi della riga i -sima <strong>di</strong> L e poi quelli della riga i -sima <strong>di</strong> U , per i = 1,2,...,n.<br />

Trovate le matrici L e U , il sistema <strong>di</strong> partenza Ax = b è equivalente a LU x = b.<br />

Si pone, dunque, y = U x, ottenendo il sistema Ly = b. Si ricava facilmente y me<strong>di</strong>ante sostituzione in<br />

avanti e da U x = y si ricava x me<strong>di</strong>ante sostituzione all’in<strong>di</strong>etro.<br />

Lo sforzo computazionale maggiore è quin<strong>di</strong> quello per il calcolo dei coefficienti <strong>di</strong> L e U .<br />

Nell’eliminazione <strong>di</strong> Gauss noi ricaviamo espressamente solo la U mentre le mo<strong>di</strong>fiche operate sulla<br />

colonna dei termini noti è equivalente al prodotto L −1 b (quin<strong>di</strong> da LU x = b risolviamo U x = L −1 b).<br />

7.5.2 Fattorizzazione <strong>di</strong> Gauss senza pivoting<br />

Matrice <strong>di</strong>agonalmente<br />

dominante in<br />

senso stretto<br />

per righe<br />

Matrice <strong>di</strong>agonalmente<br />

dominante in<br />

senso stretto<br />

per colonne<br />

Abbiamo visto che, a volte, il metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss richiede scambi <strong>di</strong> righe per evitare <strong>di</strong>visioni<br />

per zero. Allo stesso modo, il teorema <strong>di</strong> fattorizzazione LDU vale su matrici A non singolari o su matrici<br />

ottenute da A me<strong>di</strong>ante moltiplicazioni a sinistra o a destra con opportune matrici <strong>di</strong> permutazione.<br />

Ci chie<strong>di</strong>amo se esistono matrici per le quali il metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss possa essere implementato<br />

senza scambi <strong>di</strong> righe e per le quali l’algoritmo <strong>di</strong> eliminazione <strong>di</strong> Gauss sia stabile rispetto ad una crescita<br />

<strong>di</strong> errori <strong>di</strong> arrotondamento.<br />

Ve<strong>di</strong>amo, nel seguito, alcune speciali classi <strong>di</strong> matrici per cui valgono le nostre richieste.<br />

Una matrice A <strong>di</strong> <strong>di</strong>mensione n si <strong>di</strong>ce <strong>di</strong>agonalmente dominante in senso stretto per righe se vale la<br />

relazione<br />

|a i i | ><br />

n∑<br />

|a i j | per ogni i = 1,2,...,n.<br />

j =0<br />

j ≠i<br />

Una matrice A <strong>di</strong> <strong>di</strong>mensione n si <strong>di</strong>ce <strong>di</strong>agonalmente dominante in senso stretto per colonne se vale la<br />

relazione<br />

|a j j | ><br />

n∑<br />

|a i j | per ogni j = 1,2,...,n.<br />

i=0<br />

i≠j<br />

Esempio 7.5.2<br />

⎛<br />

⎞<br />

7 3 1<br />

A = ⎝2 10 −2⎠<br />

5 0 6<br />

A è una matrice <strong>di</strong>agonalmente dominante in senso stretto per righe poichè vale:|7| > |3| + |1| = 4, |10| ><br />

|2| + | − 2| = 4 e |6| > |5| + |0|. Non è <strong>di</strong>agonalmente dominante in senso stretto per colonne in quanto sulla<br />

prima colonna si ha |7| = |2| + |5|.<br />

Esempio 7.5.3<br />

⎛<br />

⎞<br />

6 3 −4<br />

A = ⎝ 3 9 5 ⎠<br />

−4 5 11<br />

A non è <strong>di</strong>agonalmente dominante in senso stretto per righe poichè, sulla prima riga si ha |6| < |3| + | − 4| =<br />

7. Essendo simmetrica, la matrice non può essere neanche <strong>di</strong>agonalmente dominante in senso stretto per<br />

colonne, perchè la relazione che abbiamo sulla prima riga vale sulla prima colonna.<br />

Le definizioni appena date si possono rilassare, definendo le matrici <strong>di</strong>agonalmente dominanti.<br />

98


7.5. Fattorizzazione triangolare<br />

Una matrice A <strong>di</strong> <strong>di</strong>mensione n si <strong>di</strong>ce <strong>di</strong>agonalmente dominante per righe se vale la relazione<br />

|a i i | ≥<br />

n∑<br />

|a i j | per ogni i = 1,2,...,n.<br />

j =0<br />

j ≠i<br />

Analoga è la definizione <strong>di</strong> matrice <strong>di</strong>agonalmente dominante per colonne (basta applicare la definizione<br />

<strong>di</strong> matrice <strong>di</strong>agonalmente dominante per righe sulla matrice A T )<br />

Si hanno i seguenti teoremi.<br />

Matrice <strong>di</strong>agonalmente<br />

dominante<br />

Teorema 7.5.2 Se A è una matrice <strong>di</strong>agonalmente dominante e non singolare, allora il metodo <strong>di</strong> eliminazione<br />

<strong>di</strong> Gauss può essere implementato senza alcuno scambio <strong>di</strong> righe e <strong>di</strong> colonne e i calcoli sono stabili rispetto<br />

alla crescita <strong>degli</strong> errori <strong>di</strong> arrotondamento.<br />

Teorema 7.5.3 Se A è una matrice <strong>di</strong>agonalmente dominante in senso stretto (per righe o per colonne), allora<br />

A è non singolare. In questo caso il metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss può essere implementato senza alcuno<br />

scambio <strong>di</strong> righe e <strong>di</strong> colonne e i calcoli sono stabili rispetto alla crescita <strong>degli</strong> errori <strong>di</strong> arrotondamento.<br />

Un’altra importante classe <strong>di</strong> matrici è data dalle matrici definite positive.<br />

Una matrice A <strong>di</strong> <strong>di</strong>mensione n si <strong>di</strong>ce<br />

G definita positiva se è simmetrica e vale x T Ax > 0 qualunque sia il vettore x ≠ 0<br />

G semidefinita positiva se x T Ax ≥ 0 qualunque sia il vettore x,<br />

G indefinita altrimenti. 2<br />

Si ha un’analoga definizione per matrici definite negative e semidefinite negative. Una matrice A <strong>di</strong><br />

<strong>di</strong>mensione n si <strong>di</strong>ce<br />

definita negativa se è simmetrica e vale x T Ax < 0 qualunque sia il vettore x ≠ 0,<br />

G semidefinita negativa se x T Ax ≤ 0 qualunque sia il vettore x.<br />

Dalla definizione <strong>di</strong> matrice definita positiva, deve essere x T Ax > 0 qualunque sia il vettore x, vale a <strong>di</strong>re:<br />

⎛<br />

⎞⎛<br />

⎞<br />

a 11 a 12 ... a 1n x 1<br />

( )<br />

a 21 a 22 ... a 2n<br />

x 2<br />

x1 x 2 ... x m ⎜<br />

⎝<br />

.<br />

. ...<br />

⎟⎜<br />

. ⎠⎝<br />

⎟<br />

. ⎠<br />

a n1 a n2 ... a nn x m<br />

⎛∑ n<br />

j =1 a ⎞<br />

1j x j<br />

= ( ∑ n<br />

)<br />

j =1<br />

x 1 x 2 ... x m a 2j x j<br />

n∑ n∑<br />

⎜<br />

⎝<br />

⎟<br />

. ⎠ = a i j x i x j > 0<br />

i=1 j =1<br />

∑ n<br />

j =1 a n j x j<br />

Matrice<br />

definita<br />

positiva<br />

Matrice<br />

definita<br />

negativa<br />

Basarsi sulla definizione per verificare che una matrice sia o meno definita positiva può essere molto<br />

<strong>di</strong>fficile. Fortunatamente, ci sono molti criteri che ci permettono <strong>di</strong> <strong>di</strong>re se una matrice è definita positiva<br />

oppure no.<br />

IL seguente risultato ci permette <strong>di</strong> eliminare certe matrici dalla classe delle matrici definite positive, se<br />

non sod<strong>di</strong>sfano certi requisiti.<br />

Teorema 7.5.4 Se una matrice A <strong>di</strong> <strong>di</strong>mensione n è definita positiva, allora<br />

G A ammette la matrice inversa;<br />

G a i i > 0 per ogni i = 1,2,...,n<br />

2 Osserviamo che non tutti gli autori richiedono la simmetria per definire una matrice definita positiva, e <strong>di</strong>stinguono tra matrici<br />

definite positive e matrici simmetriche definite positive.<br />

99


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Quin<strong>di</strong> se una matrice ha elementi a i i ≤ 0, non è una matrice definita positiva, perché, se lo fosse, in base al<br />

teorema avrebbe elementi <strong>di</strong>agonali tutti positivi.<br />

Ve<strong>di</strong>amo ora una con<strong>di</strong>zione necessaria e sufficiente per matrici definite positive.<br />

Teorema 7.5.5 Una matrice A simmetrica <strong>di</strong> <strong>di</strong>mensione n è definita positiva se e solo se tutti i suoi minori<br />

principali hanno determinante positivo.<br />

Teorema 7.5.6 Una matrice A simmetrica <strong>di</strong> <strong>di</strong>mensione n con elementi <strong>di</strong>agonali tutti positivi e<br />

<strong>di</strong>agonalmente dominante è definita positiva.<br />

Anche per matrici simmetriche definite positive, si può applicare il metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss<br />

senza operare scambi <strong>di</strong> righe e <strong>di</strong> colonne e i calcoli rimangono stabili rispetto alla crescita <strong>degli</strong> errori <strong>di</strong><br />

arrotondamento. Questo risultato ci serve per la fattorizzazione <strong>di</strong> Cholesky.<br />

7.5.3 Fattorizzazione <strong>di</strong> Cholesky<br />

Nel caso in cui la matrice A sia simmetrica, il teorema LDU si presenta nel seguente modo<br />

Teorema 7.5.7 (LDU per matrici simmetriche) Se A è una matrice simmetrica e nessuno dei suoi minori<br />

principali è singolare, allora A si può decomporre nel prodotto A = LDL T , dove L è triangolare inferiore con<br />

elementi <strong>di</strong>agonali unitari ed è univocamente determinata, L T è la sua trasposta e D è matrice <strong>di</strong>agonale.<br />

Dimostrazione. Intanto valgono le ipotesi del teorema LDU e quin<strong>di</strong> si può scrivere in maniera univoca<br />

A = LDU con L matrice triangolare inferiore, D <strong>di</strong>agonale e U triangolare superiore. Inoltre, poichè A è<br />

simmetrica, e quin<strong>di</strong> A = A T , si ha pure LDU = (LDU ) T vale a <strong>di</strong>re LDU = U T D T L T = U T DL T . Si deduce,<br />

dall’uguaglianza, che U = L T e la decomposizione <strong>di</strong>venta A = LDL T . ✔<br />

Nel caso particolare in cui A sia simmetrica e definita positiva, da x T Ax > 0 vale pure<br />

x T Ax = x T LDL T x = (L T x) T DL T x = y T Dy > 0 con y = L T x per ogni x > 0.<br />

Essendo A è definita positiva, risulta anche D definita positiva. Perciò gli elementi <strong>di</strong> D (che è una matrice<br />

<strong>di</strong>agonale) devono necessariamente essere tutti positivi. In tal caso, si considera la matrice D 1/2 che è la<br />

matrice <strong>di</strong>agonale con elementi dati dalle ra<strong>di</strong>ci quadrate <strong>degli</strong> elementi <strong>di</strong>agonali <strong>di</strong> D (si prende il valore<br />

positivo della ra<strong>di</strong>ce quadrata, e il risultato è un numero reale in virtù del fatto che gli elementi <strong>di</strong>agonali <strong>di</strong><br />

D sono tutti positivi). Si pone, quin<strong>di</strong>, M = LD 1/2 e si ottiene A = M M T : abbiamo il prodotto <strong>di</strong> una matrice<br />

triangolare inferiore con coefficienti tutti reali per la sua trasposta. Se D non fosse definita positiva (ma avesse<br />

qualche elemento negativo), allora neanche A sarebbe definita positiva e la matrice M sarebbe non reale.<br />

Quin<strong>di</strong> se A è simmetrica, si ha la decomposizione nel prodotto LL T (chiamiamo <strong>di</strong> nuovo con L la<br />

matrice M) con L reale se e solo se A è definita positiva.<br />

I coefficienti della matrice L si trovano facendo il prodotto righe per colonne ed eguagliando i termini ai<br />

corrispondenti elementi <strong>di</strong> A.<br />

Si ricava:<br />

l 11 = a 11<br />

l i 1 = a i 1 /l 11 i = 2,3,...,n<br />

i−1 ∑<br />

l i i = √ (ai i − l 2 i k ) i = 2,3,...,n<br />

k=1<br />

l i j = 1 j∑<br />

−1<br />

(a i j − l i k l j k ) j = 2,...,n i = j + 1,...,n<br />

l i i<br />

k=1<br />

Tale fattorizzazione prende il nome <strong>di</strong> fattorizzazione <strong>di</strong> Cholesky 3 .<br />

3 André-Louis Cholesky (1875-1918) fu un matematico francese. Fu ufficiale ingegnere e morì alla fine della prima guerra mon<strong>di</strong>ale.<br />

100


7.6. <strong>Esercizi</strong><br />

7.6 <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 7.6.1 ⎛ Sia data ⎞ la matrice<br />

1 0 2<br />

A = ⎝0 4 8 ⎠<br />

2 8 29<br />

Provare che verifica le con<strong>di</strong>zioni del teorema LDU e trovare i fattori L e L T tali che A = LL T .<br />

( ) 1 0<br />

Svolgimento La matrice A è simmetrica e sod<strong>di</strong>sfa le ipotesi del teorema LDU ( infatti |a 11 | = 1, det =<br />

0 4<br />

4 e det(A) = 116 − 16 − 64 = 36) per cui è possibile scrivere la matrice A come A = LL T . Si ha, quin<strong>di</strong>:<br />

⎛<br />

⎞⎛<br />

⎞ ⎛<br />

l 11 0 0 l 11 l 21 l 31 l 2 ⎞<br />

11<br />

l 11 l 21 l 11 l 31<br />

⎝l 21 l 22 0 ⎠⎝<br />

0 l 22 l 32<br />

⎠ = ⎝l 21 l 11 l21 2 + l 22 2 l 21 l 31 + l 22 l 32<br />

⎠<br />

l 31 l 32 l 33 0 0 l 33 l 31 l 11 l 31 l 21 + l 32 l 22 l31 2 + l 32 2 + l 33<br />

2<br />

Devono quin<strong>di</strong> valere le relazioni:<br />

l 2 11 = 1 =⇒ l 11 = 1<br />

l 21 l 11 = 0 =⇒ l 21 = 0<br />

l 31 l 11 = 2 =⇒ l 31 = 2<br />

l 2 21 + l 2 22 = 4 =⇒ l 22 = 4 − 0 = 2<br />

l 21 l 31 + l 22 l 32 = 8 =⇒ l 32 = 8/2 = 4<br />

√<br />

l31 2 + l 32 2 + l 33 2 = 29 =⇒ l 33 = 29 − 2 2 − 4 2 = 29 − 4 − 16 = 9 = 3<br />

La matrice L è dunque<br />

⎛<br />

1 0<br />

⎞<br />

0<br />

⎝0 2 0⎠<br />

2 4 3<br />

<strong>Esercizi</strong>o 7.6.2 ⎛ Data la matrice ⎞<br />

0.2 1 0.2<br />

A = ⎝ 1 6.5 1.75⎠<br />

0 2 2.25<br />

(a) verificare che A sod<strong>di</strong>sfa le con<strong>di</strong>zioni del teorema LDU ;<br />

(b) fattorizzare secondo Crout A = LU (prendendo u i i = 1);<br />

(c) usare la fattorizzazione per calcolare det(A −2 );<br />

(d) usare la fattorizzazione per risolvere il sistema Ax = b, con b T = (2.8 19.25 10.75) T .<br />

Svolgimento<br />

(a) La matrice verifica le con<strong>di</strong>zioni del teorema LDU in quanto i minori principali costruiti a partire<br />

dall’angolo superiore sinistro hanno tutti determinante <strong>di</strong>verso da zero:<br />

a 11 = 0.2 ≠ 0<br />

( ) 0.2 1<br />

det = 0.3 ≠ 0 det A = 0.375 ≠ 0<br />

1 6.5<br />

101


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

(b) La fattorizzazione <strong>di</strong> A come A = LU si costruisce imponendo:<br />

⎛<br />

⎞ ⎛<br />

⎞⎛<br />

⎞<br />

0.2 1 0.2<br />

l 11 0 0 1 u 12 u 13<br />

A = ⎝ 1 6.5 1.75⎠ = LU = ⎝l 21 l 22 0 ⎠⎝0 1 u 23<br />

⎠<br />

0 2 2.25<br />

l 31 l 32 l 33 0 0 1<br />

Usando le formule <strong>di</strong> pag. 97, si ottiene<br />

l 11 = 0.2<br />

0.2u 12 = 1 =⇒ u 12 = 5<br />

0.2u 13 = 0.2 =⇒ u 13 = 1<br />

l 21 = 1<br />

1 · 5 + l 22 = 6.5 =⇒ l 22 = 1.5<br />

1 · 1 + 1.5u 23 = 1.75 =⇒ u 23 = 0.5<br />

l 31 = 0<br />

0 · 5 + l 32 = 2 =⇒ l 32 = 2<br />

0 · 1 + 2 · 0.5 + l 33 = 2.25 =⇒ l 33 = 1.25<br />

Le matrici L e U sono:<br />

⎛<br />

0.2 0 0<br />

⎞<br />

⎛<br />

1 5<br />

⎞<br />

1<br />

L = ⎝ 1 1.5 0 ⎠ U = ⎝0 1 0.5⎠<br />

0 2 1.25<br />

0 0 1<br />

(c) Si ha det A = detLU = detL detU = detL = 0.375. Quin<strong>di</strong> det(A −2 ) = det(A) −2 = 0.375 −2 = 7.11111111.<br />

(d) Da Ax = b si ha LU x = b.<br />

Si pone U x = y e si hanno i due sistemi da risolvere per sostituzione in avanti e all’in<strong>di</strong>etro: Ly = b e<br />

U x = y.<br />

⎛<br />

⎞⎛<br />

⎞ ⎛ ⎞ ⎧<br />

0.2 0 0 y 1 2.8 ⎪⎨ y 1 = 2.8/0.2 = 14<br />

⎝ 1 1.5 0 ⎠⎝y 2<br />

⎠ = ⎝19.25⎠ =⇒ y 2 = (19.25 − 14)/1.5 = 3.5<br />

0 2 1.25 y 3 10.75<br />

⎪⎩<br />

y 3 = (10.75 − 2 · 3.5)1.25 = 3<br />

⎛ ⎞⎛<br />

⎞ ⎛ ⎞ ⎧<br />

1 5 1 x 1 14 ⎪⎨ x 3 = 3<br />

⎝0 1 0.5⎠⎝x 2<br />

⎠ = ⎝3.5⎠ =⇒ x 2 = 3.5 − 3 · 0.5 = 2<br />

0 0 1 x 3 3<br />

⎪⎩<br />

x 1 = 14 − 3 − 5 · 2 = 1<br />

Quin<strong>di</strong> x = (1, 2, 3) T .<br />

<strong>Esercizi</strong>o 7.6.3 ⎛ È dato il sistema ⎞ lineare ⎛ Ax = ⎞ b dove:<br />

16 −8 4<br />

20<br />

A = ⎝−8 20 4 ⎠ b = ⎝ 28 ⎠<br />

4 4 12.25<br />

28.25<br />

(a) Provare che la matrice è definita positiva.<br />

(b) Fattorizzare la matrice secondo Cholesky: A = LL T .<br />

(c) Usare la fattorizzazione per risolvere il sistema Ax = b e per calcolare det(A 3 ).<br />

102<br />

Soluzione


7.6. <strong>Esercizi</strong><br />

(a) La matrice è simmetrica, definita positiva in quanto gli elementi della <strong>di</strong>agonale principale sono tutti<br />

positivi e la matrice è <strong>di</strong>agonalmente dominante in senso stretto:<br />

16 > | − 8| + |4| = 12<br />

20 > | − 8| + |4| = 12<br />

12.25 > |4| + |4| = 8<br />

(b) Ponendo A = LL T si ricava:<br />

l 2 11 = 16 =⇒ l 11 = 4<br />

l 21 l 11 = −8 =⇒ l 21 = −2<br />

l 31 l 11 = 4 =⇒ l 31 = 1<br />

l 2 21 + l 2 22 = 20 =⇒ l 22 = 20 − 4 = 4<br />

l 21 l 31 + l 22 l 32 = 4 =⇒ l 32 = (4 + 2)/4 = 1.5<br />

l 2 31 + l 2 32 + l 2 33 = 12.25 =⇒ l 33 = 12.25 − 1 − 2.25 = 9 = 3<br />

La matrice L è dunque<br />

⎛<br />

4 0<br />

⎞<br />

0<br />

L = ⎝−2 4 0⎠<br />

1 1.5 3<br />

(c) Per risolvere il sistema Ax = b, adoperiamo il metodo <strong>di</strong> sostituzione in avanti e all’in<strong>di</strong>etro risolvendo<br />

i sistemi: Ly = b e poi L T x = y.<br />

Il primo sistema dà:<br />

⎛<br />

⎞⎛<br />

⎞ ⎛ ⎞<br />

4 0 0 y 1 20<br />

⎝−2 4 0⎠⎝y 2<br />

⎠ = ⎝ 28 ⎠<br />

1 1.5 3 y 3 28.25<br />

e otteniamo y 1 = 20/4 = 5, y 2 = (28 + 10)/4 = 9.5, y 3 = (28.25 − 5 − 14.25)/3 = 3.<br />

Nel risolvere il sistema L T x = y si ha<br />

⎛<br />

⎞⎛<br />

⎞ ⎛ ⎞<br />

4 −2 1 x 1 5<br />

⎝0 4 1.5⎠⎝x 2<br />

⎠ = ⎝9.5⎠<br />

0 0 3 x 3 3<br />

da cui x 3 = 1, x 2 = (9.5 − 1.5)/4 = 2, x 1 = (5 − 1 + 4)/4 = 2, quin<strong>di</strong> x = (2, 2, 1).<br />

Inoltre, da det(A) = det(LL T ) = det(L) 2 = (4 · 4 · 3) 2 = 48 2 = 2304 e da det(A 3 ) = (det(A)) 3 si ha<br />

det(A 3 ) = 2304 3 = 12230590464.<br />

103


C A P I T O L O<br />

8<br />

METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Mi spiace ammettere che la materia<br />

che mi è piaciuta <strong>di</strong> meno è stata la<br />

matematica. Ci ho pensato su, e<br />

credo che la ragione sia che la<br />

matematica non lascia spazio alle<br />

<strong>di</strong>scussioni. Se fai un errore, non<br />

puoi scamparla.<br />

Malcom X<br />

8.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />

8.2 Meto<strong>di</strong> iterativi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

8.3 Norme <strong>di</strong> vettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

8.4 Norme <strong>di</strong> matrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107<br />

8.5 Autovalori e autovettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />

8.6 Meto<strong>di</strong> classici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110<br />

8.6.1 Convergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110<br />

8.6.2 Controllo della convergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111<br />

8.6.3 I meto<strong>di</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113<br />

8.6.4 Convergenza dei meto<strong>di</strong> <strong>di</strong> Jacobi, Gauss-Seidel, rilassamento . . . . . . . . . . . . . . . . 117<br />

8.7 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />

8.1 Introduzione<br />

L’equazione che governa la conduzione del calore in una piastra metallica piana, omogenea e isotropa<br />

prende il nome <strong>di</strong> equazione <strong>di</strong> Poisson e si scrive come<br />

∂ 2 T<br />

∂x 2 + ∂2 T f (x, y)<br />

=<br />

∂y<br />

2<br />

ρcK H<br />

Si tratta <strong>di</strong> un’equazione alle derivate parziali dove T [ o C ] è la temperatura, K H [m 2 /s] è il coefficiente <strong>di</strong> <strong>di</strong>ffusività<br />

termica, ρ [K g /m 2 ] è la densità della piastra, c [C al/K g o C ] è il calore specifico, f (x, y) [C al/m 2 s] è il<br />

calore aggiunto o sottratto alla piastra per unità <strong>di</strong> tempo e <strong>di</strong> area. In letteratura <strong>di</strong>verse tecniche numeriche<br />

permettono <strong>di</strong> risolvere il problema (ricor<strong>di</strong>amo i meto<strong>di</strong> alle <strong>di</strong>fferenze finite e i meto<strong>di</strong> agli elementi finiti),<br />

105


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

in determinati punti (detti no<strong>di</strong>) della piastra. Qualunque sia il metodo utilizzato, si arriva ad un sistema <strong>di</strong><br />

equazioni lineari del tipo<br />

HT = q<br />

dove H rappresenta la matrice <strong>di</strong> <strong>di</strong>scretizzazione del metodo, T rappresenta il vettore delle temperature nei<br />

no<strong>di</strong> e q è il vettore dei termini noti che deriva dal metodo applicato.<br />

La matrice H puó avere una <strong>di</strong>mensione molto elevata ma ha la caratteristica <strong>di</strong> essere sparsa, cioè <strong>di</strong><br />

avere pochi elementi <strong>di</strong>versi da zero per ogni riga.<br />

Per risolvere sistemi lineari <strong>di</strong> questo tipo, si preferisce usare meto<strong>di</strong> iterativi piuttosto che <strong>di</strong>retti. In<br />

questo Capitolo presentiamo alcuni dei meto<strong>di</strong> iterativi per la risoluzione <strong>di</strong> sistemi lineari.<br />

8.2 Meto<strong>di</strong> iterativi<br />

Per risolvere un sistema <strong>di</strong> equazioni lineari Ax = b, applicando un metodo <strong>di</strong>retto, e trascurando gli<br />

errori <strong>di</strong> arrotondamento, si ottiene la soluzione esatta del problema in un numero finito (e noto a priori)<br />

<strong>di</strong> operazioni. Nei meto<strong>di</strong> iterativi, invece, si parte da un’approssimazione iniziale che viene migliorata,<br />

me<strong>di</strong>ante un proce<strong>di</strong>mento iterativo, fino ad ottenere una approssimazione sufficientemente accurata della<br />

soluzione. L’idea <strong>di</strong> risolvere sistemi lineri con meto<strong>di</strong> iterativi risale ai tempi <strong>di</strong> Gauss (1823), ma solo con<br />

l’avvento dei computers (negli anni cinquanta) si può osservare il loro sviluppo, visto che <strong>di</strong>venta possibile<br />

risolvere sistemi lineari dove la matrice A è sparsa e <strong>di</strong> gran<strong>di</strong> <strong>di</strong>mensioni – un particolare tipo <strong>di</strong> problema<br />

improponibile per i meto<strong>di</strong> <strong>di</strong>retti. Difatti, nei meto<strong>di</strong> <strong>di</strong>retti, il processo <strong>di</strong> eliminazione <strong>di</strong> Gauss (o la<br />

decomposizione della matrice <strong>di</strong> partenza nel prodotto LU con L triangolare inferiore e U triangolare superiore)<br />

porta all’introduzione del cosiddetto fill-in, cioè a matrici L e U con elementi <strong>di</strong>versi da zero là dove<br />

la matrice <strong>di</strong> partenza A ha elementi nulli. I meto<strong>di</strong> <strong>di</strong>retti <strong>di</strong>ventano quin<strong>di</strong> proibitivi perchè troppo costosi<br />

per quanto riguarda il numero <strong>di</strong> operazioni aritmetiche e l’occupazione <strong>di</strong> dati che devono essere salvati per<br />

l’implementazione numerica del metodo stesso. I meto<strong>di</strong> iterativi, al contrario, lavorano <strong>di</strong>rettamente sulla<br />

matrice A e, dal momento che A viene coinvolta solo in termini <strong>di</strong> prodotti matrice-vettore, non c’è neanche<br />

bisogno <strong>di</strong> memorizzare tutta la matrice (in genere, quando la matrice è sparsa, si lavora su memorizzazioni<br />

in forma compatta delle matrici, memorizzando solo gli elementi non nulli che servono per il prodotto<br />

matrice-vettore).<br />

Quando abbiamo stu<strong>di</strong>ato gli zeri <strong>di</strong> funzione nel Capitolo 4, data un’approssimazione iniziale, si procedeva<br />

nell’algoritmo iterativo fino a quando lo scarto tra due approssimazioni successive non <strong>di</strong>ventava<br />

minore <strong>di</strong> una prefissata tolleranza.<br />

Nel caso dei sistemi lineari, l’approccio è simile. Si parte da un vettore iniziale che approssima la soluzione<br />

del sistema e, me<strong>di</strong>ante un certo proce<strong>di</strong>mento ricorsivo, si calcola una nuova approssimazione (un<br />

vettore). Dobbiamo dunque essere capaci <strong>di</strong> misurare lo scarto tra due vettori in modo da capire quando la<br />

successione dei vettori generati dall’algoritmo tende al vettore soluzione del sistema lineare.<br />

Abbiamo perciò bisogno <strong>di</strong> definire le norme <strong>di</strong> vettori e <strong>di</strong> matrici. Nel seguito, tratteremo solo norme <strong>di</strong><br />

matrici e vettori definite nello spazio dei numeri reali (e non complessi).<br />

Norma<br />

Norme 1, ∞,<br />

8.3 Norme <strong>di</strong> vettori<br />

Il concetto <strong>di</strong> norma generalizza quello <strong>di</strong> valore assoluto (o modulo) <strong>di</strong> un numero reale (o complesso).<br />

Sia R n lo spazio dei vettori colonna <strong>di</strong> lunghezza n. La norma <strong>di</strong> un vettore x ∈ R n è una funzione, ‖ · ‖,<br />

definita in R n e a valori in R, che gode delle seguenti proprietà:<br />

‖x‖ > 0 per ogni x ≠ 0<br />

‖x‖ = 0 se e solo se x = 0<br />

‖αx‖ = |α|‖x‖ dove α è un reale (o complesso) arbitrario<br />

G ‖x + y‖ ≤ ‖x‖ + ‖y‖<br />

Le principali norme vettoriali sono:<br />

2<br />

G Norma assoluta (o norma l 1 ), in<strong>di</strong>cata con ‖ · ‖ 1 : ‖x‖ 1 = ∑ n<br />

i=1 |x i |<br />

G Norma massima (o norma infinito, l ∞ ), in<strong>di</strong>cata con ‖ · ‖ ∞ : ‖x‖ ∞ = max 1≤i≤n |x i |<br />

106


8.4. Norme <strong>di</strong> matrici<br />

Figura 8.1: Vettori in R 2 con norma unitaria nelle norme 1, ∞ e 2.<br />

G Norma euclidea (o norma l 2 ), in<strong>di</strong>cata con ‖ · ‖ 2 : ‖x‖ 2 = √ ∑n<br />

x T x =<br />

i=1 |x i | 2<br />

Tra le norme 1, ∞ e 2 valgono le seguenti relazioni (che pongono un’equivalenza tra esse). Dato un vettore<br />

x ∈ R n :<br />

‖x‖ ∞ ≤ ‖x‖ 2 ≤ n‖x‖ ∞<br />

‖x‖ ∞ ≤ ‖x‖ 1 ≤ n‖x‖ ∞<br />

Esempio 8.3.1 Il vettore x = (1,5,−20) T ha norme:<br />

‖x‖ 1 = |1| + |5| + | − 20| = 26<br />

‖x‖ ∞ = max(|1|,|5|,| − 20|) = 20<br />

√<br />

‖x‖ 2 = (1 2 + 5 2 + (−20) 2 ) = 426 = 20.639767441<br />

Per la norma euclidea vale la <strong>di</strong>seguaglianza <strong>di</strong> Cauchy-Schwarz:<br />

Diseguaglianza<br />

<strong>di</strong> Cauchy-<br />

Schwarz<br />

x T y ≤ ‖x‖ 2 ‖y‖ 2<br />

Dati due vettori x e y ∈ R n , si definisce <strong>di</strong>stanza tra i due vettori la norma della <strong>di</strong>fferenza tra i vettori.<br />

Quin<strong>di</strong>:<br />

n∑<br />

‖x − y‖ 1 = |x i − y i |<br />

i=1<br />

‖x − y‖ ∞ = max |x i − y i |<br />

1≤i≤n<br />

Distanza tra<br />

vettori<br />

‖x − y‖ 2 =<br />

√ n∑<br />

|x i − y i | 2<br />

i=1<br />

Il concetto <strong>di</strong> <strong>di</strong>stanza serve per definire il limite <strong>di</strong> una successione <strong>di</strong> vettori.<br />

Data una successione <strong>di</strong> vettori in R n , x (k) , per k = 1,2,...,∞, si <strong>di</strong>ce che la successione converge ad un<br />

vettore x <strong>di</strong> R n e si scrive lim k→∞ x (k) = x se, per ogni ɛ > 0, esiste un intero m tale che<br />

‖x (k) − x‖ < ɛ per tutti gli in<strong>di</strong>ci k ≥ m<br />

Limite <strong>di</strong> una<br />

successione<br />

<strong>di</strong> vettori<br />

8.4 Norme <strong>di</strong> matrici<br />

Analogamente alla definizione <strong>di</strong> norma vettoriale, la norma <strong>di</strong> matrici quadrate <strong>di</strong> <strong>di</strong>mensione n è una<br />

funzione, che in<strong>di</strong>chiamo con ‖ · ‖ che, per tutte le matrici A e B <strong>di</strong> <strong>di</strong>mensione n e per tutti i numeri reali (o<br />

complessi) α, sod<strong>di</strong>sfa le seguenti proprietà:<br />

107


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Norma<br />

compatibile<br />

Norma<br />

naturale<br />

traccia <strong>di</strong> una<br />

matrice<br />

G ‖A‖ > 0 per ogni A ≠ 0<br />

G ‖A‖ = 0 se e solo se A = 0<br />

G ‖αA‖ = |α|‖A‖<br />

G ‖A + B‖ ≤ ‖A‖ + ‖B‖<br />

G ‖AB‖ ≤ ‖A‖‖B‖<br />

Una proprietà importante che si richiede alle norme su matrici è che siano compatibili con norme vettoriali:<br />

la norma ‖A‖ <strong>di</strong> una matrice A si <strong>di</strong>ce compatibile con la norma ‖x‖ <strong>di</strong> un vettore x se vale la<br />

relazione<br />

‖Ax‖ ≤ ‖A‖‖x‖<br />

Alcune norme su matrici sono generate da norme su vettori: si parla allora <strong>di</strong> norma naturale o indotta<br />

dalla norma <strong>di</strong> vettori. In particolare, se ‖ · ‖ è una norma su vettori in R n , allora ‖A‖ = max ‖x‖=1 ‖Ax‖ è la<br />

norma naturale o indotta dalla norma ‖ · ‖ su vettori.<br />

Le norme <strong>di</strong> matrici indotte dalla norma 1 e dalla norma infinito su vettori sono:<br />

G Norma 1: ‖A‖ 1 = max j<br />

∑ n<br />

i=1 |a i j | (data dal massimo sulla somma delle colonne)<br />

G Norma infinito: ‖A‖ ∞ = max i<br />

∑ n<br />

j =1 |a i j | (data dal massimo sulla somma delle righe)<br />

La norma <strong>di</strong> matrice indotta dalla norma 2 è più complicata e vedremo in seguito come è definita.<br />

È facile vedere che le norme naturali sono norme compatibili con la norma <strong>di</strong> vettori da cui sono costruite.<br />

Una norma <strong>di</strong> matrici, che non è indotta, ma compatibile con la norma 2 è la cosiddetta norma euclidea<br />

(o <strong>di</strong> Frobenius). Tenendo presente che, data una matrice A, si chiama traccia della matrice o tr (A) la somma<br />

<strong>degli</strong> elementi della <strong>di</strong>agonale principale <strong>di</strong> A, la norma euclidea è data da<br />

G N (A) = √ tr (A T A) = √ √ ∑n<br />

tr (A A T ) =<br />

i=1<br />

|a i j | 2 .<br />

j =1<br />

8.5 Autovalori e autovettori<br />

Data una matrice quadrata A <strong>di</strong> or<strong>di</strong>ne n, se esiste un numero (reale o complesso) λ e un vettore x ≠ 0 tali<br />

che<br />

Ax = λx<br />

Autovalore e<br />

autovettore<br />

allora λ è un autovalore e x il corrispondente autovettore della matrice A.<br />

Scritta in maniera equivalente, la relazione definisce il sistema lineare<br />

(A − λI )x = 0<br />

Poichè x ≠ 0 e il termine noto del sistema è il vettore <strong>di</strong> tutti zeri, il determinante della matrice del sistema<br />

deve necessariamente essere uguale a zero, cioè det(A − λI ) = 0.<br />

Lo sviluppo del determinante porta a un polinomio <strong>di</strong> grado n nell’incognita λ:<br />

λ n − tr (A)λ n−1 + ... + (−1) n det(A) = 0<br />

Polinomio Questo polinomio si chiama polinomio caratteristico. Le sue n ra<strong>di</strong>ci, che chiamiamo λ 1 ,λ 2 ,...,λ n , sono gli<br />

caratteristico n autovalori della matrice A.<br />

Per le proprietà dei polinomi vale:<br />

n∑<br />

λ i = tr (A) = a 11 + a 22 + ... + a nn<br />

i=1<br />

e<br />

n∏<br />

λ i = det(A)<br />

i=1<br />

108<br />

Alcune proprietà sugli autovalori e autovettori sono le seguenti:<br />

G Se λ è autovalore della matrice A, allora λ k è autovalore della matrice potenza A k (cioè A · A ··· A k<br />

volte).


8.5. Autovalori e autovettori<br />

Figura 8.2: Autovalori e autovettori<br />

G Gli autovalori <strong>di</strong> una matrice A e della sua trasposta A T sono gli stessi (ma gli autovettori sono, in<br />

genere, <strong>di</strong>versi).<br />

G Se A e B sono due matrici arbitrarie regolari, allora gli autovalori <strong>di</strong> AB sono gli stessi <strong>di</strong> B A.<br />

Se x è un autovettore associato alla matrice A, allora Ax = λx: la matrice A trasforma il vettore x in un<br />

vettore le cui componenti sono moltiplicate per λ: se λ > 1, allora A ha l’effetto <strong>di</strong> allungare x <strong>di</strong> un fattore λ;<br />

se invece 0 < λ < 1, allora x si restringe <strong>di</strong> un fattore λ; gli effetti sono simili, ma il verso del vettore risultante<br />

Ax è opposto, quando λ < 0. I quattro casi che si possono presentare sono illustrati in Figura 8.2.<br />

Altre proprietà da tenere presenti sono le seguenti:<br />

G Se tutti gli n autovalori <strong>di</strong> una matrice A sono <strong>di</strong>stinti, allora gli n autovettori u (1) , u (2) ,...u (n) sono<br />

linearmente in<strong>di</strong>pendenti. 1<br />

G Se A è una matrice simmetrica reale definita positiva, allora i suoi autovalori sono tutti reali e positivi.<br />

Introduciamo ora il raggio spettrale <strong>di</strong> una matrice A .<br />

Definizione 8.5.1 Il raggio spettrale ρ(A) <strong>di</strong> una matrice A è definito da<br />

ρ(A) = max |λ|<br />

λ autovalore <strong>di</strong> A<br />

Quin<strong>di</strong> il raggio spettrale è il massimo, in modulo, <strong>degli</strong> autovalori <strong>di</strong> A (ricor<strong>di</strong>amo che se λ è un<br />

complesso, λ = α + iβ, con i = −1, si ha |λ| = √ α 2 + β 2 ).<br />

Possiamo ora definire la norma 2 su matrici indotta dalla norma 2 su vettori. Si può, infatti, provare che<br />

√<br />

G ‖A‖ 2 = ρ(A T A).<br />

Inoltre, per ogni norma naturale, vale il risultato<br />

Raggio<br />

spettrale<br />

Norma 2 su<br />

matrici<br />

ρ(A) ≤ ‖A‖<br />

Nello stu<strong>di</strong>are i meto<strong>di</strong> iterativi per risolvere i sistemi lineari, sarà <strong>di</strong> particolare importanza sapere quando<br />

le potenze <strong>di</strong> una matrice tendono alla matrice nulla. Matrici A, per cui (A k ) i j → 0 per k → ∞, qualunque<br />

sia i , j = 1,2,...,n, (consideriamo A · A ··· A k volte e gli elementi della matrice risultante tendono a zero per<br />

k → ∞) si <strong>di</strong>cono matrici convergenti. Diciamo che una matrice A <strong>di</strong> <strong>di</strong>mensione n è convergente se<br />

lim<br />

k→∞ (Ak ) i j = 0, i , j = 1,2,...,n<br />

Si ha il seguente teorema.<br />

Matrice<br />

convergente<br />

Teorema 8.5.1 Data una matrice A <strong>di</strong> <strong>di</strong>mensione n, sono equivalenti le seguenti proposizioni<br />

1. A è una matrice convergente.<br />

2. lim k→∞ ‖A k ‖ = 0, per qualche norma naturale.<br />

3. lim k→∞ ‖A k ‖ = 0, per tutte le norme naturali.<br />

4. ρ(A) < 1.<br />

5. lim k→∞ A k x = 0, qualunque sia il vettore x.<br />

1 Dati n vettori linearmente in<strong>di</strong>pendenti <strong>di</strong> R n , u (1) , u (2) ,...u (n) , ogni vettore <strong>di</strong> R n si può scrivere come una loro combinazione<br />

lineare. Quin<strong>di</strong> esistono n coefficienti α 1 ,α 2 ,...,α n per cui x = α 1 u (1) +α 2 u (2) +...+α n u (n) . Inoltre, per vettori linearmente in<strong>di</strong>pendenti<br />

vale il risultato: α 1 u (1) + α 2 u (2) + ... + α n u (n) = 0 se e solo se tutti i coefficienti α i sono uguali a zero, per i = 1,2,...,n.<br />

109


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

8.6 Meto<strong>di</strong> classici<br />

I meto<strong>di</strong> iterativi classici per la risoluzione <strong>di</strong> un sistema <strong>di</strong> equazioni lineari del tipo Ax = b si basano su<br />

un’idea molto semplice.<br />

G Si parte da un’approssimazione iniziale x (0) , commettendo un’errore e (0) = x − x (0) . L’errore e (0) è soluzione<br />

del sistema Ae (0) = b − Ax (0) = r (0) , dove r (0) è il residuo (ciò che resta fuori, ci <strong>di</strong>ce <strong>di</strong> quanto il<br />

vettore Ax (0) si <strong>di</strong>scosta da b).<br />

G Successivamente si definisce il passo x (1) come x (1) = x (0) + p (0) , dove ora p (0) è soluzione del sistema<br />

Mp (0) = r 0 , in cui la matrice M è più semplice della A e, allo stesso tempo, M −1 approssima in qualche<br />

modo A −1 .<br />

G Il proce<strong>di</strong>mento viene iterato fino a convergenza.<br />

Da queste richieste tra loro contrad<strong>di</strong>torie, si sviluppa una strategia che porta alla soluzione esatta x come<br />

limite della successione dei valori approssimati x (k) .<br />

Il processo iterativo si legge, infatti, come:<br />

x (k+1) = x (k) + M −1 (b − Ax (k) ) k = 0,1,....<br />

O, equivalentemente,<br />

x (k+1) = (I − M −1 A)x (k) + M −1 b k = 0,1,...<br />

Notiamo che, ad ogni passo, non dobbiamo calcolare esplicitamente M −1 , perchè risolviamo problemi del<br />

tipo Mp (k) = r (k) = b − Ax (k) in modo da porre x (k+1) = x (k) + p (k) . La matrice E = I − M −1 A è detta matrice <strong>di</strong><br />

iterazione del metodo. Nel seguito, per semplicità, poniamo q = M −1 b.<br />

Lo schema iterativo appena descritto è un metodo stazionario (cioè non <strong>di</strong>pende dall’iterazione k) e<br />

può essere visto come caso particolare <strong>di</strong> uno schema <strong>di</strong> punto fisso per equazioni nonlineari: la funzione<br />

g tale che x (k+1) = g (x (k) ) converga alla soluzione del sistema Ax = b, è data da g (x) = x + M −1 (b − Ax) o<br />

equivalentemente da g (x) = Ex (k) + q.<br />

8.6.1 Convergenza<br />

Per stu<strong>di</strong>are la convergenza <strong>di</strong> un metodo iterativo, consideriamo, per ogni vettore x (k) , il residuo r (k) =<br />

b − Ax (k) e l’errore e (k) = x − x (k) . Osserviamo che si ha la relazione r (k) = Ae (k) . Infatti<br />

Ae (k) = A(x − x (k) ) = Ax − Ax (k) = b − Ax (k) = r (k)<br />

Lo schema converge quando la successione x (k) converge alla soluzione x per k → ∞, ovvero quando<br />

lim k→∞ e (k) = 0 qualunque sia il vettore iniziale x (0) .<br />

Consideriamo lo schema iterativo x (k+1) = Ex (k) + q.<br />

È facile vedere che per la soluzione esatta x vale la relazione x = Ex + q.<br />

Consideriamo x − x (k) . Si ha<br />

x = Ex + q<br />

x (k) = Ex k−1 + q<br />

e sottraendo si ricava<br />

e (k) = Ee (k−1)<br />

La relazione appena trovata vale, alla stessa maniera, tra l’errore e (k−1) e l’errore e (k−2) per cui possiamo<br />

scrivere e (k−1) = Ee (k−2) .<br />

Scriviamo queste relazioni dall’iterazione k fino ad arrivare all’iterazione 0.<br />

110


8.6. Meto<strong>di</strong> classici<br />

e (k) = Ee (k−1)<br />

e (k−1) = Ee (k−2)<br />

e (k−2) = Ee (k−3)<br />

. = . . .<br />

e (2) = Ee (1)<br />

e (1) = Ee (0)<br />

Partendo, ora, dalla prima relazione e, andando a sostituire, ogni volta, a secondo membro, la relazione<br />

successiva, si ha:<br />

e (k) = Ee (k−1) = E(Ee (k−2) ) = E 2 e (k−2) = E 2 (Ee (k−3) ) = E 3 e (k−3) = ... = E k e (0)<br />

Osserviamo che E k rappresenta la potenza k della matrice E, cioè la E · E ···E k volte.<br />

Il metodo converge se e (k) → 0 per k → ∞. Poichè l’errore iniziale è arbitrario, si ha che lim k→∞ e (k) =<br />

lim k→∞ E k e (0) = 0 se e solo se lim k→∞ E k = 0.<br />

Per il teorema sulla convergenza <strong>di</strong> matrici (si veda pag. 109), questo si ha se e solo se ρ(E) < 1. Si può<br />

dunque stabilire il seguente teorema.<br />

Teorema 8.6.1 Lo schema iterativo<br />

x (k+1) = Ex (k) + q k ≥ 0<br />

converge qualunque sia il vettore iniziale x 0 al vettore x = Ex + q = A −1 b se e solo se ρ(E) < 1.<br />

Questo risultato lo si può provare facilmente, nel caso in cui la matrice <strong>di</strong> iterazione E abbia n autovalori<br />

<strong>di</strong>stinti e, quin<strong>di</strong>, possieda n autovettori linearmente in<strong>di</strong>pendenti, per cui l’errore iniziale e (0) si può scrivere<br />

come e (0) = α 1 u (1) + α 2 u (2) + ... + α n u (n) , dove α 1 ,α 2 ,...,α n sono delle costanti, mentre u (1) , u (2) ...u (n) sono<br />

gli autovettori associati, rispettivamente, a λ 1 , λ 2 ,...,λ n . Supponiamo che gli autovalori siano in or<strong>di</strong>ne decrescente<br />

in modulo, cioè: |λ 1 | > |λ 2 | > ... > |λ n |, per cui ρ(E) = |λ 1 |. In tal caso si può scrivere (ricordando<br />

che, se λ è un autovalore associato alla matrice A, con u un autovettore ad esso associato, si ha A k u = λ k u)<br />

e (k) = E k e (0) = E k (α 1 u (1) + α 2 u (2) + ... + α n u (n) )<br />

= α 1 E k u (1) + α 2 E k u (2) + ... + α n E k u (n)<br />

= α 1 λ k 1 u(1) + α 2 λ k 2 u(2) + ... + α n λ k n u(n)<br />

mettiamo in evidenza λ k 1<br />

(<br />

= λ k 1<br />

α 1 u (1) + α 2<br />

λ k 2<br />

λ k 1<br />

)<br />

u (2) λ k n<br />

+ ... + α n<br />

λ k u (n)<br />

1<br />

per k → ∞ si ha λk i<br />

λ k → 0 per i = 2,3,...,n<br />

1<br />

≈ λ k 1 α 1u (1)<br />

Perciò lim k→∞ e (k) = lim k→∞ λ k 1 α 1u (1) = 0 se e solo se λ k 1 → 0 e questo si ha se e solo se |λ 1| < 1. Ma |λ 1 | = ρ(E):<br />

ritroviamo il risultato visto prima.<br />

8.6.2 Controllo della convergenza<br />

Oltre a sapere che lo schema iterativo converge, è importante conoscere quanto velocemente lo schema<br />

converge. A tal proposito osserviamo che, in con<strong>di</strong>zioni asintotiche (per k → +∞) vale il seguente risultato 2<br />

‖e (k) ‖ ≈ ρ(E) k ‖e (0) ‖ (8.1)<br />

2 Questa relazione vale anche per matrici con autovalori non <strong>di</strong>stinti tra loro.<br />

111


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Scrivendo l’equazione (8.1) per l’iterazione k − 1 e facendo il rapporto tra le norme <strong>degli</strong> errori a due passi<br />

successivi si ha:<br />

‖e (k) ‖<br />

‖e (k−1) ‖ ≈ ρ(E)<br />

Ricaviamo, quin<strong>di</strong>, che il metodo iterativo ha convergenza lineare con costante asintotica uguale al raggio<br />

spettrale della matrice <strong>di</strong> iterazione.<br />

La relazione appena trovata è utile per stabilire quanto veloce è il metodo iterativo per approssimare la<br />

soluzione del sistema con una certa accuratezza. Ad esempio, vogliamo stabilire a priori quante iterazioni<br />

occorrono per ridurre la norma dell’errore iniziale <strong>di</strong> un certo fattore, ad esempio 10 (il che vuol <strong>di</strong>re ridurre<br />

l’errore <strong>di</strong> un or<strong>di</strong>ne <strong>di</strong> grandezza). Vogliamo dunque capire quale deve essere il valore <strong>di</strong> k per cui ‖e (k) ‖ =<br />

‖e (0) ‖<br />

10 . Ma ‖e(k) ‖ ≈ ρ(E) k ‖e (0) ‖ da cui<br />

ρ(E) k ‖e (0) ‖ ≈ ‖e(0) ‖<br />

10 =⇒ ρ(E)k ≈ 1<br />

10<br />

Applicando il logaritmo in base 10 ad ambo i membri si ha<br />

1<br />

k log 10 (ρ(E)) ≈ −1 =⇒ k ≈ −<br />

log 10 (ρ(E))<br />

Velocità<br />

asintotica <strong>di</strong><br />

convergenza<br />

cioè occorrono k iterazioni con k dato dal più piccolo intero che sod<strong>di</strong>sfa la relazione appena scritta. Meno<br />

iterazioni occorrono fare, più veloce è il metodo.<br />

Si definisce perciò velocità asintotica <strong>di</strong> convergenza<br />

R = −log 10 (ρ(E)) = −log 10 (ρ(E k ))<br />

k<br />

Osserviamo che, essendo ρ(E) < 1, nelle ipotesi in cui il metodo converge, log 10 (ρ(E)) < 0 e, <strong>di</strong> conseguenza,<br />

R > 0. Se vogliamo ridurre l’errore iniziale <strong>di</strong> una certa quantità ɛ, rifacendo i conti come prima, da una parte<br />

vogliamo che sia ‖e (k) ‖ ≤ ɛ‖e (0) ‖, dall’altra sappiamo che ‖e (k) ‖ ≈ ρ(E) k ‖e (0) ‖. Uguagliando i termini abbiamo<br />

ρ(E) k ‖e (0) ‖ ≤ ɛ‖e (0) ‖ =⇒ ρ(E) k ≤ ɛ<br />

Passando ai logaritmi (<strong>di</strong> quantità minori <strong>di</strong> uno) si ha<br />

k log 10 (ρ(E)) ≤ log 10 (ɛ) =⇒ −k log 10 (ρ(E)) ≥ −log 10 (ɛ) =⇒ k ≥ −log 10 (ɛ)<br />

R<br />

Troviamo in questo modo quante iterazioni (il primo intero k che verifica la relazione precedente) occorre<br />

fare per poter ridurre l’errore iniziale <strong>di</strong> ɛ.<br />

Se si traccia un grafico semilogaritmico del profilo <strong>di</strong> convergenza dello schema iterativo, ponendo sull’asse<br />

delle ascisse il numero delle iterazioni e sull’asse delle or<strong>di</strong>nate la norma dell’errore, si può vedere che<br />

la velocità asintotica <strong>di</strong> convergenza è legata alla pendenza della retta. Infatti, riconducendoci, per semplicità,<br />

al caso in cui la matrice <strong>di</strong> iterazione abbia n autovalori <strong>di</strong>stinti tra loro e or<strong>di</strong>nati in senso crescente, dalla<br />

relazione (vista a pag. 111)<br />

e (k) ≈ λ k 1 α 1u (1)<br />

passando alle norme e ai logaritmi in base 10 si ha<br />

log 10 ‖e (k) ‖ ≈ k log 10 |λ 1 | + costante<br />

La pendenza del grafico è l’opposto della velocità asintotica <strong>di</strong> convergenza R.<br />

Nel caso in cui non è nota la soluzione esatta x, poichè ‖e (k) ‖ ≈ ‖x (k) − x (k−1) ‖ = ‖d (k) ‖ (valgono le stesse<br />

considerazioni viste per gli schemi iterativi per funzioni non lineari a pag. 53), ritroviamo lo stesso risultato<br />

sul profilo <strong>di</strong> convergenza semilogaritmico in cui si pone sull’asse delle ascisse il numero delle iterazioni e<br />

sull’asse delle or<strong>di</strong>nate la norma <strong>degli</strong> scarti.<br />

112


8.6. Meto<strong>di</strong> classici<br />

Figura 8.3: La matrice A come somma delle matrici L, D e U .<br />

8.6.3 I meto<strong>di</strong><br />

Si scriva la matrice A come somma della matrice che ha i soli elementi <strong>di</strong>agonali <strong>di</strong> A (che chiamiamo<br />

D), della matrice costituita dai soli elementi della parte triangolare bassa <strong>di</strong> A (che chiamiamo L) e dai soli<br />

elementi della parte triangolare alta <strong>di</strong> A (che denotiamo con U ),<br />

A = L + D +U<br />

In questo modo è facile ricavare i meto<strong>di</strong> iterativi <strong>di</strong> Jacobi, Gauss-Seidel e <strong>di</strong> rilassamento, che sono i meto<strong>di</strong><br />

iterativi classici per la soluzione <strong>di</strong> sistemi lineari.<br />

L’ipotesi da fare è che A abbia elementi <strong>di</strong>agonali <strong>di</strong>versi da zero (a i i ≠ 0 per i = 1,2,...,n,n, da cui la<br />

matrice <strong>di</strong>agonale D è invertibile).<br />

Se la matrice A è simmetrica, definita positiva, necessariamente a i i ≠ 0. Altrimenti, poichè A è non singolare<br />

(se così non fosse non potremmo risolvere il sistema), le equazioni del sistema possono essere rior<strong>di</strong>nate<br />

in modo da avere la matrice risultante con elementi <strong>di</strong>agonali <strong>di</strong>versi da zero.<br />

Il metodo <strong>di</strong> Jacobi<br />

Il metodo <strong>di</strong> Jacobi 3 (o <strong>degli</strong> spostamenti simultanei - o rilassamento simultaneo) si ha ponendo M = D<br />

da cui la matrice <strong>di</strong> iterazione <strong>di</strong>venta E J = I − D −1 A = I − D −1 (L + D +U ) = −D −1 (L +U ).<br />

Scrivendo lo schema iterativo per Jacobi, si ha, in forma matriciale:<br />

x (k+1) = E J x (k) + D −1 b<br />

x (k+1) = −D −1 (L +U )x (k) + D −1 b<br />

Per ricavare questo schema, si può partire dal sistema lineare Ax = b e scrivere la matrice A come L+D+U .<br />

Si ha<br />

(L + D +U )x = b<br />

si porta a secondo membro (L +U )x<br />

Dx = −(L +U )x + b<br />

si moltiplicano ambo i membri per l’inversa della matrice D<br />

x = −D −1 (L +U )x + D −1 b<br />

si innesca il metodo iterativo considerando il vettore x a primo membro dell’equazione<br />

all’iterazione k + 1 e quello a destra all’iterazione k<br />

x (k+1) = −D −1 (L +U )x (k) + D −1 b<br />

3 Carl Gustav Jacob Jacobi (1804-1851) fu un grande matematico tedesco. Tra i suoi numerosi stu<strong>di</strong> ricor<strong>di</strong>amo quelli sulle funzioni<br />

ellittiche, sulla teoria dei numeri e sulla meccanica celeste.<br />

113


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Componente per componente, il metodo <strong>di</strong> Jacobi si scrive, per i = 1,2,...,n, come<br />

⎡<br />

⎤<br />

x (k+1)<br />

i<br />

=<br />

(D −1 ) i i<br />

1<br />

a i i<br />

⇑<br />

o, equivalentemente,<br />

⎢<br />

⎣ b i −<br />

((L+U )x (k) ) i<br />

n∑<br />

j =1,j ≠i<br />

⇑<br />

a i j x (k)<br />

⎥<br />

j ⎦<br />

x (k+1)<br />

i<br />

=<br />

(D −1 ) i i<br />

1<br />

a i i<br />

⇑<br />

⎡<br />

⎢<br />

⎣ b i −<br />

(Lx (k) ) i<br />

i−1<br />

∑<br />

j =1<br />

a i j x (k)<br />

j<br />

⇑<br />

−<br />

n∑<br />

(U x (k) ) i<br />

j =i+1<br />

⇑<br />

⎤<br />

a i j x (k)<br />

⎥<br />

j ⎦<br />

per i = 1,...,n<br />

La formula la si può ricavare <strong>di</strong>rettamente, scrivendo, equazione per equazione, il sistema da risolvere<br />

Ax = b:<br />

a 11 x 1 + a 12 x 2 + a 13 x 3 + ... + a 1n x n = b 1<br />

a 21 x 1 + a 22 x 2 + a 23 x 3 + ... + a 2n x n = b 2<br />

. = . . .<br />

a i 1 x 1 + a i 2 x 2 + a i 3 x 3 + ... + a i n x n = b i<br />

. = . . .<br />

a n1 x 1 + a n2 x 2 + a n3 x 3 + ... + a nn x n = b n<br />

Dalla prima equazione “isoliamo” la prima incognita rispetto a tutte le altre; dalla seconda equazione<br />

“isoliamo” la seconda incognita e così via per le altre equazioni, ottenendo:<br />

a 11 x 1 = b 1 − (a 12 x 2 + a 13 x 3 + ... + a 1n x n )<br />

a 22 x 2 = b 2 − (a 21 x 1 + a 23 x 3 + ... + a 2n x n )<br />

. =<br />

.<br />

a i i x i = b i − (a i 1 x 1 + a i 2 x 2 + ... + a i i−1 x i−1 + a i i+1 x i+1 + ... + a i n x n )<br />

. =<br />

.<br />

a nn x n = b n − (a n1 x 1 + a n2 x 2 + a n3 x 3 + ... + a nn−1 x n−1 )<br />

Dividendo l’i -sima equazione per il coefficiente a i i , per i = 1,2,...,n, ricaviamo<br />

114<br />

x 1 = 1<br />

a 11<br />

[b 1 − (a 12 x 2 + a 13 x 3 + ... + a 1n x n )]<br />

x 2 = 1<br />

a 22<br />

[b 2 − (a 21 x 1 + a 23 x 3 + ... + a 2n x n )]<br />

. =<br />

.<br />

x i = 1<br />

a i i<br />

[b i − (a i 1 x 1 + a i 2 x 2 + ... + a i i−1 x i−1 + a i i+1 x i+1 + ... + a i n x n )]<br />

. =<br />

.<br />

x n = 1<br />

a nn<br />

[b n − (a n1 x 1 + a n2 x 2 + a n3 x 3 + ... + a nn−1 x n−1 )]


8.6. Meto<strong>di</strong> classici<br />

Se pensiamo <strong>di</strong> partire da un vettore inziale x (0) , il vettore x (1) si ottiene dalle equazioni precedenti, ponendo<br />

a secondo membro <strong>di</strong> ciascuna equazione le componenti del vettore x (0) . Si ricava, in tal modo, la<br />

formula ricorsiva dello schema <strong>di</strong> Jacobi:<br />

x (k+1)<br />

1<br />

= 1 [ (<br />

)]<br />

b 1 − a 12 x (k)<br />

2<br />

+ a 13 x (k)<br />

3<br />

+ ... + a 1n x n<br />

(k)<br />

a 11<br />

)]<br />

x (k+1)<br />

2<br />

= 1<br />

a 22<br />

[<br />

b 2 −<br />

. =<br />

x (k+1)<br />

i<br />

= 1<br />

a i i<br />

[<br />

b i −<br />

. =<br />

x (k+1)<br />

n = 1<br />

a nn<br />

[<br />

b n −<br />

(<br />

a 21 x (k)<br />

1<br />

+ a 23 x (k)<br />

3<br />

+ ... + a 2n x n<br />

(k)<br />

.<br />

(<br />

a i 1 x (k)<br />

1<br />

+ a i 2 x (k)<br />

2<br />

+ ... + a i i−1 x (k)<br />

i−1 + a i i+1x (k)<br />

i+1 + ... + a i n x n<br />

(k)<br />

.<br />

(<br />

a n1 x (k)<br />

1<br />

+ a n2 x (k)<br />

2<br />

+ a n3 x (k)<br />

3<br />

+ ... + a nn−1 x (k)<br />

n−1<br />

Ritroviamo, dunque, la formula scritta prima in forma compatta.<br />

La formula in funzione del residuo r (k) = b − Ax (k) è data invece da x (k+1) = x (k) + D −1 r (k) .<br />

)]<br />

)]<br />

Il Metodo <strong>di</strong> Gauss-Seidel<br />

Nell’algoritmo <strong>di</strong> Gauss-Seidel 4 si pone M = D + L ottenendo la matrice E S = I − (D + L) −1 A = I − (D +<br />

L) −1 (L + D +U ) = −(D + L) −1 U . Lo schema iterativo è:<br />

x (k+1) = E S x (k) + (D + L) −1 b<br />

Lo schema <strong>di</strong> Gauss-Seidel si può ricavare a partire dal sistema lineare Ax = b nel modo seguente:<br />

Ax = b<br />

(L + D +U )x = b<br />

si porta a secondo membro U x<br />

(D + L)x = −U x + b<br />

si moltiplicano ambo i membri per l’inversa della matrice (D + L)<br />

x = −(D + L) −1 U x + (D + L) −1 b<br />

si innesca il metodo iterativo considerando il vettore x a primo membro dell’equazione<br />

all’iterazione k + 1 e quello a destra all’iterazione k<br />

x (k+1) = −(D + L) −1 U x (k) + (D + L) −1 b<br />

Moltiplicando ambo i membri per (D + L) si ha<br />

da cui<br />

(D + L)x (k+1) = b −U x (k)<br />

Dx (k+1) = b − Lx (k+1) −U x (k)<br />

x (k+1) = D −1 ( b − Lx (k+1) −U x (k))<br />

Componente per componente si ha<br />

4 Philipp Ludwig von Seidel (1821-1896) fu un matematico tedesco. Il suo lavoro più importante riguarda le aberrazioni ottiche.<br />

115


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

[<br />

x (k+1) = 1<br />

i<br />

a i i<br />

i−1 ∑<br />

b i −<br />

j =1<br />

a i j x (k+1)<br />

j<br />

−<br />

n∑<br />

j =i+1<br />

a i j x (k)<br />

j<br />

]<br />

per i = 1,...,n<br />

Il metodo è detto anche <strong>degli</strong> spostamenti successivi, in quanto il calcolo delle componenti del vettore<br />

x (k+1) è fatto utilizzando le componenti già calcolate del vettore stesso. Infatti, per i > 1, è ragionevole pensare<br />

che i valori già calcolati x (k+1)<br />

1<br />

, x (k+1)<br />

2<br />

,..., x (k+1) possano essere utilizzati per dare una migliore approssimazione<br />

del valore x (k+1) . Dalle equazioni del sistema, ragionando come per il metodo <strong>di</strong> Jacobi, possiamo quin<strong>di</strong><br />

i−1<br />

i<br />

scrivere:<br />

(<br />

)<br />

a 11 x (k+1)<br />

1<br />

= b 1 − a 12 x (k)<br />

2<br />

+ a 13 x (k)<br />

3<br />

+ ... + a 1n x n<br />

(k)<br />

(<br />

)<br />

a 22 x (k+1)<br />

2<br />

= b 2 − a 21 x (k+1)<br />

1<br />

+ a 23 x (k)<br />

3<br />

+ ... + a 2n x n<br />

(k)<br />

. =<br />

a i i x (k+1) = b<br />

i<br />

i −<br />

. =<br />

a nn x n<br />

(k+1) = b n −<br />

.<br />

(<br />

a i 1 x (k+1)<br />

1<br />

+ a i 2 x (k+1)<br />

.<br />

2<br />

+ ... + a i i−1 x (k+1)<br />

i−1<br />

)<br />

+ a i i+1 x (k)<br />

i+1 + ... + a i n x n<br />

(k)<br />

(<br />

a n1 x (k+1)<br />

1<br />

+ a n2 x (k+1)<br />

2<br />

+ a n3 x (k+1)<br />

3<br />

+ ... + a nn−1 x (k+1)<br />

n−1<br />

Dividendo ambo i membri dell’equazione i -sima per a i i (per i = 1,2,...,n) si ha:<br />

x (k+1)<br />

1<br />

= 1 [ (<br />

)]<br />

b 1 − a 12 x (k)<br />

2<br />

+ a 13 x (k)<br />

3<br />

+ ... + a 1n x n<br />

(k)<br />

a 11<br />

x (k+1)<br />

2<br />

= 1<br />

a 22<br />

[<br />

b 2 −<br />

. =<br />

x (k+1)<br />

i<br />

= 1<br />

a i i<br />

[<br />

b i −<br />

. =<br />

x (k+1)<br />

n = 1<br />

a nn<br />

[<br />

b n −<br />

(<br />

a 21 x (k+1)<br />

1<br />

+ a 23 x (k)<br />

3<br />

+ ... + a 2n x n<br />

(k)<br />

.<br />

(<br />

a i 1 x (k+1)<br />

1<br />

+ a i 2 x (k+1)<br />

.<br />

)]<br />

2<br />

+ ... a i i−1 x (k+1)<br />

i−1<br />

)]<br />

+ a i i+1 x (k)<br />

i+1 + ... + a i n x n<br />

(k)<br />

(<br />

a n1 x (k+1)<br />

1<br />

+ a n2 x (k+1)<br />

2<br />

+ a n3 x (k+1)<br />

3<br />

+ ... + a nn−1 x (k+1)<br />

n−1<br />

Usando il residuo, lo schema <strong>di</strong> Gauss-Seidel si scrive come<br />

x (k+1) = x (k) + (D + L) −1 r (k)<br />

)<br />

)]<br />

Il metodo <strong>di</strong> rilassamento<br />

Ciascuno dei meto<strong>di</strong> <strong>di</strong> Jacobi e Gauss-Seidel può essere anche rilassato tramite un fattore ω in modo che<br />

la nuova approssimazione x (k+1) sia ottenuta come una combinazione <strong>di</strong> x (k+1) e x (k) me<strong>di</strong>ante il fattore ω. In<br />

pratica:<br />

x (k+1) ←− (1 − ω)x (k) + ωx (k+1)<br />

Questa operazione viene fatta <strong>di</strong>rettamente nel momento in cui si stabilisce il metodo iterativo con<br />

rilassamento.<br />

Si può osservare che il metodo <strong>di</strong> Jacobi rilassato non produce effettivi miglioramenti rispetto al metodo<br />

non rilassato. Invece, il metodo <strong>di</strong> Gauss-Seidel rilassato può produrre un metodo molto più veloce in termini<br />

116


8.6. Meto<strong>di</strong> classici<br />

<strong>di</strong> convergenza e, quin<strong>di</strong>, preferibile rispetto al metodo senza rilassamento. Come metodo <strong>di</strong> rilassamento,<br />

dunque, consideriamo il metodo <strong>di</strong> rilassamento ottenuto da Gauss-Seidel. Per scelte <strong>di</strong> ω nell’intervallo<br />

]0,1[ si parla <strong>di</strong> metodo Sotto-Rilassato, o Under-Relaxation (e in genere è usato per ottenere convergenza<br />

nella soluzione <strong>di</strong> sistemi che non convergono con il metodo <strong>di</strong> Gauss-Seidel). Per valori <strong>di</strong> ω nell’intervallo<br />

[1,2[ si ha, invece, il metodo noto come metodo <strong>di</strong> sovra-rilassamento o SOR (Successive Over-Relaxation) –<br />

usato per accelerare la convergenza in sistemi che sono convergenti con il metodo <strong>di</strong> Gauss-Seidel.<br />

Lo schema <strong>di</strong> rilassamento, applicato al metodo <strong>di</strong> Gauss-Seidel, è dato da<br />

x (k+1) = (1 − ω)x (k)<br />

i<br />

+ ω i−1 ∑<br />

[b<br />

i i −<br />

a i i<br />

j =1<br />

a i j x (k+1)<br />

j<br />

−<br />

n∑<br />

j =i+1<br />

a i j x (k)<br />

j<br />

]<br />

per i = 1,...,n<br />

La matrice <strong>di</strong> iterazione del metodo <strong>di</strong> rilassamento si ricava scrivendo in forma matriciale l’algoritmo<br />

appena descritto<br />

x (k+1) = (1 − ω)x (k) + ωD −1 ( b − Lx (k+1) −U x (k))<br />

x (k+1) = [ (1 − ω)I − ωD −1 U ] x (k) − ωD −1 Lx (k+1) + ωD −1 b<br />

(I + ωD −1 L)x (k+1) = [ (1 − ω)I − ωD −1 U ] x (k) + ωD −1 b<br />

Moltiplicando ambo i membri per D, si ricava<br />

La matrice <strong>di</strong> iterazione del metodo è dunque<br />

E = (D + ωL) −1 [(1 − ω)D − ωU ]<br />

= (D + ωL) −1 [(1 − ω)D − ω(A − D − L)]<br />

= (D + ωL) −1 [(D + ωL) − ωA]<br />

= [ I − ω(D + ωL) −1 A ]<br />

(D + ωL)x (k+1) = [(1 − ω)D − ωU ] x (k) + ωb<br />

A questo punto, ci si può chiedere quale sia l’ω ottimale nel metodo <strong>di</strong> rilassamento. L’ω ottimale è quello<br />

che fa sì che il metodo <strong>di</strong> rilassamento converga nel minor numero <strong>di</strong> iterazioni (quin<strong>di</strong>, l’ω ottimale rende<br />

minimo il raggio spettrale della matrice <strong>di</strong> iterazione). Vedremo, per particolari matrici A, quando è possibile<br />

stabilire a priori quale sia l’ω ottimale per risolvere il sistema lineare Ax = b.<br />

8.6.4 Convergenza dei meto<strong>di</strong> <strong>di</strong> Jacobi, Gauss-Seidel, rilassamento<br />

Le matrici <strong>di</strong> iterazione dei tre meto<strong>di</strong> appena descritti sono scritte in Tabella 8.6.4 Perchè ci sia<br />

metodo matrice<br />

Jacobi E J = I − D −1 A = −D −1 (L +U )<br />

Gauss-Seidel E S = I − (D + L) −1 A = −(D + L) −1 U<br />

rilassamento E ω = I − ω(D + ωL) −1 A<br />

Tabella 8.1: Matrici <strong>di</strong> iterazione dei meto<strong>di</strong> <strong>di</strong> Jacobi, Gauss-Seidel, rilassamento<br />

convergenza, il raggio spettrale della matrice <strong>di</strong> iterazione deve essere minore <strong>di</strong> uno.<br />

Per i meto<strong>di</strong> <strong>di</strong> Jacobi e <strong>di</strong> Gauss-Seidel si può provare la convergenza del metodo, se la matrice A ha una<br />

delle seguenti caratteristiche:<br />

G A è <strong>di</strong>agonalmente dominante in senso stretto<br />

117


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

G A è a <strong>di</strong>agonalmente dominante (per righe o per colonne) ed è irriducibile 5 .<br />

Si ha inoltre, questo risultato:<br />

G se A è simmetrica non singolare con elementi principali reali e positivi, allora il metodo <strong>di</strong> Gauss-Seidel<br />

è convergente se e solo se A è definita positiva.<br />

Per quanto riguarda il metodo <strong>di</strong> rilassamento, con<strong>di</strong>zione necessaria per la convergenza è |ω − 1| < 1, cioè<br />

ω deve appartenere all’intervallo [0,2] ( per 0 < ω < 1 si ha sotto-rilassamento e per 1 ≤ ω < 2 si ha sovrarilassamento).<br />

Difatti il determinante della matrice <strong>di</strong> iterazione del metodo <strong>di</strong> rilassamento vale 6 detE ω = (1 − ω) n e,<br />

poichè il prodotto <strong>degli</strong> autovalori <strong>di</strong> una matrice è uguale al determinante della matrice stessa, segue 7 la<br />

relazione ρ(E ω ) ≥ |1 − ω|. Quin<strong>di</strong>, se |1 − ω| > 1, sicuramente il metodo <strong>di</strong> rilassamento non convergerà.<br />

Perciò, con<strong>di</strong>zione necessaria per la convergenza è |1 − ω| < 1.<br />

Si ha questo importante teorema.<br />

Teorema 8.6.2 (Ostrowski-Reich) Se A è definita positiva e ω è un numero reale nell’intervallo ]0,2[, allora il<br />

metodo <strong>di</strong> rilassamento è convergente.<br />

G La convergenza del metodo <strong>di</strong> rilassamento si ha, inoltre, per A simmetrica con elementi <strong>di</strong>agonali<br />

positivi ed elementi extra-<strong>di</strong>agonali negativi o nulli, se e solo se A è definita positiva.<br />

Un altro interessante teorema mette in relazione il metodo <strong>di</strong> rilassamento con i meto<strong>di</strong> <strong>di</strong> Jacobi e <strong>di</strong> Gauss-<br />

Seidel, sia per quanto riguarda la convergenza, sia per quanto riguarda il valore ottimale del parametro ω, in<br />

corrispondenza <strong>di</strong> matrici A che godono della cosidetta proprietà A e che siano coerentemente or<strong>di</strong>nate.<br />

Definizione 8.6.1 Una matrice A, <strong>di</strong> <strong>di</strong>mensione n, si <strong>di</strong>ce che ha proprietà A se esiste una matrice <strong>di</strong><br />

permutazione P tale che la matrice PAP T abbia la forma<br />

( )<br />

PAP T D1 A 1<br />

=<br />

A 2 D 2<br />

dove D 1 e D 2 sono matrici <strong>di</strong>agonali.<br />

Una matrice con proprietà A si <strong>di</strong>ce biciclica.<br />

Equivalentemente, una matrice A, <strong>di</strong> <strong>di</strong>mensione n, ha proprietà A se l’insieme dei numeri naturali<br />

{1,2,...,n} può essere scomposto in due sottoinsiemi non vuoti e complementari 8 S e T in modo tale che<br />

( )<br />

5 P Q<br />

cioè non può essere messa sotto la forma<br />

R<br />

6 Dalla definizione <strong>di</strong> E ω si ha detE ω = det[(D + ωL) −1 ((1 − ω)D − ωU )]. Poichè il determinante del prodotto <strong>di</strong> due matrici è uguale<br />

al prodotto dei determinanti delle matrici stesse, si ha detE ω = det[(D + ωL) −1 ]det[(1 − ω)D − ωU )] = detD −1 (1 − ω) n detD. Si arriva<br />

a questo risultato, tenendo presente il fatto che il determinante <strong>di</strong> una matrice triangolare è uguale al prodotto <strong>degli</strong> elementi della<br />

<strong>di</strong>agonale principale.<br />

7 Infatti, considerando λ i autovalore della matrice E ω , per i = 1,2,...,n e ρ(E ω ) il raggio spettrale, si ha detE ω = ∏ n<br />

i=1 λ i ≤<br />

∏ n<br />

i=1 ρ(E ω) = ρ(E ω ) n da cui segue (1 − ω) n ≤ ρ(E ω ) n , cioè ρ(E ω ) ≥ |1 − ω|.<br />

8 Due insiemi S e T non vuoti si <strong>di</strong>cono complementari <strong>di</strong> V = {1,2,...,n} se S ≠ , T ≠ , S ∪ T = V e, inoltre, se i ∈ S,i ∉ T e,<br />

viceversa, se j ∈ T, j ∉ S<br />

118


8.6. Meto<strong>di</strong> classici<br />

i coefficienti non nulli a i j ≠ 0 si hanno per i = j oppure per i ∈ S e j ∈ T oppure per i ∈ T e j ∈ S.<br />

Esempio 8.6.1 La matrice tri<strong>di</strong>agonale<br />

⎛<br />

⎞<br />

2 −1 0 0<br />

A = ⎜−1 2 −1 0<br />

⎟<br />

⎝ 0 −1 2 −1⎠<br />

0 0 −1 2<br />

ha proprietà A (o è biciclica): permutando la prima e quarta riga e la prima e quarta colonna, me<strong>di</strong>ante la<br />

⎛<br />

⎞<br />

0 0 0 1<br />

matrice <strong>di</strong> permutazione P = ⎜0 1 0 0<br />

⎟<br />

⎝0 0 1 0⎠ si ha<br />

1 0 0 0<br />

⎛<br />

⎞<br />

2 0 −1 0<br />

( )<br />

PAP T = ⎜ 0 2 −1 −1<br />

⎟<br />

2 0<br />

⎝−1 −1 2 0 ⎠ =⇒ D 1 = D 2 =<br />

0 2<br />

0 −1 0 2<br />

Possiamo scegliere S = {1,3} e T = {2,4}.<br />

Definizione 8.6.2 Una matrice si <strong>di</strong>ce coerentemente or<strong>di</strong>nata in relazione ad un vettore <strong>di</strong> or<strong>di</strong>namento q, <strong>di</strong><br />

lunghezza n, se per ogni coefficiente a i j non nullo, con i ≠ j , si verifica:<br />

G se j > i allora q j − q i = 1<br />

G se j < i allora q j − q i = −1<br />

Un’altra definizione <strong>di</strong> matrice con coerente or<strong>di</strong>namento considera la matrice A data non dalla scomposizione<br />

A = L + D +U che abbiamo visto fino ad ora ma come A = D(L A + I +U A ), (osserviamo che, rispetto<br />

alla prima scomposizione, abbiamo messo in evidenza la matrice <strong>di</strong>agonale D e quin<strong>di</strong> le matrici triangolari<br />

superiore e inferiore sono L A = D −1 L e U A = D −1 U ). Sia D non singolare. Allora la matrice A è detta<br />

coerentemente or<strong>di</strong>nata se gli autovalori della matrice J(α) = αL A + α −1 U A , con α ≠ 0 sono in<strong>di</strong>pendenti dal<br />

parametro α.<br />

( )<br />

D1 A 1<br />

Le matrici con proprietà A (o bicicliche) nella forma A =<br />

(P = I nella definizione <strong>di</strong> proprietà<br />

A 2 D 2<br />

A) sono coerentemente or<strong>di</strong>nate.<br />

Le matrici tri<strong>di</strong>agonali sono un esempio <strong>di</strong> matrici bicicliche e coerentemente or<strong>di</strong>nate.<br />

Per il metodo <strong>di</strong> rilassamento si può provare il seguente risultato.<br />

Teorema 8.6.3 (Young) Se A è una matrice con proprietà A e coerente or<strong>di</strong>namento e 0 < ω < 2, allora:<br />

G se µ è autovalore della matrice <strong>di</strong> iterazione <strong>di</strong> Jacobi E J , ogni λ che verifica la relazione (λ + ω − 1) 2 =<br />

λω 2 µ 2 è autovalore <strong>di</strong> E ω ;<br />

G se λ è autovalore non nullo <strong>di</strong> E ω , allora ogni µ che verifica la relazione precedente è autovalore <strong>di</strong> E J ;<br />

G se gli autovalori <strong>di</strong> E J sono reali e il metodo <strong>di</strong> Jacobi converge (ρ(E J ) < 1), esiste uno ed uno solo ω opt<br />

che rende ottimale il metodo <strong>di</strong> rilassamento, tale cioè che ρ(ω opt ) = min 0


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

8.7 <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 8.7.1<br />

⎛<br />

Sia dato<br />

⎞<br />

il sistema<br />

⎛ ⎞<br />

lineare Ax = b, dove<br />

8 2 6 30<br />

A = ⎝7 5 0⎠ b = ⎝34⎠<br />

1 0 5 7<br />

(a) Provare che gli schemi <strong>di</strong> Jacobi e <strong>di</strong> Seidel convergono e calcolare la velocità asintontica <strong>di</strong><br />

convergenza <strong>di</strong> entrambi gli schemi.<br />

(b) A partire dallo stesso vettore iniziale x (0) = (0 0 0) T , calcolare le approssimazioni x (1) e x (2) che si<br />

ottengono applicando lo schema <strong>di</strong> Jacobi e lo schema <strong>di</strong> Seidel.<br />

Svolgimento<br />

(a) La matrice A non è <strong>di</strong>agonalmente dominante nè per righe nè per colonne (vedasi la seconda riga e<br />

la terza colonna). Non possiamo usare il criterio <strong>di</strong> matrice <strong>di</strong>agonalmente dominante per provare la<br />

convergenza dei due meto<strong>di</strong>. La matrice<br />

( )<br />

A è biciclica e coerentemente or<strong>di</strong>nata (si veda lo schema a<br />

5 0<br />

croce che in<strong>di</strong>vidua D 1 = (8) e D 2 = ):<br />

0 5<br />

8 2 6<br />

7 5 0<br />

1 0 5<br />

Quin<strong>di</strong> se proviamo che lo schema <strong>di</strong> Jacobi converge, cioè che l’autovalore <strong>di</strong> massimo modulo della<br />

matrice <strong>di</strong> Jacobi è reale e in modulo minore <strong>di</strong> 1, allora, poichè per matrici bicicliche e coerentemente<br />

or<strong>di</strong>nate vale ρ(E J ) 2 = ρ(E S ), allora anche il metodo <strong>di</strong> Gauss-Seidel convergerà alla soluzione (da<br />

ρ(E J ) < 1 segue ρ(E S ) < 1). La matrice <strong>di</strong> Jacobi è E J = I − D −1 A cioè<br />

⎛<br />

0 −2/8<br />

⎞<br />

−6/8<br />

⎛<br />

0 −1/4<br />

⎞<br />

−3/4<br />

E J = ⎝−7/5 0 0 ⎠ = ⎝−7/5 0 0 ⎠<br />

−1/5 0 0 −1/5 0 0<br />

Troviamo gli autovalori della matrice E J imponendo det(E J − µI ) = 0.<br />

−µ −1/4 −3/4<br />

−7/5 −µ 0<br />

∣−1/5 0 −µ ∣ = −µ3 + 3 4 · 1<br />

5 µ + 1 4 · 7<br />

5 µ = 0<br />

Si ha: 0 = det(E J − µI ) = −µ 3 + ( 3<br />

20 + 7<br />

20 )µ,<br />

Una ra<strong>di</strong>ce è µ = 0, e le altre due sono µ = ± 1/2 = ± 0.5 = 0.707106781.<br />

Gli autovalori sono tutti reali e quello <strong>di</strong> massimo modulo è µ = 0.707106781 < 1.<br />

C’è, dunque, convergenza per i meto<strong>di</strong> <strong>di</strong> Jacobi e <strong>di</strong> Gauss-Seidel (ρ(E S ) = ρ(E J ) 2 = 0.5). Le velocità<br />

<strong>di</strong> convergenza valgono<br />

R J = −log 10 (ρ(E J )) = 0.1505149<br />

R S = −log 10 (ρ(E S )) = 0.301029995 = −log 10 (ρ(E J ) 2 ) = 2R J<br />

120


8.7. <strong>Esercizi</strong><br />

(b)<br />

Lo schema <strong>di</strong> Jacobi è:<br />

⎧<br />

x (k+1)<br />

1<br />

= 1 (30 − 2x(k)<br />

2<br />

− 6x (k)<br />

3<br />

8 )<br />

⎪⎨<br />

⎪⎩<br />

3<br />

= 1 2 1.0 1.55 0.65<br />

(7 − x(k)<br />

1<br />

5 Partendo dal vettore x (0) con componenti<br />

tutte nulle, abbiamo<br />

k x 1 (k)<br />

x 2 (k)<br />

x 3 (k)<br />

0 0 0 0<br />

1 3.75 6.8 1.4<br />

x (k+1)<br />

2<br />

= 1 (34 − 7x(k)<br />

1<br />

5 )<br />

x (k+1)<br />

Lo schema <strong>di</strong> Seidel è:<br />

⎧<br />

⎪⎨<br />

⎪⎩<br />

x (k+1)<br />

1<br />

= 1 (30 − 2x(k)<br />

2<br />

− 6x (k)<br />

3<br />

8 )<br />

x (k+1)<br />

2<br />

= 1 (34 − 7x(k+1)<br />

1<br />

)<br />

5<br />

x (k+1)<br />

3<br />

= 1 5<br />

(7 − x(k+1)<br />

1<br />

)<br />

Partendo dal vettore x (0) con componenti<br />

tutte nulle, abbiamo<br />

k x (k)<br />

1<br />

x (k)<br />

2<br />

x (k)<br />

3<br />

0 0 0 0<br />

1 3.75 1.55 0.65<br />

2 2.875 2.775 0.825<br />

<strong>Esercizi</strong>o 8.7.2 ⎛ Dato⎞il sistema Ax = b con<br />

5 0 10<br />

A = ⎝0 3 15⎠<br />

2 1 α<br />

(a) <strong>di</strong>re per quali valori <strong>di</strong> α il metodo <strong>di</strong> Jacobi converge.<br />

(b) trovare il valore <strong>di</strong> α in corrispondenza del quale il metodo SOR ha un valore <strong>di</strong> omega ottimo ω opt =<br />

3/2. Per tale valore trovare la velocità asintotica <strong>di</strong> convergenza del metodo SOR.<br />

Svolgimento<br />

(a) La matrice <strong>di</strong>pende dal parametro α quin<strong>di</strong> a priori non possiamo <strong>di</strong>re se Jacobi converge o meno.<br />

Scriviamo la matrice <strong>di</strong> iterazione del metodo <strong>di</strong> Jacobi come<br />

⎛<br />

⎞⎛<br />

⎞ ⎛<br />

⎞<br />

1/5 0 0 0 0 10 0 0 −2<br />

E J = −D −1 (L +U ) = −⎝<br />

0 1/3 0 ⎠⎝0 0 15⎠ = ⎝ 0 0 −5⎠<br />

0 0 1/α 2 1 0 −2/α −1/α 0<br />

Gli autovalori si calcolano imponendo det(E J − µI ) = 0, vale a <strong>di</strong>re<br />

−µ 0 −2<br />

0 −µ −5<br />

∣−2/α −1/α −µ ∣ = 0 vale a <strong>di</strong>re − µ3 + 9µ α = 0<br />

Ricaviamo gli autovalori µ = 0 e µ = ± 3 α<br />

.<br />

Perchè ci sia convergenza deve dunque essere 3 α<br />

< 1 ovvero 3 < α. Ricaviamo la relazione α > 9.<br />

(b) Dalla relazione dell’ω opt , ω opt =<br />

or<strong>di</strong>nata, si ha:<br />

2<br />

1 + √ , valida perchè la matrice è biciclica e coerentemente<br />

1 − ρ(E J )<br />

2<br />

2<br />

1 + 1 − 9/α = 3 2 =⇒ 1 3 = 1 − 9/α =⇒ −8<br />

9 = − 9 α =⇒ α = 81 8 = 10.125<br />

Da ω opt = 3 2 = 1.5 segue λ opt = ω opt − 1 = 0.5, da cui R = −log 10 (λ opt ) = 0.3010299957.<br />

121


C A P I T O L O<br />

9<br />

INTEGRAZIONE NUMERICA<br />

Dio non si preoccupa delle nostre<br />

<strong>di</strong>fficoltà matematiche. Lui integra<br />

empiricamente.<br />

Albert Einstein<br />

9.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123<br />

9.2 Formula dei trapezi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124<br />

9.3 Formule <strong>di</strong> Newton-Cotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />

9.3.1 Formula <strong>di</strong> Cavalieri-Simpson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

9.3.2 Sull’errore della formula <strong>di</strong> Cavalieri-Simpson . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />

9.4 Formule composte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />

9.4.1 Formula composta dei trapezi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />

9.4.2 Confronti tra la formula dei trapezi e <strong>di</strong> Cavalieri-Simpson . . . . . . . . . . . . . . . . . . 134<br />

9.5 Estrapolazione <strong>di</strong> Richardson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136<br />

9.6 Approssimazione <strong>di</strong> Romberg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />

9.7 Introduzione alle formule <strong>di</strong> quadratura <strong>di</strong> Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />

9.7.1 Proprietà delle formule <strong>di</strong> Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

9.7.2 Formule <strong>di</strong> Gauss-Legendre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

9.7.3 Altre formule <strong>di</strong> Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

9.7.4 Applicazione delle formule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />

9.7.5 Sulla funzione peso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

9.8 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

9.1 Introduzione<br />

Un’automobile effettua il giro <strong>di</strong> una pista in 84 secon<strong>di</strong>. La velocità dell’auto viene misurata ogni 6 secon<strong>di</strong><br />

usando un’apparecchiatura radar per il controllo della velocità, ricavando i valori che si trovano in<br />

Tabella 9.1.<br />

In base ai dati in possesso, quanto è lunga la pista?<br />

Sapendo che la velocità v è data da v(t) = d s (dove s rappresenta lo spostamento e t il tempo), per calcolare<br />

la lunghezza della pista (data dallo spostamento effettuato dall’auto), dobbiamo integrare la velocità<br />

d t<br />

tra<br />

123


9. INTEGRAZIONE NUMERICA<br />

Tempo 0 6 12 18 24 30 36 42 48 54 60 66 72 78 84<br />

Velocità 38 41 45 48 45 41 37 33 30 26 24 27 32 35 37<br />

Tabella 9.1: Dati della velocità misurati ogni 6 secon<strong>di</strong>. Il tempo è espresso in secon<strong>di</strong> e la velocità è data in<br />

metri al secondo.<br />

il tempo iniziale e quello finale.<br />

∫ 84<br />

0<br />

∫ s(84)<br />

∫<br />

d s s(84)<br />

v(t)d t =<br />

s(0) d t d t = d s<br />

s(0)<br />

Essendo s(0) = 0 e s(84) = L la lunghezza della pista, si ha<br />

∫ 84<br />

0<br />

v(t)d t =<br />

∫ s(84)<br />

s(0)<br />

d s = L<br />

Quin<strong>di</strong>, se riusciamo a risolvere l’integrale in cui la funzione integranda è la velocità, per le uguaglianze<br />

date, sapremo <strong>di</strong>re quanto vale L, essendo<br />

∫ 84<br />

0<br />

v(t)d t = L<br />

Sfruttando i dati della velocità misurati ogni 6 secon<strong>di</strong>, dobbiamo essere in grado <strong>di</strong> poter risolvere<br />

numericamente questo integrale.<br />

In questo Capitolo stu<strong>di</strong>eremo come fare. Ci occuperemo, infatti, <strong>di</strong> approssimare l’integrale definito<br />

∫ b<br />

I = f (x)d x<br />

a<br />

dove f è una funzione definita nell’intervallo [a,b] (e f può essere nota oppure data su determinati punti<br />

dell’intervallo, come nell’esempio appena visto).<br />

Una formula <strong>di</strong> integrazione numerica (detta anche formula <strong>di</strong> quadratura numerica) approssima<br />

l’integrale esatto I = ∫ b<br />

a f (x)d x me<strong>di</strong>ante ∑ n<br />

j =0 a j f (x j ):<br />

∫ b<br />

I =<br />

a<br />

f (x)d x ≈<br />

n∑<br />

a j f (x j )<br />

j =0<br />

dove x j , j = 0,...,n sono le ascisse o punti <strong>di</strong> appoggio della formula <strong>di</strong> quadratura e a j sono i pesi della<br />

formula.<br />

9.2 Formula dei trapezi<br />

Consideriamo la retta che interpola la f negli estremi dell’intervallo <strong>di</strong> integrazione.<br />

seguiamo l’approccio <strong>di</strong> interpolazione me<strong>di</strong>ante la tabella delle <strong>di</strong>fferenze <strong>di</strong>vise:<br />

Per semplicità,<br />

a<br />

b<br />

f (a)<br />

f (b)<br />

f (b) − f (a)<br />

Il polinomio <strong>di</strong> interpolazione (retta) che interpola la f in a e in b (gli estremi dell’intervallo <strong>di</strong> integrazione)<br />

è dato da<br />

f (b) − f (a)<br />

p(x) = f (a) + (x − a)<br />

b − a<br />

b − a<br />

124


9.3. Formule <strong>di</strong> Newton-Cotes<br />

L’errore <strong>di</strong> interpolazione, utilizzando l’espressione del resto <strong>di</strong> Lagrange è dato da<br />

E(x) = f ′′ (ξ x )<br />

(x − a)(x − b)<br />

2<br />

dove ξ x è un punto dell’intervallo [a,b]. Per quanto abbiamo stu<strong>di</strong>ato sull’interpolazione, sappiamo che la<br />

funzione f (x) si può scrivere come somma del polinomio e dell’errore: f (x) = p(x) + E(x). Nel nostro caso,<br />

abbiamo<br />

f (b) − f (a)<br />

f (x) = f (a) + (x − a) + f ′′ (ξ x )<br />

(x − a)(x − b)<br />

b − a<br />

2<br />

Dovendo integrare la f tra a e b e valendo l’uguaglianza precedente, integrando ambo i membri,<br />

otteniamo:<br />

∫ b<br />

∫ b<br />

(<br />

) ∫<br />

f (b) − f (a)<br />

b<br />

f (x)d x = f (a) + (x − a) d x + (x − a)(x − b) f ′′ (ξ x )<br />

d x<br />

b − a<br />

2<br />

a<br />

ovvero<br />

∫ b<br />

a<br />

a<br />

f (a) + f (b)<br />

f (x)d x = (b − a) + 1 2 2<br />

∫ b<br />

a<br />

a<br />

(x − a)(x − b)f ′′ (ξ x ))d x<br />

Poichè il prodotto (x −a)(x −b) ha segno costante in [a,b], per il teorema del Valor Me<strong>di</strong>o del calcolo integrale<br />

(si veda il Teorema 2.5.6) si ha<br />

1<br />

2<br />

∫ b<br />

a<br />

(x − a)(x − b)f ′′ (ξ x ))d x = 1 2 f ′′ (ξ)<br />

∫ b<br />

a<br />

(x − a)(x − b)d x = − 1 2 f ′′ (b − a)3<br />

(ξ)<br />

3!<br />

dove ξ è un punto interno all’intervallo [a,b].<br />

La quantità E i nt = − 1 2 f ′′ (b − a)3<br />

(ξ) = − 1<br />

3! 12 f ′′ (ξ)(b − a) 3 rappresenta l’errore che si commette approssimando<br />

l’integrale <strong>di</strong> f in [a,b] me<strong>di</strong>ante l’integrale della retta passante per f (a) e f (b), vale a <strong>di</strong>re, me<strong>di</strong>ante<br />

l’area del trapezio sottesa dalla corda passante per f (a) e f (b).<br />

In<strong>di</strong>cando con M = max a≤x≤b |f ′′ (x)| possiamo maggiorare l’errore con la relazione<br />

(b − a)3<br />

|E i nt | ≤ M<br />

12<br />

La formula dei trapezi approssima l’integrale <strong>di</strong> f in [a,b] come I tr ap dato da<br />

I tr ap = b − a [f (a) + f (b)]<br />

2<br />

9.3 Formule <strong>di</strong> Newton-Cotes<br />

Se, al posto <strong>di</strong> una retta, pren<strong>di</strong>amo come funzione interpolante la f un polinomio <strong>di</strong> grado più elevato,<br />

otterremo altre formule <strong>di</strong> quadrature.<br />

Supponiamo <strong>di</strong> poter valutare la f in n + 1 punti x 0 , x 1 ,..., x n e costruiamo il polinomio interpolatore <strong>di</strong><br />

grado n utilizzando la formula <strong>di</strong> Lagrange.<br />

Avremo p n (x) = ∑ n<br />

i=0 f (x i )L i (x), dove i polinomi <strong>di</strong> Lagrange sono dati dalla nota formula<br />

L i (x) =<br />

n∏<br />

j =0<br />

j ≠i<br />

x − x j<br />

x i − x j<br />

125


9. INTEGRAZIONE NUMERICA<br />

Figura 9.1: Formula dei trapezi: l’integrale della funzione f (zona tratteggiata in blu) viene approssimata<br />

me<strong>di</strong>ante l’area del trapezio sotteso alla retta <strong>di</strong> interpolazione per f (a) e f (b) (zona verde).<br />

Se i no<strong>di</strong> sono equi<strong>di</strong>stanti con passo h, possiamo scrivere x j = x 0 + j h, con j = 0,1,...,n e per un generico<br />

punto x compreso tra x 0 e x n vale x = x 0 + sh con 0 ≤ s ≤ n, s numero reale.<br />

Quin<strong>di</strong> x − x j = x 0 + sh − (x 0 + j h) = (s − j )h e x i − x j = (i − j )h, da cui il polinomio <strong>di</strong> Lagrange si può<br />

scrivere come<br />

L i (x) =<br />

n∏ s − j<br />

i − j = L i (s)<br />

j =0<br />

j ≠i<br />

Da f (x) = p n (x) + E(x) dove E(x) è l’errore della formula <strong>di</strong> interpolazione, passando all’integrale,<br />

abbiamo<br />

∫ b<br />

a<br />

f (x)d x =<br />

∫ b<br />

a<br />

p n (x)d x +<br />

∫ b<br />

a<br />

E(x)d x<br />

Il primo integrale a secondo membro rappresenta la formula che approssima l’integrale della f mentre il<br />

secondo integrale rappresenta l’errore della formula <strong>di</strong> quadratura.<br />

La formula <strong>di</strong> quadratura è quin<strong>di</strong> data dal valore dell’integrale <strong>di</strong> p n :<br />

∫ b<br />

∫ b n∑<br />

n∑<br />

I = f (x)d x ≈ f (x i )L i (x)d x = f (x i )<br />

a<br />

a<br />

i=0<br />

i=0<br />

∫ b<br />

a<br />

L i (x)d x<br />

La formula <strong>di</strong> quadratura ha dunque come no<strong>di</strong> i punti x i e come pesi gli integrali ∫ b<br />

a L i (x)d x.<br />

Sia x 0 = a e x n = b, tenendo presente che L i (x) = L i (s) con x = x 0 + sh, da cui d x = hd s abbiamo<br />

∫ b<br />

a<br />

∫ xn<br />

L i (x)d x = L i (x)d x =<br />

x 0<br />

Allora<br />

∫ b<br />

n∑<br />

I = f (x)d x ≈ h f (x i )<br />

a<br />

i=0<br />

∫ n<br />

0<br />

∫ n<br />

0<br />

L i (s)hd s = h<br />

L i (s)d s<br />

∫ n<br />

0<br />

L i (s)d s<br />

126


9.3. Formule <strong>di</strong> Newton-Cotes<br />

Definiamo coefficienti <strong>di</strong> Newton-Cotes 1 le espressioni<br />

C (n) = 1 i<br />

n<br />

∫ n<br />

0<br />

L i (s)d s<br />

i = 0,1,...,n<br />

La formula precedente si scrive, quin<strong>di</strong>, come<br />

∫ b<br />

I =<br />

a<br />

n∑<br />

n∑<br />

f (x)d x ≈ nh f (x i )C (n) = (x<br />

i n − x 0 )<br />

i=0<br />

L’errore della formula <strong>di</strong> quadratura è dato da<br />

E i nt =<br />

∫ b<br />

a<br />

∫ b<br />

E(x)d x =<br />

a<br />

i=0<br />

f (n+1) (ξ x )<br />

(x − x 0 )(x − x 1 )···(x − x n )d x<br />

(n + 1)!<br />

f (x i )C (n)<br />

i<br />

(9.1)<br />

Dato un polinomio <strong>di</strong> interpolazione <strong>di</strong> grado n me<strong>di</strong>ante il proce<strong>di</strong>mento <strong>di</strong> Lagrange è dunque possibile<br />

ricavare una formula <strong>di</strong> quadratura numerica che prende il nome <strong>di</strong> formula <strong>di</strong> Newton-Cotes. Per quanto<br />

riguarda l’errore si può osservare che le formule ottenute con un valore n <strong>di</strong>spari (cui corrisponde un numero<br />

n + 1 pari <strong>di</strong> punti <strong>di</strong> appoggio) è solo leggermente inferiore alle formule <strong>di</strong> or<strong>di</strong>ne pari che le precedono<br />

imme<strong>di</strong>atamente (cui corrisponde un numero <strong>di</strong>spari <strong>di</strong> punti <strong>di</strong> appoggio).<br />

Per questo motivo le formule <strong>di</strong> or<strong>di</strong>ne pari sono le più usate.<br />

Osserviamo che per f (x) ≡ 1, qualunque sia il grado del polinomio utilizzato nelle formule <strong>di</strong> Newton-<br />

Cotes, l’errore <strong>di</strong> integrazione sarà zero. Nell’intervallo [a,b] ≡ [0,1], applicando l’equazione (9.1) si ha<br />

1 =<br />

∫ 1<br />

0<br />

d x =<br />

n∑<br />

i=0<br />

C (n)<br />

i<br />

Troviamo che la somma dei coefficienti <strong>di</strong> Newton-Cotes vale 1.<br />

Per n = 1 (si hanno quin<strong>di</strong> due punti <strong>di</strong> appoggio, x 0 e x 1 ) i coefficienti <strong>di</strong> Cotes sono quelli già ricavati<br />

della formula dei trapezi<br />

Formula dei<br />

trapezi<br />

C (1)<br />

0<br />

= 1 1<br />

C (1)<br />

1<br />

= 1 1<br />

∫ 1<br />

0<br />

∫ 1<br />

0<br />

∫ 1<br />

L 0 (s)d s =<br />

L 1 (s)d s =<br />

0<br />

∫ 1<br />

0<br />

(s − 1)<br />

−1 d s = 1 2<br />

s<br />

1 d s = 1 2<br />

e la formula <strong>di</strong> integrazione <strong>di</strong>venta<br />

∫ b<br />

I =<br />

a<br />

f (x)d x ≈ h<br />

1∑<br />

i=0<br />

9.3.1 Formula <strong>di</strong> Cavalieri-Simpson<br />

f (x i )C (1)<br />

i<br />

= (x 1 − x 0 ) f (x 0) + f (x 1 )<br />

2<br />

Considerando n = 2 (quin<strong>di</strong> 3 punti <strong>di</strong> appoggio nell’intervallo [a,b], x 0 = a, x 1 = a + b e x 2 = b, i due<br />

2<br />

estremi dell’intervallo e il punto centrale) la formula <strong>di</strong> quadratura prende il nome <strong>di</strong> formula <strong>di</strong> Cavalieri-<br />

Simpson 2<br />

1 Roger Cotes (1682-1716) fu un matematico inglese che lavorò molto con Isaac Newton, in particolare per la correzione del suo<br />

famoso libro Principia. Egli inventò le formule <strong>di</strong> quadratura che prendono il suo nome e per primo introdussse quella che oggi<br />

conosciamo come formula <strong>di</strong> Eulero, per cui e x = cos(x) + i sin(x) nel campo complesso.<br />

2 Bonaventura Francesco Cavalieri (1598-1647) fu un matematico italiano. Stu<strong>di</strong>ò teologia e geometria. Lavorò su problemi <strong>di</strong> ottica<br />

e <strong>di</strong> cinematica. È famoso soprattutto per il cosiddetto principio <strong>di</strong> Cavalieri.<br />

Thomas Simpson (1710-1761) fu un matematico britannico, inventore della formula <strong>di</strong> quadratura per il calcolo <strong>di</strong> integrali definiti,<br />

sebbene questa formula fosse stata già scoperta 200 anni prima da Keplero e pare fosse usata anche da Cavalieri nel 1639 e poi riscoperta<br />

da James Gregory. I suoi stu<strong>di</strong> riguardano anche l’astrologia.<br />

127


9. INTEGRAZIONE NUMERICA<br />

Figura 9.2: Formula <strong>di</strong> Cavalieri-Simpson: l’integrale della funzione f (zona tratteggiata in blu) viene<br />

approssimata me<strong>di</strong>ante l’area della regione sottesa alla parabola passante per f (a), f (c) e f (b) (zona verde).<br />

C (2)<br />

0<br />

= 1 2<br />

C (2)<br />

1<br />

= 1 2<br />

C (2)<br />

2<br />

= 1 2<br />

∫ 2<br />

0<br />

∫ 2<br />

0<br />

∫ 2<br />

0<br />

L 0 (s)d s = 1 2<br />

L 1 (s)d s = 1 2<br />

L 2 (s)d s = 1 2<br />

∫ 2<br />

0<br />

∫ 2<br />

0<br />

∫ 2<br />

0<br />

(s − 1)(s − 2)<br />

d s = 1 (−1)(−2) 6<br />

(s)(s − 2)<br />

(1)(−1) d s = 4 6<br />

(s)(s − 1)<br />

d s = 1 (2)(1) 6<br />

La formula <strong>di</strong> Cavalieri-Simpson approssima l’integrale della f considerando come no<strong>di</strong> x 0 =<br />

a, x 1 = c = a + b e x 2 = b e come pesi i coefficienti <strong>di</strong> Cotes C (2)<br />

0<br />

= 1 2<br />

6 , C (2)<br />

1<br />

= 4 6 , C (2)<br />

2<br />

= 1 6 , ottenendo:<br />

∫ b<br />

I =<br />

a<br />

f (x)d x ≈ (x 2 − x 0 )<br />

2∑<br />

i=0<br />

f (x i )C (2)<br />

i<br />

= b − a (f (a) + 4f (c) + f (b))<br />

6<br />

= (b − a)( f (a)<br />

6<br />

4f (c)<br />

+ + f (b)<br />

6 6 )<br />

Con la formula <strong>di</strong> Cavalieri-Simpson, dunque, l’integrale della f viene approssimato con l’integrale della<br />

parabola passante per i due estremi a e b e per il punto centrale dell’intervallo.<br />

Per quanto riguarda l’errore che si commette approssimando l’integrale della f con la formula <strong>di</strong><br />

Cavalieri-Simpson, consideriamo, seguendo l’approccio visto per la formula dei trapezi, l’integrale dell’errore<br />

del polinomio <strong>di</strong> interpolazione <strong>di</strong> Lagrange.<br />

Per il polinomio <strong>di</strong> secondo grado p 2 che interpola la f , l’errore è dato da E(x) = f ′′′ (ξ x )<br />

(x−a)(x−c)(x−b).<br />

3!<br />

128


9.3. Formule <strong>di</strong> Newton-Cotes<br />

Quando facciamo l’integrale, l’errore nell’approssimare l’integrale esatto con la formula <strong>di</strong> Cavalieri-<br />

Simpson è dunque dato da<br />

∫ b<br />

E i nt =<br />

a<br />

f ′′′ (ξ x )<br />

(x − a)(x − c)(x − b)d x<br />

3!<br />

Questa volta, la funzione (x − a)(x − c)(x − b) cambia segno all’interno dell’intervallo [a,b] e non possiamo<br />

più applicare il teorema del Valor Me<strong>di</strong>o come nella formula dei trapezi. In maniera più laboriosa, tuttavia, si<br />

ricava per l’errore la seguente formula:<br />

E i nt = − f IV (u)<br />

90<br />

( ) b − a 5<br />

= − f IV (u)<br />

(b − a)5<br />

2 2880<br />

dove u è un opportuno punto dell’intervallo ]a,b[.<br />

Osservando i valori dei coefficienti <strong>di</strong> Newton-Cotes per n = 1 e per n = 2 si può vedere come i coefficienti<br />

siano simmetrici e la loro somma vale 1. Questo risultato si può generalizzare per ogni n.<br />

9.3.2 Sull’errore della formula <strong>di</strong> Cavalieri-Simpson<br />

Per capire l’errore che si ha nella formula <strong>di</strong> Cavalieri-Simpson, deduciamo la stessa formula seguendo<br />

un’altra strada.<br />

Per semplificare il <strong>di</strong>scorso, scegliamo l’intervallo [a,b] simmetrico rispetto all’origine, quin<strong>di</strong> del tipo<br />

[−t, t] con t ∈ R, sapendo che, se non fosse così, basta applicare una traslazione dell’asse x per ricondursi a<br />

questo caso. Scriviamo il polinomio <strong>di</strong> interpolazione che passa per i punti −t, 0 e t e che interpola anche la<br />

derivata prima della f in 0.<br />

Me<strong>di</strong>ante la tabella delle <strong>di</strong>fferenza <strong>di</strong>vise, il punto 0 va contato due volte e si ha:<br />

−t f (−t)<br />

f (0) − f (−t)<br />

0 f (0)<br />

t<br />

f ′ f (0) − f (−t)<br />

(0) −<br />

0 f (0) f ′ (0)<br />

t<br />

= t f ′ (0) − f (0) + f (−t)<br />

t<br />

t 2<br />

f (t) − f (0)<br />

− f<br />

f (t) − f (0)<br />

′ (0)<br />

t f (t)<br />

t<br />

= f (t) − f (0) − t f ′ (0) f (t) − 2t f ′ (0) − f (−t)<br />

t<br />

t<br />

t 2<br />

2t 3<br />

Il polinomio <strong>di</strong> interpolazione è, dunque<br />

f (0) − f (−t)<br />

p(x) = f (−t) + (x + t) + t f ′ (0) − f (0) + f (−t)<br />

t<br />

t 2 (x + t)x + f (t) − 2t f ′ (0) − f (−t)<br />

2t 3 (x + t)x 2<br />

L’errore <strong>di</strong> interpolazione per questo polinomio <strong>di</strong> grado 3 vale<br />

E(x) = f (IV ) (ξ x )<br />

(x + t)x 2 (x − t)<br />

4!<br />

Quin<strong>di</strong> da f (x) = p(x) + E(x), andando a integrare tra −t e t si ha:<br />

∫ t<br />

−t<br />

−t<br />

∫ t<br />

∫ t<br />

f (x)d x = p(x)d x + E(x)d x<br />

−t<br />

−t<br />

Nell’integrazione del polinomio p(x) è facile vedere che i termini che <strong>di</strong>pendono da f ′ (0) portano un<br />

contributo nullo. Infatti<br />

∫ t<br />

( f ′ (0)<br />

(x + t)x − f ′ ) ∫<br />

(0)<br />

t<br />

t<br />

t 2 (x + t)x 2 f ′ )<br />

(0)<br />

d x =<br />

(x 2 + t x − x3<br />

t<br />

t − x2 d x<br />

−t<br />

= f ′ (0)<br />

t<br />

[t x2<br />

2 − x4<br />

4t<br />

] t<br />

−t<br />

= 0<br />

129


9. INTEGRAZIONE NUMERICA<br />

Gli integrali <strong>degli</strong> altri termini del polinomio p(x) portano alla formula <strong>di</strong> Cavalieri-Simpson.<br />

(omettendo i passaggi matematici) si ha<br />

Infatti<br />

∫ t<br />

−t<br />

(<br />

f (−t) +<br />

f (0) − f (−t) f (−t) − f (0)<br />

(x + t) +<br />

t<br />

t 2 (x + t)x +<br />

= 2t (f (−t) + 4f (0) + f (t))<br />

6<br />

f (t) − f (−t)<br />

2t 3 (x + t)x 2 )<br />

d x =<br />

Allora l’errore della formula <strong>di</strong> Cavalieri-Simpson coincide con l’integrale <strong>di</strong> E(x).<br />

Quin<strong>di</strong> E i nt = ∫ t f (IV ) (ξ x )<br />

−t<br />

(x + t)x 2 (x − t)d x<br />

4!<br />

La funzione (x + t)x 2 (x − t) = (x 2 − t 2 )x 2 non cambia mai segno all’interno dell’intervallo [−t, t], quin<strong>di</strong> si<br />

può applicare il teorema del Valore Me<strong>di</strong>o del calcolo integrale, per cui<br />

E i nt = f (IV ) (ξ)<br />

24<br />

∫ t<br />

−t<br />

(x 2 − t 2 )x 2 d x = f (IV ) [<br />

(ξ) x<br />

5<br />

] t<br />

24 5 − t 2 x3<br />

3 −t<br />

Considerando che l’ampiezza dell’intervallo è h = 2t si ha<br />

E i nt = − f (IV ) (ξ)<br />

( h 90 2 )5 = − f (IV ) (ξ)<br />

2880 h5<br />

Troviamo la formula dell’errore per Cavalieri-Simpson.<br />

= − f (IV ) (ξ)<br />

t 5<br />

90<br />

9.4 Formule composte<br />

Le formule <strong>di</strong> Newton-Cotes non vanno bene su intervalli molto ampi perchè per avere risultati più accurati<br />

dovremmo utilizzare formule <strong>di</strong> grado elevato (in modo da utilizzare un numero elevato <strong>di</strong> punti <strong>di</strong><br />

appoggio). Ci sono vari motivi che sconsigliano questa procedura:<br />

G i valori dei coefficienti in formule <strong>di</strong> grado elevato sono <strong>di</strong>fficili da ottenere;<br />

G le formule <strong>di</strong> Newton-Cotes, essendo basate su polinomi <strong>di</strong> interpolazione con no<strong>di</strong> equi<strong>di</strong>stanti,<br />

danno risultati inaccurati su intervalli ampi a causa della natura oscillatoria dei polinomi <strong>di</strong> grado<br />

elevato.<br />

Conviene dunque utilizzare formule <strong>di</strong> grado basso ma scomponendo l’intervallo <strong>di</strong> integrazione in più<br />

sottointervalli e, in ciascuno <strong>di</strong> essi, applicare la stessa formula.<br />

Sfruttiamo il fatto che se l’intervallo [a,b] viene <strong>di</strong>viso in n sottointervalli in modo che [a,b] = [a, x 1 ] ∪<br />

[x 1 , x 2 ] ∪ [x 2 , x 3 ] ∪ ... ∪ [x n−1 ,b], allora<br />

∫ b<br />

a<br />

∫ x1<br />

∫ x2<br />

∫ x3<br />

∫ b<br />

f (x)d x = f (x)d x + f (x)d x + f (x)d x + ... + f (x)d x<br />

a<br />

x 1 x 2 x n−1<br />

Su ciascuno intervallo [x i−1 , x i ] per i = 1,2,...,n, approssimiamo l’integrale della f me<strong>di</strong>ante una formula<br />

<strong>di</strong> quadratura più semplice, utilizzando pochi punti.<br />

9.4.1 Formula composta dei trapezi<br />

Sud<strong>di</strong>vi<strong>di</strong>amo l’intervallo [a,b] in n sottointervalli definiti dai punti d’appoggio x 0 , x 1 ,..., x n (per semplicità<br />

supponiamo i punti equi<strong>di</strong>stanti con passo h = b − a<br />

n , in modo che x 0 = a e x n = b, x i = x 0 + i h,<br />

i = 0,...,n).<br />

L’integrale su [a,b] si può dunque ottenere come somma <strong>degli</strong> integrali su tali sottointervalli:<br />

130<br />

∫ b<br />

a<br />

f (x)d x =<br />

n∑<br />

i=1<br />

∫ xi<br />

x i−1<br />

f (x)d x


9.4. Formule composte<br />

Figura 9.3: Formula composta dei trapezi, utilizzando 3 sottointervalli (4 punti).<br />

Ciascuno <strong>degli</strong> integrali su [x i−1 , x i ] viene approssimato utilizzando la formula dei trapezi:<br />

n∑<br />

i=1<br />

∫ xi<br />

x i−1<br />

f (x)d x ≈<br />

In forma estesa abbiamo<br />

n∑<br />

i=1<br />

x i − x i−1<br />

2<br />

[f (x i−1 ) + f (x i )] =<br />

n∑<br />

i=1<br />

I ≈ h 2 [f (x 0) + 2f (x 1 ) + 2f (x 2 ) + ... + 2f (x n−1 ) + f (x n )]<br />

f (a) + f (b)<br />

= h[ + f (x 1 ) + f (x 2 ) + ... f (x n−1 )]<br />

2<br />

h<br />

2 [f (x i−1) + f (x i )]<br />

L’errore che si commette è dato dalla somma <strong>degli</strong> errori commessi sui singoli sottointervalli<br />

E i nt =<br />

n∑<br />

i=1<br />

−f ′′ (ξ i ) h3<br />

12<br />

Supponendo che la derivata seconda della f sia continua e limitata in [a,b] e chiamando con m e M<br />

rispettivamente il minimo e il massimo <strong>di</strong> f ′′ in [a,b], si ha:<br />

m ≤ f ′′ (ξ i ) ≤ M<br />

i = 1,...,n<br />

Considerando la somma <strong>di</strong> queste <strong>di</strong>seguaglianze, per i = 1,...,n si ricava<br />

∑<br />

n∑<br />

n<br />

nm ≤ f ′′ i=1<br />

(ξ i ) ≤ nM =⇒ m ≤<br />

f ′′ (ξ i )<br />

≤ M<br />

i=1<br />

n<br />

∑ n<br />

i=1<br />

Per il teorema del Valor Interme<strong>di</strong>o (teorema 2.5.3),<br />

f ′′ (ξ i )<br />

è un valore assunto dalla funzione in<br />

n<br />

qualche punto u <strong>di</strong> [a,b].<br />

Applicando la relazione h = b − a , l’errore <strong>di</strong>venta<br />

n<br />

n∑<br />

E i nt = −f ′′ (ξ i ) h3<br />

i=1<br />

12 = −n f ′′ (ξ) h3<br />

12 = − f ′′ (ξ)<br />

12 (b − a)h2 = − f ′′ (ξ) (b − a) 3<br />

12 n 2 131


9. INTEGRAZIONE NUMERICA<br />

Quin<strong>di</strong> per n → ∞ l’errore tende a zero come h 2 o, equivalentemente, come 1 n 2 .<br />

Formula composta <strong>di</strong> Cavalieri-Simpson<br />

Sud<strong>di</strong>vi<strong>di</strong>amo l’intervallo [a,b] in n sottointervalli <strong>di</strong> ampiezza costante uguale a h e su ciascuno <strong>di</strong> questi<br />

sottointervalli applichiamo la formula <strong>di</strong> Cavalieri-Simpson. Abbiamo, in questo modo, la formula composta<br />

<strong>di</strong> Cavalieri-Simpson.<br />

Su ogni intervallino, quin<strong>di</strong>, dobbiamo considerare gli estremi dell’intervallino e il punto centrale <strong>di</strong> esso.<br />

Siano a i e b i gli estremi <strong>di</strong> ciascuna sud<strong>di</strong>visione e sia c i = a i + b i<br />

il punto me<strong>di</strong>o <strong>di</strong> ciascuna sud<strong>di</strong>visione<br />

2<br />

(quin<strong>di</strong> per i = 1,...,n). L’estremo superiore b i <strong>di</strong> ciascun intervallino, con i = 1,n − 1 coincide con l’estremo<br />

inferiore dell’intervallino successivo: b i = a i+1 . In tal modo, seguendo lo stesso ragionamento fatto per i<br />

trapezi si ha:<br />

∫ b<br />

a<br />

∫ b1<br />

∫ b2<br />

∫ bn<br />

f (x)d x = f (x)d x + f (x)d x + ... + f (x)d x<br />

a 1 a 2 a n<br />

Applicando la formula <strong>di</strong> Cavalieri-Simpson su ciascun intervallino risulta:<br />

∫ bi<br />

a i<br />

In tal modo<br />

∫ b<br />

a<br />

f (x)d x ≈ b i − a i<br />

6<br />

f (x)d x ≈<br />

(<br />

f (ai ) + 4f (c i ) + f (b i ) ) = h 6<br />

n∑ h (<br />

f (ai ) + 4f (c i ) + f (b i ) )<br />

i=1<br />

6<br />

Si ha la formula composta <strong>di</strong> Cavalieri-Simpson.<br />

(<br />

f (ai ) + 4f (c i ) + f (b i ) )<br />

Figura 9.4: Formula composta <strong>di</strong> Cavalieri-Simpson, utilizzando 3 sottointervalli (7 punti).<br />

132


9.4. Formule composte<br />

Possiamo vedere la formula composta <strong>di</strong> Cavalieri-Simpson anche in una forma compatta.<br />

Considerando che, su ogni sottointervallo, dobbiamo prendere il punto me<strong>di</strong>o, facciamo<br />

una numerazione progressiva dei punti <strong>di</strong> integrazione nel modo seguente:<br />

x 0 = a<br />

x 2i = x 0 + i h<br />

i = 0,...n no<strong>di</strong> estremi dei sottointervalli<br />

x 2i+1 = x 0 + (i + 1 2 )h<br />

i = 0,...,n − 1 no<strong>di</strong> centrali dei sottointervalli<br />

Quin<strong>di</strong> i no<strong>di</strong> pari corrispondono agli estremi dei sottointervalli, mentre i no<strong>di</strong> <strong>di</strong>spari sono<br />

i punti centrali <strong>di</strong> ogni sottointervallo. Per la formula <strong>di</strong> quadratura otteniamo<br />

∫ b<br />

n−1 ∑<br />

∫ x2i+2<br />

I = f (x)d x =<br />

f (x)d x<br />

a<br />

i=0<br />

i=0<br />

x 2i<br />

n−1 ∑ h<br />

≈<br />

6 [f (x 2i ) + 4f (x 2i+1 ) + f (x 2i+2 )]<br />

= h 6 [f (x 0) + 4f (x 1 ) + 2f (x 2 ) + 4f (x 3 ) + ... + 2f (x 2n−2 ) + 4f (x 2n−1 ) + f (x 2n )]<br />

= h n−1<br />

6 [f (x ∑<br />

n−1 ∑<br />

0) + 4 f (x 2i+1 ) + 2 f (x 2i ) + f (x 2n )]<br />

i=0<br />

i=0<br />

Per quanto riguarda l’errore, facendo la somma <strong>degli</strong> errori <strong>di</strong> integrazione sugli n sottointervalli,<br />

nell’ipotesi che la derivata quarta sia continua e limitata, si ha 3 :<br />

E i nt = − 1 ( ) h 5<br />

(f IV (ξ 1 ) + f IV (ξ 2 ) + ... + f IV (ξ n ))<br />

90 2<br />

= − h5 n−1 ∑<br />

f IV (b − a)5<br />

n−1 ∑<br />

(ξ i ) = −<br />

2880<br />

2880n 5 f IV (ξ i )<br />

i=0<br />

i=0<br />

Si considera quin<strong>di</strong> il punto ξ tale che 4<br />

f IV (ξ) = 1 n<br />

n∑<br />

f IV (ξ i )<br />

i=1<br />

(b − a)5<br />

E i nt = −<br />

2880n 4 f IV (b − a)h4<br />

(ξ) = − f IV (ξ)<br />

2880<br />

Quin<strong>di</strong> per n → ∞ l’errore tende a zero come<br />

1 n 4 o, equivalentemente, come h4 . Nella formula dei trapezi<br />

l’errore invece decresce come<br />

1 . Ci aspettiamo quin<strong>di</strong> che il maggiore sforzo computazionale <strong>di</strong>a una<br />

n2 maggiore accuratezza nei risultati quando si applica la formula <strong>di</strong> Cavalieri-Simpson rispetto alla formula dei<br />

trapezi.<br />

3 Ricor<strong>di</strong>amo che h = b − a<br />

n .<br />

4 Si ripete lo stesso ragionamento fatto sulla derivata seconda nella formula composta dei trapezi, questa volta però sulla derivata<br />

quarta. Per esercizio, si consiglia <strong>di</strong> ripetere tutti i passaggi per arrivare al risultato.<br />

133


9. INTEGRAZIONE NUMERICA<br />

9.4.2 Confronti tra la formula dei trapezi e <strong>di</strong> Cavalieri-Simpson<br />

Esempio 9.4.1 Consideriamo f (x) = e x . Sia a = 0 e b = 1.<br />

Allora, per l’integrale esatto e per le formule dei trapezi e <strong>di</strong> Cavalieri-Simpson, si ha, rispettivamente:<br />

I =<br />

∫ 1<br />

0<br />

e x d x = [ e x] 1<br />

0 = e − 1 = 1.718281828<br />

I tr ap = 1 (1 + e) = 1.859140914<br />

2<br />

I C−S = 1 6 (1 + 4e1/2 + e) = 1 (1 + 6.594885083 + 2.718281828) = 1.718861152<br />

6<br />

La formula <strong>di</strong> Cavalieri-Simpson dà il risultato migliore.<br />

Sia ancora f (x) = e x ma gli estremi <strong>di</strong> integrazione siano a = 0.9 e b = 1. Allora<br />

I =<br />

∫ 1<br />

0.9<br />

e x d x = e − e 0.9 = 0.2586787173<br />

I − I tr ap = I − 0.1<br />

2 (e0.9 + e) = −2.2 × 10 −4<br />

I − I C−S = I − 0.1<br />

6 (e0.9 + 4e 0.95 + e) = −9.0 × 10 −9<br />

Ora la formula <strong>di</strong> Cavalieri-Simpson si rivela particolarmente accurata. Ciò non deve sorprendere se si va<br />

a vedere la formula dell’errore, con l’ampiezza dell’intervallo che da 1 si è ridotta a 0.1, per cui (b − a) 5 da 1<br />

vale ora 10 −5 .<br />

Considerato che f ′′ = f e f IV = f , queste derivate possono essere maggiorate dal valore assunto nell’estremo<br />

superiore dell’intervallo, cioè e. Quin<strong>di</strong> gli errori delle formule dei trapezi e <strong>di</strong> Cavalieri-Simpson sono<br />

maggiorate da<br />

|E tr ap | ≤ e<br />

12 (b − a)3 = 2.265 × 10 −1 (b − a) 3<br />

|E C−S | ≤ e<br />

2880 (b − a)5 = 9.438 × 10 −4 (b − a) 5<br />

Perciò per a = 0 e b = 1 gli errori sono maggiorati da<br />

|E tr ap | = 2.265 × 10 −1<br />

|E C−S | = 9.438 × 10 −4<br />

Invece per a = 0.9 e b = 1, poichè b − a = 0.1 = 10 −1 , abbiamo<br />

|E tr ap | = 2.265 × 10 −1 · 10 −3 = 2.265 × 10 −4<br />

|E C−S | = 9.438 × 10 −4 · 10 −5 = 9.438 × 10 −9<br />

Esempio 9.4.2 Si voglia approssimare l’integrale a<br />

∫ 1<br />

0<br />

e −x2 d x ≈ 0.746824.<br />

a È un integrale che non può essere risolto analiticamente. Se si vuole calcolare una sua approssimazione senza<br />

fare uso <strong>di</strong> formule <strong>di</strong> quadrature, possiamo, ad esempio, pensare <strong>di</strong> applicare la definizione <strong>di</strong> integrale ∫ b<br />

a f (x)d x =<br />

∑<br />

lim n n→∞ f (a + i h(n)) · h(n), con h(n) = (b − a)/n, e considerare come approssimazione dell’integrale la somma parziale<br />

∑ i=0<br />

n<br />

i=0 f (a + i h(n)) · h(n) con un valore <strong>di</strong> n molto grande. Per esempio, con n = 107 otteniamo il valore 0.74682420125254.<br />

134


9.4. Formule composte<br />

Sud<strong>di</strong>vi<strong>di</strong>amo l’intervallo [0,1] in 4 sottointervalli. Sia h = 1/4 = 0.25. Per la formula composta dei trapezi<br />

abbiamo<br />

I tr ap = h 2 [e0 + 2e −h2 + 2e −(2h)2 + 2e −(3h)2 + e −(4h)2 ]<br />

= 0.125[1 + 2e −0.1252 + 2e −0.52 + 2e −0.752 + e −1 ]<br />

= 0.742984<br />

Applichiamo ora la formula <strong>di</strong> Cavalieri-Simpson su soli 2 sottointervalli, in modo da valutare la funzione<br />

negli stessi punti precedenti. L’ampiezza <strong>di</strong> ciascun sottointervallo è dunque h = 0.5.<br />

I C−S = h 6 [e0 + 4e −(h/2)2 + 2e −(h)2 + 4e −( 3 2 h)2 + e −(2h)2 ]<br />

= 0.25<br />

3 [1 + 4e−0.1252 + 2e −0.52 + 4e −0.752 + e −1 ]<br />

= 0.746855<br />

A parità <strong>di</strong> punti (e non <strong>di</strong> sottointervalli) la formula <strong>di</strong> Cavalieri-Simpson è più accurata <strong>di</strong> quella dei<br />

trapezi.<br />

Invece considerando 4 sottointervalli nella formula <strong>di</strong> Cavalieri-Simpson dobbiamo considerare anche i<br />

punti interni <strong>di</strong> ascisse 0.125, 0.375, 0.625, 0.875 e il risultato che otteniamo è 0.746826, evidentemente<br />

maggiormente accurato.<br />

Esempio 9.4.3 Ripren<strong>di</strong>amo l’esempio visto all’inizio del Capitolo, in cui è misurata la velocità <strong>di</strong><br />

un’automobile ogni 6 secon<strong>di</strong> e si vuole calcolare la lunghezza percorsa dalla macchina.<br />

In base ai dati in possesso, possiamo applicare la formula composta dei trapezi su 14 intervalli <strong>di</strong> ampiezza<br />

h = 6 secon<strong>di</strong>. Abbiamo (ponendo v 1 = v(0), v 2 = v(6), . . . , v 13 = v(78), v 14 = v(84)):<br />

( v1 + v<br />

) 14<br />

L = 6 + v 2 + v 3 + ... + v 13 = 3009 metri<br />

2<br />

Possiamo anche applicare la formula <strong>di</strong> Cavalieri-Simpson, considerando ora 7 intervalli <strong>di</strong> ampiezza pari<br />

a h = 12 secon<strong>di</strong>. In tal caso, otteniamo:<br />

L = 2(v 1 + 4v 2 + 2v 3 + 4v 4 + 2v 5 + ... + 2v 12 + 4v 13 + v 14 ) = 3010 metri<br />

In questo caso entrambi i risultati sono accettabili.<br />

Se la funzione integranda ha le derivate che sono facili da determinare e da maggiorare, la formula dell’errore<br />

può essere utile per determinare il numero <strong>di</strong> sottointervalli su cui applicare una formula composta<br />

<strong>di</strong> quadratura in modo da ottenere un’approssimazione con un errore minore <strong>di</strong> una tolleranza prefissata.<br />

Esempio 9.4.4 Consideriamo ∫ 1<br />

0 e−x2 d x. In quanti sottointervalli bisogna sud<strong>di</strong>videre l’intervallo <strong>di</strong> integrazione<br />

per applicare la formula dei trapezi e <strong>di</strong> Cavalieri-Simpson e ottenere un errore che sia minore <strong>di</strong><br />

una tolleranza ɛ = 10 −5 ?<br />

Per i trapezi, l’errore è maggiorato da<br />

|E tr ap | ≤ max 0≤x≤1 |f ′′ (x)| (b − a) 3<br />

12<br />

n 2<br />

Per Cavalieri-Simpson si ha<br />

|E C−S | ≤ max 0≤x≤1 |f IV (x)| (b − a) 5<br />

2880<br />

n 4 135


9. INTEGRAZIONE NUMERICA<br />

Da f (x) = e −x2 abbiamo, per le derivate:<br />

f ′ (x) = −2xe −x2<br />

f ′′ (x) = (−2 + 4x 2 )e −x2<br />

f ′′′ (x) = (12x − 8x 3 )e −x2<br />

f IV (x) = (12 − 48x 2 + 16x 4 )e −x2<br />

Si trova che il massimo <strong>di</strong> |f ′′ | e |f IV | in [0,1] è dato dal loro valore in x = 0, quin<strong>di</strong> abbiamo:<br />

|E tr ap | ≤ 2<br />

12n 2 = 1<br />

6n 2 |E C−S | ≤ 12<br />

2880n 4 = 1<br />

240n 4<br />

La richiesta dell’accuratezza per l’errore <strong>di</strong>venta:<br />

|E tr ap | ≤ 10 −5 |E C−S | ≤ 10 −5<br />

vale a <strong>di</strong>re, rispettivamente,<br />

1<br />

6n 2 ≤ 10−5 1<br />

240n 4 ≤ 10−5<br />

Per i trapezi, il primo intero n che verifica la <strong>di</strong>suguaglianza è n = 130, per Cavalieri-Simpson si ha, invece,<br />

n = 5.<br />

Applicando le formule su 130 intervalli per i trapezi e su 5 intervalli per Cavalieri-Simpson, otteniamo i<br />

risultati:<br />

I tr ap = 0.74682050480289 I C−S = 0.7468249482544<br />

9.5 Estrapolazione <strong>di</strong> Richardson<br />

Applichiamo la formula <strong>di</strong> Cavalieri-Simpson sull’intero intervallo [a,b]. L’errore che si commette, come<br />

sappiamo, vale<br />

E 1 = − f IV (ξ 1 )<br />

90<br />

( ) b − a 5<br />

= − f IV (ξ 1 )<br />

(b − a)5<br />

2 2880<br />

Sud<strong>di</strong>vi<strong>di</strong>amo ora l’intervallo [a,b] in due sottointervalli e applichiamo la formula composta <strong>di</strong> Cavalieri-<br />

Simpson. L’errore che otteniamo vale<br />

E 2 = − f IV (ξ 2 ) (b − a) 5<br />

2880 2 4<br />

e, supponendo che le derivate quarte della f non siano molto <strong>di</strong>verse tra loro, si ha E 2 ≈ E 1<br />

16 .<br />

L’errore, quin<strong>di</strong>, <strong>di</strong>venta 16 volte più piccolo passando dalla formula <strong>di</strong> Cavalieri-Simpson in un intervallo<br />

alla formula applicata in due sottointervalli.<br />

Sia I il valore esatto dell’integrale e Q 1 e Q 2 i due valori approssimati ottenuti considerando la formula<br />

<strong>di</strong> Cavalieri-Simpson con n = 1 e n = 2 sottointervalli. Sia ɛ l’errore, cambiato <strong>di</strong> segno, che si ha con n = 2,<br />

ɛ = −E 2 ≈ −E 1 /16. Possiamo scrivere<br />

I + ɛ = Q 2 per n = 2<br />

I + 16ɛ = Q 1 per n = 1<br />

136


9.6. Approssimazione <strong>di</strong> Romberg<br />

Si può ricavare ɛ dalle due relazioni ottenendo<br />

Quin<strong>di</strong><br />

ɛ = Q 1 −Q 2<br />

15<br />

I ≈ Q 2 + Q 2 −Q 1<br />

15<br />

Utilizzando le due approssimazioni Q 1 e Q 2 possiamo approssimare l’integrale esatto con una maggiore accuratezza<br />

me<strong>di</strong>ante la formula appena scritta. Questo proce<strong>di</strong>mento prende il nome <strong>di</strong> estrapolazione <strong>di</strong><br />

Richardson. Può essere utilizzato per migliorare l’approssimazione <strong>di</strong> un integrale ma è basato sull’ipotesi<br />

che le derivate quarte della funzione integranda siano circa uguali e, quin<strong>di</strong>, va usato con cautela.<br />

9.6 Approssimazione <strong>di</strong> Romberg<br />

Ripetendo lo stesso <strong>di</strong>scorso dell’estrapolazione <strong>di</strong> Richardson a partire dalla formula dei trapezi e in<br />

maniera sistematica, si ha l’approssimazione <strong>di</strong> Romberg.<br />

Supponiamo l’uguaglianza delle derivate seconde della funzione integranda f e sia 2 m il numero <strong>di</strong><br />

sottointervalli in cui sud<strong>di</strong>vi<strong>di</strong>amo il dominio <strong>di</strong> integrazione [a,b].<br />

Applicando la formula dei trapezi su 2 m−1 sottointervalli e, successivamente, su 2 m sottointervalli, l’errore<br />

<strong>di</strong>minuisce come 1/4. Chiamando con A m e A m−1 i risultati della formula dei trapezi rispettivamente su 2 m<br />

e su 2 m−1 sottointervalli e chiamando con ɛ l’errore cambiato <strong>di</strong> segno commesso con 2 m sottointervalli,<br />

abbiamo:<br />

I + ɛ = A m<br />

I + 4ɛ = A m−1<br />

L’integrale può essere dunque migliorato con il valore<br />

B m = A m + A m − A m−1<br />

.<br />

3<br />

Per m = 1 si ha:<br />

A 0 = b − a [f (a) + f (b)] è la formula dei trapezi applicata su un unico intervallo<br />

2<br />

A 1 = b − a<br />

2 [ f (a)<br />

2 + f ( a + b<br />

2 ) + f (b) ] è la formula dei trapezi su 2 sottointervalli<br />

2<br />

B 1 = (b − a)[ f (a) 4f ( a + b<br />

6 + 2 )<br />

6<br />

) + f (b) ] troviamo la formula <strong>di</strong> Cavalieri-Simpson!<br />

6<br />

Si ha dunque che B 1 (e quin<strong>di</strong> ciascun B m ) corrisponde al valore ottenuto con la formula <strong>di</strong> Cavalieri-<br />

Simpson. L’errore ottenuto con B m è dunque proporzionale a 1/n 4 . Nel passo successivo, utilizzando i valori<br />

B m , otteniamo la nuova approssimazione data da<br />

C m = B m + B m − B m−1<br />

15<br />

per m ≥ 2<br />

Si può <strong>di</strong>mostrare che C m coincide con la formula <strong>di</strong> Newton-Cotes con n = 4, dove l’errore è proporzionale<br />

a 1/n 6 e alla derivata sesta <strong>di</strong> f.<br />

La nuova approssimazione è data da:<br />

D m = C m + C m −C m−1<br />

63<br />

per m ≥ 3<br />

137


9. INTEGRAZIONE NUMERICA<br />

L’errore ora <strong>di</strong>venta proporzionale a 1/n 8 ma D m non è più un risultato delle formule <strong>di</strong> Newton-Cotes. Il<br />

proce<strong>di</strong>mento può andare avanti per calcolare E m , F m , etc tenendo presente che al denominatore dobbiamo<br />

mettere il valore 4(d + 1) − 1 dove d è il valore del denominatore della formula precedente.<br />

Il vantaggio dell’approssimazione <strong>di</strong> Romberg si vede solo ai primi livelli dell’applicazione (in particolare<br />

passando da A m a B m ). Inoltre, a causa della precisione finita con cui sono eseguiti i calcoli, le formule <strong>di</strong><br />

Romberg <strong>di</strong> or<strong>di</strong>ne elevato <strong>di</strong>ventano inefficaci se il risultato iniziale A m è già abbastanza accurato rispetto<br />

alla precisione numerica consentita.<br />

9.7 Introduzione alle formule <strong>di</strong> quadratura <strong>di</strong> Gauss<br />

Consideriamo <strong>di</strong> voler approssimare l’integrale dato da<br />

∫ b<br />

a<br />

f (x)w(x) d x<br />

dove [a,b] può essere finito o infinito (per esempio [−1,1], [0,+∞]). Abbiamo due funzioni, la f (x) e la w(x),<br />

e vogliamo integrare il prodotto <strong>di</strong> queste due funzioni. La funzione w(x), che chiamiamo funzione peso, sia<br />

positiva (w(x) ≥ 0).<br />

Vogliamo trovare dei coefficienti w i , i = 0,...n (detti pesi della formula <strong>di</strong> quadratura) e dei no<strong>di</strong> x i , i =<br />

0,...n (detti no<strong>di</strong> <strong>di</strong> quadratura) nell’intervallo [a,b] in modo da approssimare l’integrale me<strong>di</strong>ante<br />

∫ b<br />

a<br />

f (x)w(x) d x ≈<br />

n∑<br />

w i f (x i )<br />

0=1<br />

Considerando anche l’errore <strong>di</strong> quadratura:<br />

∫ b<br />

a<br />

f (x)w(x) d x =<br />

n∑<br />

w i f (x i ) + E i nt (f )<br />

i=0<br />

Diremo che la formula <strong>di</strong> quadratura ha un grado <strong>di</strong> precisione (o esattezza) polinomiale d se E i nt (f ) = 0<br />

per tutti i polinomi f fino al grado d (cioè se applichiamo la formula <strong>di</strong> quadratura per approssimare<br />

∫ b<br />

a<br />

f (x)w(x) d x con f polinomio <strong>di</strong> grado d, l’errore è nullo). Osserviamo che ora non stiamo parlando <strong>di</strong><br />

formule <strong>di</strong> quadratura composte quin<strong>di</strong> n non si riferisce a sud<strong>di</strong>visioni dell’intervallo [a,b].<br />

Per le formule <strong>di</strong> Newton-Cotes, si ha w(x) ≡ 1 e si può provare che il grado <strong>di</strong> precisione d è:<br />

d = n per le formule ottenute da polinomi <strong>di</strong> interpolazione <strong>di</strong> grado n <strong>di</strong>spari (come nei Trapezi: n = 1)<br />

G d = n + 1 per le formule ottenute da polinomi <strong>di</strong> interpolazione <strong>di</strong> grado n pari (come in Cavalieri-<br />

Simpson: n = 2)<br />

Diremo che la formula <strong>di</strong> quadratura è interpolatoria se vale d = n . Le formule interpolatorie sono ottenute<br />

per interpolazione, percorrendo la stessa strada che abbiamo visto per le formule <strong>di</strong> Newton-Cotes.<br />

Interpoliamo la funzione f me<strong>di</strong>ante un polinomio <strong>di</strong> grado n, utilizzando i polinomi <strong>di</strong> Lagrange. Nel costruire<br />

i pesi dobbiamo tenere conto anche della funzione w e quin<strong>di</strong> i pesi saranno w i = ∫ b<br />

a L i (x)w(x) d x<br />

dove L i (x) è l’i -simo polinomio <strong>di</strong> Lagrange.<br />

Con questo approccio, e con no<strong>di</strong> equi<strong>di</strong>stanti, la formula <strong>di</strong> quadratura che ricaviamo ha al più grado <strong>di</strong><br />

precisione d = n (o d = n + 1 quando w(x) ≡ 1 e per n pari, come abbiamo visto per le formule <strong>di</strong> Newton-<br />

Cotes).<br />

È possibile ricavare formule <strong>di</strong> quadratura che abbiano un grado <strong>di</strong> precisione d maggiore del grado del<br />

polinomio interpolante? E se sì come?<br />

A tal fine consideriamo il polinomio dei no<strong>di</strong> F (x) = ∏ n<br />

i=0 (x − x i ), <strong>di</strong> grado n + 1, lo stesso che abbiamo<br />

introdotto nel Capitolo sull’interpolazione.<br />

Vale il seguente teorema.<br />

Teorema 9.7.1 (<strong>di</strong> W. Gautschi) Dato un intero k con 0 < k ≤ n + 1, la formula <strong>di</strong> quadratura<br />

∫ b<br />

a<br />

f (x)w(x) d x =<br />

n∑<br />

w i f (x i ) + E i nt (f )<br />

i=0<br />

ha grado <strong>di</strong> precisione (esattezza) d = n + k se e solo se sono sod<strong>di</strong>sfatte entrambe le con<strong>di</strong>zioni (a) e (b):<br />

138


9.7. Introduzione alle formule <strong>di</strong> quadratura <strong>di</strong> Gauss<br />

(a) la formula è interpolatoria;<br />

(b) il polinomio dei no<strong>di</strong> F (x) sod<strong>di</strong>sfa la relazione ∫ b<br />

a<br />

F (x)p(x)w(x) d x = 0 per ogni polinomio p <strong>di</strong> grado<br />

≤ k − 1.<br />

Osserviamo che la con<strong>di</strong>zione in (b):<br />

G impone k con<strong>di</strong>zioni sui no<strong>di</strong> x 0 , x 1 , x 2 ,... x n . Se fosse k = 0 non ci sarebbero con<strong>di</strong>zioni in più da<br />

considerare e avremmo d = n (cioè esattezza d = n);<br />

G fornisce una relazione <strong>di</strong> ortogonalità: il polinomio F è ortogonale ai polinomi <strong>di</strong> grado ≤ k −1 rispetto<br />

alla funzione peso w. 5<br />

Nel caso specifico, il punto (b) <strong>di</strong>ce che:<br />

∫ b<br />

a<br />

∫ b<br />

a<br />

∫ b<br />

a<br />

∫ b<br />

a<br />

F (x)w(x) d x = 0<br />

xF (x)w(x) d x = 0<br />

x 2 F (x)w(x) d x = 0<br />

.<br />

x k−1 F (x)w(x) d x = 0<br />

G fa sì che k non possa essere maggiore o uguale a n + 2. Se fosse infatti k = n + 2, il punto (b) sarebbe:<br />

(b) il polinomio dei no<strong>di</strong> F (x) sod<strong>di</strong>sfa la relazione ∫ b<br />

a<br />

F (x)p(x)w(x)d x = 0 per ogni polinomio p <strong>di</strong><br />

grado ≤ k − 1 = n + 1.<br />

Allora, si potrebbe prendere come polinomio p(x) esattamente F (x) (che ha grado n + 1) e, per la<br />

(b) sarebbe ∫ b<br />

a (F (x))2 w(x)d x = 0: ma questo è un assurdo perchè l’integrale <strong>di</strong> una funzione positiva<br />

non può essere nullo, e, nel nostro caso, w(x) è positiva e (F (x)) 2 , essendo il quadrato <strong>di</strong> un polinomio,<br />

è pure essa una funzione positiva.<br />

Il caso ottimale (il più alto grado <strong>di</strong> precisione che si può ottenere), si ha per k uguale al valore massimo che<br />

può assumere, vale a <strong>di</strong>re k = n + 1. In tal caso d = n + k = n + n + 1 = 2n + 1. Si hanno le cosiddette formule<br />

<strong>di</strong> Gauss.<br />

A seconda della scelta della funzione peso w e dell’intervallo [a,b] abbiamo <strong>di</strong>verse formule <strong>di</strong> Gauss.<br />

Dimostrazione.<br />

[del teorema <strong>di</strong> W. Gautschi]<br />

Dimostriamo che se d = n + k allora sono vere la (a) e la (b) (necessità). Essendo d = n + k<br />

la formula è esatta anche per polinomi <strong>di</strong> grado n: abbiamo <strong>di</strong>mostrato il punto (a).<br />

Se p è un polinomio <strong>di</strong> grado al più k − 1, allora F (x)p(x) è un polinomio (perchè prodotto<br />

<strong>di</strong> due polinomi) <strong>di</strong> grado al più n + 1 + k − 1 = n + k. Applichiamo a questo polinomio<br />

prodotto la formula <strong>di</strong> quadratura (che è esatta valendo l’ipotesi che d = n + k, quin<strong>di</strong><br />

E i nt (F (x)p(x)) = 0). Quin<strong>di</strong><br />

∫ b<br />

n∑<br />

F (x)p(x)w(x) d x = F (x i )p(x i )w i .<br />

a<br />

i=0<br />

Ma F (x i ) = 0 essendo F il polinomio dei no<strong>di</strong>. Perciò ∑ n<br />

i=0 F (x i )p(x i )w i = 0<br />

5 Per definizione, infatti, due funzioni u e v si <strong>di</strong>cono ortogonali rispetto alla funzione peso w (positiva), se ∫ b<br />

a u(x)v(x)w(x) d x = 0.<br />

139


9. INTEGRAZIONE NUMERICA<br />

Di conseguenza ∫ b<br />

a F (x)p(x)w(x) d x = ∑ n<br />

i=0 F (x i )p(x i )w i = 0 e quin<strong>di</strong> il punto (b) è provato.<br />

Supponiamo ora che siano vere le con<strong>di</strong>zioni (a) e (b) e <strong>di</strong>mostriamo che d = n + k (sufficienza). Sia p un<br />

polinomio <strong>di</strong> grado n +k. Dobbiamo provare che E i nt (p) = 0. Divi<strong>di</strong>amo il polinomio p per il polinomio F :<br />

possiamo scrivere p(x) = F (x)q(x)+r (x) dove q(x) (quoziente) è un polinomio <strong>di</strong> grado k −1 e r (x) (resto) è<br />

un polinomio <strong>di</strong> grado n. Nel fare l’integrale, abbiamo<br />

∫ b<br />

a<br />

p(x)w(x) d x =<br />

∫ b<br />

a<br />

q(x)F (x)w(x) d x +<br />

∫ b<br />

a<br />

r (x)w(x) d x<br />

Il primo integrale a secondo membro vale zero a motivo dell’ipotesi (b) (q(x) è un polinomio <strong>di</strong> grado k − 1<br />

e quin<strong>di</strong> quell’integrale è zero). Il secondo integrale, invece, per la (a) può essere calcolato esattamente<br />

andando ad applicare la formula <strong>di</strong> quadratura (essendo r <strong>di</strong> grado n ed essendo la formula interpolatoria<br />

si ha E i nt (r ) = 0 ). Si ha<br />

∫ b<br />

∫ b<br />

n∑<br />

p(x)w(x) d x = r (x)w(x) d x = r (x i )w i<br />

a<br />

a<br />

Ma r (x i ) = p(x i ) − q(x i )F (x i ) = p(x i ) (essendo F (x i ) = 0). Quin<strong>di</strong><br />

∫ b<br />

∫ b<br />

n∑<br />

p(x)w(x) d x = r (x)w(x) d x = p(x i )w i<br />

a<br />

a<br />

i=0<br />

i=1<br />

L’errore è dunque zero e la <strong>di</strong>mostrazione è completata. ✔<br />

Da un punto <strong>di</strong> vista teorico la con<strong>di</strong>zione (a) del teorema permette <strong>di</strong> calcolare i pesi delle formule <strong>di</strong> Gauss:<br />

essendo la formula interpolatoria si ha w i = ∫ b<br />

a L i (x)w(x) d x.<br />

La con<strong>di</strong>zione (b) permette <strong>di</strong> calcolare i no<strong>di</strong> x i della formula (imponendo l’ortogonalità tra F (x) e i<br />

polinomi <strong>di</strong> grado k = 0,1,2,...,n si ricava un sistema <strong>di</strong> n + 1 equazioni nelle incognite dei coefficienti<br />

del polinomio F (x). Una volta trovato il polinomio F (x) ricaviamo le ra<strong>di</strong>ci, che sono appunti i no<strong>di</strong> <strong>di</strong><br />

integrazione 6 .<br />

9.7.1 Proprietà delle formule <strong>di</strong> Gauss<br />

Scriviamo le formule <strong>di</strong> Gauss con la notazione<br />

∫ b<br />

a<br />

f (x)w(x) d x =<br />

n∑<br />

w i f (x i ) + E G i nt (f )<br />

i=0<br />

Si ha E G (f ) ≡ 0 per f polinomio <strong>di</strong> grado ≤ 2n + 1<br />

i nt I no<strong>di</strong> x i sono reali, <strong>di</strong>stinti e contenuti nell’intervallo aperto ]a,b[.<br />

G I pesi w i sono tutti positivi.<br />

Infatti, per j = 0,1,...n si ha 0 < ∫ b<br />

a (L j (x)) 2 w(x) d x = ∑ n<br />

i=0 w i (L j (x i )) 2<br />

(l’errore è nullo perchè (L j (x)) 2 è un polinomio <strong>di</strong> grado 2n). Ma L j (x i ) = 0 se i ≠ j e L j (x i ) = 1 se i = j .<br />

Quin<strong>di</strong> ∑ n<br />

i=0 w i (L j (x i )) 2 = w j . Abbiamo provato che i pesi sono positivi.<br />

Le formule <strong>di</strong> Gauss si possono ricavare me<strong>di</strong>ante interpolazione (detta <strong>di</strong> Hermite) sui no<strong>di</strong> x i contati<br />

ciascuno come nodo doppio nel senso che su ciascun nodo imponiamo la con<strong>di</strong>zione <strong>di</strong> interpolazione non<br />

solo sulla f ma anche sulla derivata prima della f . Una volta che abbiamo ricavato il polinomio <strong>di</strong> interpolazione<br />

p(x) (che interpola quin<strong>di</strong> per ogni nodo sia la f sia la f ′ ) e approssimato ∫ b<br />

f (x)w(x) d x me<strong>di</strong>ante<br />

∫ b<br />

a<br />

p(x)w(x) d x, dalla formula che ricaviamo imponiamo che i termini che contengono la derivata prima<br />

siano uguali a zero (questa osservazione è dovuta a Markov, matematico russo, nel 1885).<br />

La formula che otteniamo (considerando che il polinomio interpola la f e la f ′ ) avrà termini del tipo:<br />

∫ b<br />

a f (x)w(x) d x = ∑ n<br />

i=0 w i f (x i ) + ∑ n<br />

i=0 C i f ′ (x i ) + E G i nt (x)<br />

6 Ricor<strong>di</strong>amo che un polinomio <strong>di</strong> grado n + 1 lo possiamo scrivere come a n+1 x n+1 + a n x n + ··· + a 0 ma possiamo anche <strong>di</strong>videre<br />

per il coefficiente <strong>di</strong> grado massimo e scriverlo in forma cosiddetta monica x n+1 + b n x n + b n−1 x n−1 + ... + b 0 , e avere quin<strong>di</strong> solo n + 1<br />

coefficienti (b 0 , b 1 , . . . , b n ) : le ra<strong>di</strong>ci dei due polinomi non cambiano.<br />

a<br />

140


9.7. Introduzione alle formule <strong>di</strong> quadratura <strong>di</strong> Gauss<br />

Imponendo C i = 0 i = 0,1,2,...n, otteniamo n + 1 con<strong>di</strong>zioni che ci permettono <strong>di</strong> ricavare i valori <strong>di</strong> x i (i<br />

no<strong>di</strong> <strong>di</strong> integrazione della formula). Possiamo poi ricavare il valore dei pesi w i (che <strong>di</strong>pendono a loro volta dai<br />

no<strong>di</strong>). Nel procedere con l’interpolazione sui valori della f e della f ′ , l’errore del polinomio <strong>di</strong> interpolazione<br />

si può scrivere come E = (F (x)) 2 f (2(n+1)) (ξ x )<br />

(poichè ogni nodo è contato due volte, e supponendo che la f<br />

(2(n + 1))!<br />

sia derivabile 2(n + 1) volte e sia continua).<br />

Di conseguenza, l’errore nella formula <strong>di</strong> integrazione (applicando il teorema del Valor Me<strong>di</strong>o in quanto<br />

(F (x)) 2 w(x) non cambia segno nell’intervallo <strong>di</strong> integrazione) si può scrivere come E G i nt<br />

E G i nt (x) = f (2(n+1)) (ξ)<br />

(2(n + 1))!<br />

∫ b<br />

a<br />

(F (x)) 2 w(x) d x<br />

9.7.2 Formule <strong>di</strong> Gauss-Legendre<br />

A seconda della funzione peso, si ha una particolare formula <strong>di</strong> Gauss.<br />

In genere i no<strong>di</strong> <strong>di</strong> integrazione sono calcolati su intervalli “canonici” (spetta a noi fare il cambio <strong>di</strong><br />

variabili se l’integrale è da farsi su altri intervalli).<br />

Per w(x) ≡ 1 e [a,b] ≡ [−1,1] si ha la formula <strong>di</strong> Gauss-Legendre.<br />

I no<strong>di</strong> della formula <strong>di</strong> quadratura, sono le ra<strong>di</strong>ci dei cosiddetti polinomi <strong>di</strong> Legendre.<br />

n + 1 no<strong>di</strong> pesi<br />

2 x 0,1 = ±0.57735026918962576 w 0 = w 1 = 1.0<br />

3 x 0 = −0.77459666924148338 w 0 = 5/9 = 0.5555555556<br />

x 1 = 0 w 1 = 8/9 = 0.8888888889<br />

x 2 = 0.77459666924148338 w 2 = 5/9 = 0.5555555556<br />

4 x 0 = −0.86113631159405257 w 0 = 0.3478548451374538<br />

x 1 = −0.33998104358485626 w 1 = 0.6521451548625461<br />

x 2 = 0.33998104358485626 w 2 = 0.6521451548625461<br />

x 3 = 0.86113631159405257 w 3 = 0.3478548451374538<br />

I polinomi <strong>di</strong> Legendre (e, come essi, anche tutti gli altri polinomi le cui ra<strong>di</strong>ci sono i no<strong>di</strong> delle altre<br />

formule <strong>di</strong> Gauss) hanno la caratteristica <strong>di</strong> essere polinomi mutuamente ortogonali (nel senso che presi<br />

due polinomi <strong>di</strong> Legendre, che chiamiamo ω n (x) e ω m (x), rispettivamente <strong>di</strong> grado n e m, con n ≠ m, si ha<br />

∫ b<br />

a ω n(x)ω m (x)w(x) d x = 0).<br />

I polinomi <strong>di</strong> Legendre (e, come essi, i polinomi delle altre formule <strong>di</strong> Gauss), si ricavano me<strong>di</strong>ante formule<br />

ricorsive, cioè ogni polinomio <strong>di</strong> Legendre <strong>di</strong> grado n è legato (me<strong>di</strong>ante una relazione opportuna) ai<br />

polinomi <strong>di</strong> Legendre <strong>di</strong> grado n − 1 e n − 2.<br />

9.7.3 Altre formule <strong>di</strong> Gauss<br />

1<br />

G Con w(x) = √ e [a,b] = [−1,1] si hanno le formule <strong>di</strong> Gauss-Chebychev (prima specie) in<br />

(1 − x 2 )<br />

quanto i no<strong>di</strong> <strong>di</strong> integrazione sono le ra<strong>di</strong>ci dei cosiddetti polinomi <strong>di</strong> Chebychev <strong>di</strong> prima specie.<br />

G Con w(x) = √ (1 − x 2 ) e [a,b] = [−1,1] si hanno le formule <strong>di</strong> Gauss-Chebychev (seconda specie) in<br />

quanto i no<strong>di</strong> <strong>di</strong> integrazione sono le ra<strong>di</strong>ci dei cosiddetti polinomi <strong>di</strong> Chebychev <strong>di</strong> seconda specie.<br />

G Con w(x) = (1 − x) α (1 + x) β (per α > −1 e β > −1) e [a,b] = [−1,1] si hanno le formule <strong>di</strong> Gauss-Jacobi.<br />

G Con w(x) = x α e −x (per α > −1) e [a,b] = [0,+∞] si hanno le formule <strong>di</strong> Gauss-Laguerre.<br />

G Con w(x) = e −x2 e [a,b] = [−∞,+∞] si hanno le formule <strong>di</strong> Gauss-Hermite.<br />

141


9. INTEGRAZIONE NUMERICA<br />

Figura 9.5: Funzioni peso per le formule <strong>di</strong> quadratura <strong>di</strong> Gauss-Chebycev <strong>di</strong> prima e seconda specie (a<br />

sinistra e a destra rispettivamente)<br />

Figura 9.6: Funzioni peso per le formule <strong>di</strong> quadratura <strong>di</strong> Gauss-Jacobi (con α = 2 e β = 4) e <strong>di</strong> Gauss-Laguerre<br />

(con α = 2) (a sinistra e a destra rispettivamente)<br />

Figura 9.7: Funzione peso per le formula <strong>di</strong> quadratura <strong>di</strong> Gauss-Hermite.<br />

9.7.4 Applicazione delle formule<br />

Supponiamo <strong>di</strong> voler approssimare un integrale utilizzando le formule <strong>di</strong> Gauss-Legendre, ma in un<br />

intervallo <strong>di</strong>verso da [−1,1].<br />

Dobbiamo fare un cambio <strong>di</strong> variabili. Da ∫ b<br />

a f (x) d x dobbiamo passare a ∫ 1<br />

−1<br />

f (t) d t.<br />

Poniamo x = b − a<br />

2 t + b + a<br />

2<br />

Per t = −1 si ha x = b − a<br />

2 (−1) + b + a = −b + a + b + a = 2a = a. Quin<strong>di</strong> per t = −1, si ha x = a (il primo<br />

2<br />

2<br />

2<br />

estremo <strong>di</strong> un intervallo viene trasformato nel primo estremo dell’altro intervallo).<br />

Per t = 1 si ha x = b − a<br />

2 (1) + b + a = b − a + b + a = 2b 2<br />

2 2 = b.<br />

Perciò, per t = 1, si ha x = b.<br />

Inoltre d x = b − a d t. Con la trasformazione <strong>di</strong> variabili si ha:<br />

2<br />

∫ b<br />

∫ 1<br />

( b − a<br />

f (x) d x = f<br />

a<br />

−1 2 t + b + a ) b − a<br />

d t<br />

2 2<br />

142


9.8. <strong>Esercizi</strong><br />

Applicando la formula <strong>di</strong> Gauss-Legendre<br />

∫ b<br />

a<br />

f (x) d x ≈ b − a<br />

2<br />

n∑<br />

w G i<br />

i=0<br />

f ( b − a<br />

2 x i + b + a<br />

2 )<br />

9.7.5 Sulla funzione peso<br />

Supponiamo <strong>di</strong> voler integrare una funzione g (x) in [a,b] (intervallo finito). Supponiamo che la funzione<br />

integranda g abbia una singolarità algebrica agli estremi (con una certa molteplicità), in modo da poter<br />

scrivere g (x) = f (x)(b − x) α (x − a) β<br />

Adesso, facciamo un cambiamento <strong>di</strong> variabile, da [a,b] a [−1,1], considerando la trasformazione x =<br />

b − a<br />

2 t + b + a<br />

2 .<br />

Si ha (b − x) = b − a<br />

b − a<br />

(1 − t) e (x − a) = (1 + t).<br />

2 2<br />

Allora<br />

∫ b<br />

a g (x) d x = b − a<br />

∫ 1<br />

−1 f ( b − a<br />

) α ( ) b − a β<br />

(1 − t) α (1 + t) β d t<br />

2<br />

2<br />

2 t + b + a ( b − a<br />

2 ) 2<br />

( ) b − a α+β+1<br />

∫ 1<br />

=<br />

−1<br />

2<br />

f ( b − a<br />

2 t + b + a<br />

2 )(1 − t)α (1 + t) β d t<br />

Posso applicare le formule <strong>di</strong> Gauss-Jacobi e “scaricare” sulla funzione peso le singolarità della funzione<br />

<strong>di</strong> partenza.<br />

Sia dato l’integrale ∫ 1<br />

0 f (x)(1 − x)p d x con f regolare e p intero elevato: allora (1 − x) p è una funzione che<br />

ha valori vicini a zero. La funzione da integrare è quasi <strong>di</strong>scontinua e le formule classiche (Trapezi o Cavalieri-<br />

Simpson) non danno buoni risultati. Si può pensare a questo integrale come ad un integrale <strong>di</strong> tipo Jacobi (su<br />

cui applicare la formula <strong>di</strong> Gauss-Jacobi) con α = p e β = 0. Si fa l’opportuno passaggio <strong>di</strong> variabili in modo<br />

da integrare sull’intervallo [−1,1]. La formula <strong>di</strong> Gauss incorpora nella funzione peso la parte che riguarda<br />

(1 − x) p .<br />

9.8 <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 9.8.1 Sia dato l’integrale I =<br />

∫ 0<br />

−2<br />

e −x (x + 1) dx.<br />

(a) Approssimare il valore dell’integrale applicando la formula dei trapezi con n = 5 sud<strong>di</strong>visioni in parti<br />

uguali dell’intervallo <strong>di</strong> integrazione.<br />

(b) Trovare una maggiorazione dell’errore commesso e, dopo aver calcolato analiticamente l’integrale<br />

esatto, confrontare tale stima con l’errore esatto.<br />

Svolgimento<br />

(a) Applichiamo la formula dei trapezi con n = 5 sud<strong>di</strong>visioni dell’intervallo dato. Vale, dunque, h = 0.4. I<br />

punti da considerare e il valore della f (x) = e −x (x + 1), sono:<br />

i x i f (x i )<br />

0 -2 -7.3890561<br />

1 -1.6 -2.97181945<br />

2 -1.2 -0.664023385<br />

3 -0.8 0.445108186<br />

4 -0.4 0.895094819<br />

5 0 1<br />

143


9. INTEGRAZIONE NUMERICA<br />

La formula dei trapezi è<br />

I tr ap = h( f (x 0) + f (x 5 )<br />

+ f (x 1 ) + f (x 2 ) + f (x 3 ) + f (x 4 )) = −2.19606715<br />

2<br />

(b) Per calcolare una maggiorazione dell’errore commesso, dobbiamo calcolare la derivata seconda della<br />

f .<br />

Da f (x) = e −x (x + 1) segue f ′ (x) = −e −x (x + 1) + e −x = −e −x x e f ′′ (x) = e −x x − e −x = e −x (x − 1).<br />

Poichè f ′′ (x) è sempre negativa nell’intervallo <strong>di</strong> integrazione e a noi interessa la funzione valore<br />

assoluto della f ′′ (x), stu<strong>di</strong>amo la funzione g (x) = |f ′′ (x)| = e −x (1 − x). Si ha che g ′ (x) = e −x (x − 2) < 0<br />

in [−2,0], quin<strong>di</strong> g è decrescente e ha valore massimo per x = −2. Si ha dunque che M = max|f ′′ (x)| =<br />

|f ′′ (−2)| = 22.1671682968<br />

Quin<strong>di</strong> |E tr ap | ≤ M |(b − a)3 |<br />

12 · 5 2 = 0.591124488<br />

Analiticamente, è facile calcolare l’integrale esatto (per parti):<br />

∫ 0<br />

∫ 0<br />

I = f (x) dx = −e −x (x + 1)| 0 −2 + e −x dx = −e −x (x + 2)| 0 −2 = −2<br />

−2<br />

−2<br />

Quin<strong>di</strong> l’errore esatto, in valore assoluto, è:<br />

maggiorazione trovata prima.<br />

|I − I tr ap | = 0.196067154, un valore minore della<br />

<strong>Esercizi</strong>o 9.8.2 Sia dato l’integrale<br />

∫ 2<br />

2<br />

0 x − 4 d x<br />

(a) Dare una sua approssimazione con la formula dei trapezi e n = 4 sud<strong>di</strong>visioni in parti uguali<br />

dell’intervallo <strong>di</strong> integrazione.<br />

(b) Trovare una maggiorazione dell’errore commesso.<br />

(c) Confrontare l’errore esatto con la stima precedentemente trovata.<br />

(d) Dire in quanti sottointervalli occorre sud<strong>di</strong>videre l’intervallo <strong>di</strong> integrazione per ottenere una<br />

maggiorazione dell’errore minore della tolleranza ɛ = 10 −5 .<br />

Svolgimento<br />

(a) Sud<strong>di</strong>videndo l’intervallo <strong>di</strong> integrazione [0,2] in n = 4 parti si trova un passo h = 2/4 = 1/2 = 0.5.<br />

La formula dei trapezi è:<br />

I T = b − a f (a) + f (b)<br />

( + f (x 1 ) + f (x 2 ) + f (x 3 ))<br />

n 2<br />

f (0) + f (2)<br />

= 0.5( + f (0.5) + f (1) + f (1.5))<br />

2<br />

= 0.5( −0.5 − 1 − 0.571428571 − 0.666666667 − 0.8)<br />

2<br />

= −1.39404762<br />

(b) Consideriamo la formula dell’errore: E = − f ′′ (ξ) (b − a) 3<br />

12 n 2<br />

Da f (x) = 2<br />

x − 4 segue f ′ (x) =<br />

−2<br />

(x − 4) 2 e f ′′ 4<br />

(x) =<br />

(x − 4) 3 .<br />

Per maggiorare l’errore dobbiamo considerare che vale<br />

|E| ≤ max 0≤x≤2 |f ′′ (x)| (b − a) 3<br />

12<br />

n 2 , da cui dobbiamo calcolare M = max 0≤x≤2 |f ′′ (x)|.<br />

144


9.8. <strong>Esercizi</strong><br />

La funzione (x −4) 3 4<br />

è continua, crescente e sempre negativa nell’intervallo [0,2]. Quin<strong>di</strong> |<br />

(x − 4) 3 | =<br />

4<br />

(4 − x) 3 : osserviamo il cambiamento al denominatore. Poniamo g (x) = 4<br />

(4 − x) 3 . Risulta g ′ (x) =<br />

12<br />

(4 − x) 4 > in [0,2], quin<strong>di</strong> la g è crescente e ha valore massimo per x = 2. Perciò M = max 0≤x≤2 |f ′′ (x)| =<br />

|f ′′ (2)| = 4 2 3 = 1/2 = 0.5. Si ha allora la maggiorazione dell’errore |E| ≤ M 12<br />

(c) L’integrale esatto si calcola facilmente:<br />

2 3<br />

4 2 = 1<br />

48 = 0.0208333333<br />

∫ 2<br />

I =<br />

0<br />

2<br />

x − 4 d x = 2ln(|x − 4|)|2 0 = 2ln(| − 2|) − 2ln(| − 4|) = 2ln(1/2) = ln(1/4) − 1.386294361<br />

L’errore esatto commesso con la formula dei trapezi, in valore assoluto, è |I − I T | = 0.00775325793<br />

(d) Perchè la maggiorazione dell’errore sia minore della tolleranza ɛ = 10 −5 deve essere |E| ≤ M 12 n 2 ≤ 10−5<br />

cioè n 2 ≥ M 12 23 10 5 = 105 = 33333.333333. Quin<strong>di</strong> n > 182.574186, vale a <strong>di</strong>re n = 183.<br />

3<br />

2 3<br />

<strong>Esercizi</strong>o 9.8.3 Dato l’integrale<br />

∫ 0.5<br />

1<br />

I = d x<br />

1 − x<br />

2<br />

0<br />

(a) si approssimi I con i valori Q 1 e Q 2 ottenuti applicando il metodo <strong>di</strong> Cavalieri-Simpson prima a tutto<br />

l’intervallo e poi sud<strong>di</strong>videndo l’intervallo in due parti uguali;<br />

(b) si approssimi I usando la formula <strong>di</strong> estrapolazione <strong>di</strong> Richardson;<br />

(c) dopo aver calcolato analiticamente il valore esatto <strong>di</strong> I , determinare l’errore esatto commesso con<br />

l’estrapolazione <strong>di</strong> Richardson.<br />

Svolgimento<br />

(a) Applichiamo la formula <strong>di</strong> Cavalieri-Simpson su tutto l’intervallo, considerando che l’ampiezza<br />

dell’intervallo è b − a = 0.5 e h = 0.25<br />

Q 1 = 0.25 (f (0) + 4f (0.25) + f (0.5)) = 0.523823565<br />

3<br />

Si ha, infatti, f (0) = 1, f (0.25) = 1.03279556 e f (0.5) = 1.15470054.<br />

Sud<strong>di</strong>videndo l’intervallo in due parti uguali, abbiamo h = 0.125, da cui i punti: x 0 = a = 0, x 1 =<br />

0.125, x 2 = 0.25, x 3 = 0.375, e x 4 = b = 0.5.<br />

Q 2 = h 3 (f (x 0) + 4(f (x 1 ) + 4f (x 3 )) + 2f (x 2 ) + f (x 4 )) = 0.523616326<br />

dove f (0.125) = 1.00790526, f (0.375) = 1.07871978 (essendo già in possesso <strong>degli</strong> altri valori, calcolati<br />

per Q 1 )<br />

(b) La formula <strong>di</strong> estrapolazione <strong>di</strong> Richardson è: Q 3 = Q 2 + Q 2 −Q 1<br />

da cui ricaviamo Q 3 = 0.5236025101<br />

15<br />

(c) Analiticamente l’integrale esatto è:<br />

∫ 0.5<br />

1<br />

I = d x =<br />

0 1 − x<br />

2 arcsin(x)|0.5 0 = π/6 − 0 = 0.523598775<br />

L’errore esatto commesso con l’estrapolazione <strong>di</strong> Richardson, in valore assoluto, è: |I −Q 3 | = 3.7351·<br />

10 −6 .<br />

145


9. INTEGRAZIONE NUMERICA<br />

<strong>Esercizi</strong>o 9.8.4 Si calcoli I = ∫ 5<br />

2 sin( x) d x utilizzando il metodo <strong>di</strong> Gauss-Legendre con 3 punti <strong>di</strong><br />

appoggio (x 1 = − (3/5), x 2 = 0, x 3 = (3/5); w 1 = w 3 = 5/9, w 1 = 8/9).<br />

Svolgimento<br />

Applichiamo la formula, ricordandoci che dobbiamo utilizzarla non in [2,5] ma in [−1,1]. Considerando<br />

che la trasformazione dall’intervallo [2,5] all’intervallo [−1,1] porta al cambiamento <strong>di</strong> variabili x = b − a<br />

2 t +<br />

b + a<br />

= 5 − 2<br />

2 2 t + 5 + 2 = 3 2 2 t + 7 2 si ha d x = 3 d t. La formula <strong>di</strong> Gauss-Legendre deve essere applicata sui no<strong>di</strong><br />

2<br />

trasformati dati da 3 2 x i + 7 . Perciò abbiamo<br />

2<br />

I G = 3 (w 1 f ( 3 2 2 x 1 + 7 2 ) + w 2 f ( 3 2 x 2 + 7 2 ) + w 3 f ( 3 2 x 3 + 7 )<br />

2 )<br />

= 1.5 ( (5/9)f (−1.161895004 + 3.5) + (8/9)f (3.5) + (5/9)f (1.161895004 + 3.5) )<br />

= 1.5(0.5550723689 + 0.8491794877 + 0.4621443545) = 2.799594317<br />

146


C A P I T O L O<br />

10<br />

EQUAZIONI ALLE DERIVATE ORDINARIE<br />

L’universo è un’equazione<br />

<strong>di</strong>fferenziale.<br />

Jules Henri Poincarè<br />

10.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />

10.2 Sulle equazioni <strong>di</strong>fferenziali or<strong>di</strong>narie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />

10.3 Metodo <strong>di</strong> Eulero esplicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149<br />

10.4 Metodo <strong>di</strong> Eulero implicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151<br />

10.5 Metodo <strong>di</strong> Crank-Nicolson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154<br />

10.6 Stu<strong>di</strong>o dell’errore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155<br />

10.7 Errori <strong>di</strong> troncamento locale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155<br />

10.8 Convergenza e stabilità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

10.8.1 Convergenza <strong>di</strong> Eulero esplicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

10.8.2 Stabilità <strong>di</strong> Eulero esplicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157<br />

10.8.3 Convergenza <strong>di</strong> Eulero implicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157<br />

10.8.4 Stabilità <strong>di</strong> Eulero implicito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

10.8.5 Convergenza <strong>di</strong> Crank-Nicolson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

10.8.6 Stabilità <strong>di</strong> Crank-Nicolson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159<br />

10.8.7 Sulla stabilità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159<br />

10.9 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />

10.1 Introduzione<br />

All’inizio del ’900, van der Pol 1 stu<strong>di</strong>ò fenomeni non lineari e propose l’equazione <strong>di</strong>fferenziale<br />

1 Balthasar van der Pol (1889-1959) fu un fisico e matematico olandese. Nel 1916 lavorò per un anno con l’ingegnere John Ambrose<br />

Fleming a Londra (Fleming aveva già inventato il <strong>di</strong>odo nel 1904). Si trasferì successivamente a Cambridge e iniziò una collaborazione<br />

con John Joseph Thomson al Caven<strong>di</strong>sh Laboratory (Thomson aveva scoperto l’elettrone nel 1897). Qui <strong>di</strong>venne amico <strong>di</strong> Edward Appleton<br />

che, nel 1947, ricevette il premio Nobel per la fisica per i suoi contributi alla conoscenza della ionosfera – stu<strong>di</strong> fatti insieme a<br />

van der Pol. La loro collaborazione riguardò anche lo stu<strong>di</strong>o <strong>di</strong> fenomeni non lineari usando circuiti trio<strong>di</strong> per verificare le loro teorie.<br />

Quando van del Pol rientrò in Olanda, continuò a occuparsi <strong>di</strong> ottica, elettromagnetismo, onde ra<strong>di</strong>o e fisica atomica. Il nome <strong>di</strong> van<br />

der Pol è associato con l’equazione <strong>di</strong>fferenziale che porta il suo nome. Questa equazione apparve per la prima volta sul suo articolo On<br />

relaxation oscillation pubblicato sulla rivista Philosophical Magazine nel 1926.<br />

147


10. EQUAZIONI ALLE DERIVATE ORDINARIE<br />

y ′′ (t) + ɛ(y 2 (t) − 1)y ′ (t) + y(t) = 0<br />

Questa equazione governa l’intensità <strong>di</strong> corrente in un circuito oscillante a triodo e viene utilizzata nello<br />

stu<strong>di</strong>o <strong>di</strong> circuiti che contengono valvole termoioniche, i cosiddetti tubi a vuoto, come il tubo cato<strong>di</strong>co del<br />

televisore o il magnetron nei forni a microonde. La quantità ɛ in<strong>di</strong>ca l’intensità dello smorzamento non<br />

lineare: quanto più ɛ è elevato tanto più il sistema perde energia rapidamente.<br />

L’equazione <strong>di</strong>fferenziale del secondo or<strong>di</strong>ne si può ricondurre ad un sistema <strong>di</strong> equazioni <strong>di</strong>fferenziali<br />

del primo or<strong>di</strong>ne. Ponendo u = (u 1 ,u 2 ) = (y, y ′ ) si ha<br />

( u<br />

′<br />

) (<br />

)<br />

1<br />

u 2<br />

=<br />

−ɛ((u 1 ) 2 − 1)u 2 − u 1<br />

u ′ 2<br />

Come si risolve numericamente un sistema <strong>di</strong> equazioni <strong>di</strong>fferenziali come quello appena scritto? In<br />

questo Capitolo, daremo una piccola introduzione a meto<strong>di</strong> numerici che permettono <strong>di</strong> risolvere equazioni<br />

<strong>di</strong>fferenziali del primo or<strong>di</strong>ne.<br />

10.2 Sulle equazioni <strong>di</strong>fferenziali or<strong>di</strong>narie<br />

Vogliamo trovare una funzione y(t) che sod<strong>di</strong>sfi la seguente equazione <strong>di</strong>fferenziale or<strong>di</strong>naria ( ODE:<br />

Or<strong>di</strong>nary Differential Equation) del primo or<strong>di</strong>ne:<br />

dy<br />

= f (t, y),<br />

dt a<br />

≤ t ≤ b<br />

La funzione f (t, y) è assegnata. Ci riferiamo a t come alla variabile in<strong>di</strong>pendente. Dobbiamo trovare quella<br />

funzione y = y(t) tale che la sua derivata prima y ′ = y ′ (t) = dy(t) coincida con f (t, y(t)).<br />

dt<br />

Esempio 10.2.1 Sia f (t, y) = −y + t definita per t ≥ 0 e per qualunque y reale. Si ha<br />

y ′ = −y + t, t ≥ 0<br />

Si verifica che, per qualunque scalare α la funzione y(t) = t − 1 + αe −t sod<strong>di</strong>sfa la ODE.<br />

Se, inoltre, è assegnato un valore iniziale, per esempio y(0) = 1, allora, dovendo essere −1 + α = y(0) = 1,<br />

risulta α = 2. Assegnare una soluzione iniziale determina un’unica soluzione all’ODE. Si parla <strong>di</strong> problema<br />

a valori iniziali (IVP).<br />

Nel caso in cui y(0) = 1 si ricava l’unica soluzione y(t) = t − 1 + 2e −t .<br />

Problemi in cui abbiamo equazioni alle derivate or<strong>di</strong>narie <strong>di</strong> or<strong>di</strong>ne più elevato possono essere trasformati<br />

in sistemi equivalenti <strong>di</strong> equazioni del primo or<strong>di</strong>ne.<br />

Esempio 10.2.2 La seconda legge del moto <strong>di</strong> Newton <strong>di</strong>ce che la forza F è uguale al prodotto della massa<br />

m per l’accelerazione a: F = ma. Questa equazione è una ODE del secondo or<strong>di</strong>ne in quanto l’accelerazione<br />

a è data da a = y ′′ , dove y è la coor<strong>di</strong>nata della posizione. L’ODE può essere riscritta come:<br />

y ′′ = F /m<br />

Definendo u 1 = y e u 2 = y ′ si ha il sistema (equivalente all’equazione <strong>di</strong> prima) <strong>di</strong> due equazioni del primo<br />

or<strong>di</strong>ne <strong>di</strong> ODE: ( u<br />

′<br />

) ( )<br />

1<br />

u2<br />

u<br />

2<br />

′ =<br />

F /m<br />

Per risolvere il sistema, possiamo usare meto<strong>di</strong> che vanno bene per risolvere equazioni <strong>di</strong>fferenziali del primo<br />

or<strong>di</strong>ne. La prima componente della soluzione u 1 corrisponde alla posizione y dell’equazione da cui<br />

siamo partiti. La seconda componente u 2 fornisce la velocità y ′ .<br />

148


10.3. Metodo <strong>di</strong> Eulero esplicito<br />

Sistemi del primo or<strong>di</strong>ne <strong>di</strong> ODE hanno la forma<br />

Sistemi <strong>di</strong><br />

ODE<br />

y ′ (t) = f(t,y)<br />

dove y : R −→ R n con y = (y 1 y 2 ... y n ), f : R n+1 −→ R n e y ′ (t) = dy<br />

d t<br />

denota la derivata rispetto a t (per cui la<br />

i -sima componente del vettore derivata è data da y ′ i (t) = d y i (t)<br />

). La funzione f è assegnata e noi vogliamo<br />

d t<br />

determinare il vettore <strong>di</strong> funzioni y che sod<strong>di</strong>sfa l’ODE.<br />

Per semplicità noi stu<strong>di</strong>eremo il caso <strong>di</strong> una singola equazione scalare, n = 1. Ma l’approccio è del tutto<br />

simile nel caso <strong>di</strong> sistemi <strong>di</strong> equazioni del primo or<strong>di</strong>ne.<br />

Sia data l’ODE<br />

y ′ = f (t, y(t))<br />

a ≤ t ≤ b<br />

con valore iniziale<br />

y(a) = y a .<br />

Per risolvere questa ODE <strong>di</strong>scretizziamo l’intervallo [a,b] in n + 1 punti, equi<strong>di</strong>stanti per semplicità: t i =<br />

a + i h, h = 0,1,...,n, con h = (b − a)/n.<br />

Il passo <strong>di</strong> <strong>di</strong>scretizzazione (temporale se t assume il significato della variabile temporale) è dunque h.<br />

Nelle applicazioni pratiche, il passo h è variabile (cioè i punti non sono equi<strong>di</strong>stanti), tuttavia, per capire<br />

meglio come funzionano i meto<strong>di</strong>, noi useremo sempre un passo h costante.<br />

Sia y(t) la soluzione esatta del nostro problema a valori iniziali. Allora y(t i ) è il valore esatto della<br />

soluzione calcolata nel punto t i .<br />

In<strong>di</strong>chiamo invece con y i il valore approssimato al tempo t i che ricaviamo applicando un metodo<br />

numerico che risolve il problema proposto.<br />

10.3 Metodo <strong>di</strong> Eulero esplicito<br />

Con il metodo <strong>di</strong> Eulero 2 esplicito applichiamo la formula <strong>di</strong> Taylor (del secondo or<strong>di</strong>ne) alla funzione<br />

y(t), <strong>di</strong> centro t i , in modo da poter successivamente approssimare la derivata prima y ′ (t i ):<br />

y(t) = y(t i ) + (t − t i )y ′ (t i ) + (t − t i ) 2<br />

y ′′ (ξ i )<br />

2<br />

La quantità (t − t i ) 2<br />

y ′′ (ξ i ) è il resto della formula <strong>di</strong> Taylor con ξ i un punto opportuno nel segmento <strong>di</strong><br />

2<br />

estremi t e t i .<br />

Pren<strong>di</strong>amo come t il valore t i + h vale a <strong>di</strong>re t i+1 , da cui si ha t − t i = t i+1 − t i = h. Sostituendo si ottiene:<br />

y(t i+1 ) = y(t i ) + hy ′ (t i ) + h2<br />

2 y′′ (ξ i )<br />

Esplicitando y ′ (t i ) rispetto agli altri termini si ha:<br />

y ′ (t i ) = y(t i+1) − y(t i )<br />

− h h 2 y′′ (ξ i )<br />

Ora si sostituisce il valore trovato per y ′ (t i ) nella ODE y ′ = f (t, y(t)) per t = t i :<br />

y(t i+1 ) − y(t i )<br />

− h h 2 y′′ (ξ i ) = f (t i , y(t i ))<br />

2 Leonhard Euler (1707-1783) fu un matematico svizzero. Fu studente <strong>di</strong> Johann Bernoulli che comprese le sue gran<strong>di</strong> potenzialità<br />

e favorì i suoi stu<strong>di</strong>. Eulero è noto soprattutto per i suoi contributi nel campo della geometria, della teoria dei numeri, delle equazioni<br />

<strong>di</strong>fferenziali, del calcolo delle variazioni. È lui che introdusse il simbolo f (x) per in<strong>di</strong>care le funzioni, e per la base naturale, i per la<br />

ra<strong>di</strong>ce quadrata <strong>di</strong> −1, <strong>di</strong> π, il simbolo <strong>di</strong> sommatoria ∑ e altri ancora.<br />

149


10. EQUAZIONI ALLE DERIVATE ORDINARIE<br />

Trascurando il termine h 2 y′′ (ξ i ) non abbiamo più i valori della soluzione esatta, ma otterremo i valori della<br />

soluzione approssimata. Scriviamo dunque:<br />

y i+1 − y i<br />

h<br />

= f (t i , y i )<br />

La formula <strong>di</strong> Eulero esplicito è: y i+1 = y i + h f (t i , y i ).<br />

La formula è <strong>di</strong> tipo esplicito perchè per passare dal livello i al livello i + 1 sfruttiamo i dati che già<br />

conosciamo del livello i .<br />

Si parte infatti da y 0 = y(t 0 ) = y(a) = y a e si ricava:<br />

y 1 = y 0 + f (t 0 , y 0 )<br />

y 2 = y 1 + f (t 1 , y 1 )<br />

. = . . .<br />

Un altro<br />

approccio<br />

Si arriva alla stessa formula integrando l’ODE e approssimando l’integrale della f me<strong>di</strong>ante il valore in<br />

f (t 0 , y(t 0 )): da y ′ = f (t, y(t)) integrando ambo i membri da t 0 a t, otteniamo<br />

∫ t<br />

t 0<br />

∫<br />

d y<br />

t<br />

∫ y(t)<br />

d t d t = f (t, y(t)) d t =⇒ d y =<br />

t 0 y 0<br />

∫ t<br />

t 0<br />

f (t, y(t)) d t<br />

Al secondo membro, approssiamo ∫ t<br />

t 0<br />

f (t, y(t)) d t me<strong>di</strong>ante il valore (t − t 0 )f (t 0 , y(t 0 )) (approssimiamo la f<br />

me<strong>di</strong>ante la retta f (t 0 , y(t 0 ))).<br />

Abbiamo:<br />

y(t) = y 0 + (t − t 0 )f (t 0 , y 0 )) + errore della formula <strong>di</strong> quadratura.<br />

Per t = t 1 , numericamente: y 1 = y 0 + h f (t 0 , y 0 )).<br />

Ai passi successivi: y i+1 = y i + h f (t i , y i ))<br />

Esempio 10.3.1 Supponiamo <strong>di</strong> applicare il metodo <strong>di</strong> Eulero esplicito alla ODE y ′ = −y con passo h a<br />

partire dal punto iniziale t 0 = 0 e avanziamo al tempo t 1 = t 0 + h<br />

y 1 = y 0 + h f (t 0 , y 0 ) = y 0 − hy 0 = (1 − h)y 0<br />

Il valore y 1 che otteniamo è affetto da errore: y 1 ≠ y(t 1 ) Per esempio, se per t 0 si ha y 0 = 1, la soluzione esatta<br />

è y(t) = e −t . Per h = 0.5, si ha y 1 = 0.5 mentre y(0.5) = e −0.5 ≈ 0.60653<br />

Interpretazione<br />

geometrica<br />

Da un punto <strong>di</strong> vista geometrico (si veda la Figura 10.1), il valore in t i+1 è approssimato utilizzando il valore<br />

della retta la cui pendenza è data da f (t i , y i ): è come se ad ogni passo cercassimo <strong>di</strong> risolvere il problema a<br />

valori iniziali:<br />

y ′ (t) = f (t, y(t))<br />

y(t i ) = y i<br />

per cui il valore che otteniamo per il tempo t i+1 è tangente alla traiettoria della soluzione <strong>di</strong> questo IVP.<br />

150


10.4. Metodo <strong>di</strong> Eulero implicito<br />

Figura 10.1: Interpretazione geometrica del metodo <strong>di</strong> Eulero esplicito. Si è considerato il problema y ′ = −y<br />

con y(0) = 1 la cui soluzione esatta è y(t) = e −t . I valori numerici ottenuti dal metodo <strong>di</strong> Eulero esplicito sono<br />

cerchiati e si trovano sulla linea spezzata che li interpola. La linea spezzata è tangente, all’inizio <strong>di</strong> ogni passo,<br />

alla traiettoria che passa per il corrispondente punto, soluzione del problema y ′ = −y con y(t i ) = y i .<br />

10.4 Metodo <strong>di</strong> Eulero implicito<br />

Se applichiamo la formula <strong>di</strong> Taylor <strong>di</strong> punto iniziale t i+1 , abbiamo<br />

y(t) = y(t i+1 ) + (t − t i+1 )y ′ (t i+1 ) + (t − t i+1) 2<br />

y ′′ (ξ i )<br />

2<br />

Per t = t i , si ha t − t i+1 = t i − t i+1 = t i − (t i + h) = −h. Sostituendo, abbiamo:<br />

y(t i ) = y(t i+1 ) − hy ′ (t i+1 ) + h2<br />

2 y′′ (ξ i )<br />

Otteniamo quin<strong>di</strong><br />

y ′ (t i+1 ) = y(t i+1) − y(t i )<br />

+ h h 2 y′′ (ξ i )<br />

Andando a sostituire nella ODE al tempo t i+1 , si ha :<br />

y(t i+1 ) − y(t i )<br />

+ h h 2 y′′ (ξ i ) = f (t i+1 , y(t i+1 ))<br />

Trascurando il termine del resto <strong>di</strong> Taylor h 2 y′′ (ξ i ) abbiamo:<br />

y i+1 − y i<br />

h<br />

= f (t i+1 , y i+1 ))<br />

La formula <strong>di</strong> Eulero implicito vale y i+1 = y i + h f (t i+1 , y i+1 )).<br />

151


10. EQUAZIONI ALLE DERIVATE ORDINARIE<br />

La <strong>di</strong>fferenza rispetto alla formula esplicita è che la f è valutata non più al tempo t i ma al tempo t i+1 Quin<strong>di</strong><br />

il calcolo <strong>di</strong> y i+1 <strong>di</strong>pende implicitamente da y i+1 stesso! La valutazione <strong>di</strong> y i+1 <strong>di</strong>venta quin<strong>di</strong> più laboriosa<br />

e complicata (se si ha un’equazione non lineare in y i+1 , la si risolve tramite un metodo <strong>di</strong> punto fisso o <strong>di</strong><br />

Newton-Raphson). In termini <strong>di</strong> accuratezza si hanno risultati migliori.<br />

Esempio 10.4.1 Consideriamo sempre y ′ = −y con y(0) = 1 (soluzione esatta y(t) = e −t ).<br />

Il metodo <strong>di</strong> Eulero implicito <strong>di</strong>venta: y i+1 = y i − hy i+1 ovvero (1 + h)y i+1 = y i<br />

La soluzione numerica è y i+1 =<br />

y i<br />

(1 + h) .<br />

Per h = 0.5 ricaviamo y 1 = 0.66667 contro un valore esatto y(1) ≈ 0.60653.<br />

Esempio 10.4.2 Si abbia l’equazione y ′ = −y 3 con con<strong>di</strong>zione iniziale y(0) = 1. Usando il metodo <strong>di</strong> Eulero<br />

implicito con passo h = 0.5, per ricavare y 1 otteniamo l’equazione implicita<br />

y 1 = y 0 + h f (t 1 , y 1 ) = 1 − 0.5y 3 1<br />

Questa equazione non lineare in y 1 può essere risolta me<strong>di</strong>ante metodo <strong>di</strong> punto fisso (x = g (x) = 1−0.5x 3 )<br />

oppure utilizzando il metodo <strong>di</strong> Newton-Raphson per F (x) = 0 con F (x) = x −1+0.5x 3 ) . L’approssimazione<br />

iniziale per ottenere y 1 può essere o la soluzione al passo precedente, y 0 , oppure usare il metodo <strong>di</strong> Eulero<br />

esplicito, che dà y 1 = y 0 − 0.5y 3 0 = 0.5. Otteniamo, come y 1 il valore finale y 1 ≈ 0.7709.<br />

Esempio 10.4.3 Vogliamo <strong>di</strong>scretizzare il problema <strong>di</strong> Cauchy<br />

y ′ = −y 2<br />

y(0) = 1<br />

con passo h = 0.1 applicando il metodo <strong>di</strong> Eulero esplicito per ricavare y 1 e y 2 .<br />

Il metodo <strong>di</strong> Eulero esplicito è:<br />

y i+1 = y i + h f (t i , y i ) = y i + h(−y 2 i ) = y i − hy 2 i<br />

Partendo da y 0 = 1 si ricava:<br />

y 1 = 1 − 0.1(1 2 ) = 0.9<br />

y 2 = 0.9 − 0.1(0.9 2 ) = 0.819<br />

Per confronto, calcoliamo la soluzione esatta y(t) = 1<br />

t + 1 , ottenendo:<br />

y(t 1 ) = y(0.1) = 1/(0.1 + 1) = 0.9090909090<br />

y(t 2 ) = y(0.2) = 1/(0.2 + 1) = 0.8333333333<br />

Applichiamo ora il metodo <strong>di</strong> Eulero implicito con lo stesso passo h = 0.1.<br />

y i+1 = y i + h f (t i+1 , y i+1 ) = y i − hy 2 i+1<br />

Per ricavare y 1 la formula <strong>di</strong>venta:<br />

y 1 = y 0 + h f (t 1 , y 1 ) = 1 − 0.1(y 2 1 )<br />

152


10.4. Metodo <strong>di</strong> Eulero implicito<br />

Abbiamo un’equazione non lineare in y 1 . Per trovare y 1 , possiamo pensare <strong>di</strong> applicare lo schema <strong>di</strong> punto<br />

fisso alla funzione g (y) = 1 − 0.1(y 2 ) partendo da y (0) = y 0 = 1, in quanto y 1 = g (y 1 ) è punto fisso per la<br />

funzione g . Applichiamo tre passi dello schema <strong>di</strong> punto fisso:<br />

y (1) = g (y (0) ) = 1 − 0.1(1 2 ) = 0.9<br />

y (2) = g (y (1) ) = 1 − 0.1(0.9 2 ) = 0.919<br />

y (3) = g (y (2) ) = 1 − 0.1(0.919 2 ) = 0.9155439<br />

Se pren<strong>di</strong>amo y (3) come approssimazione <strong>di</strong> y 1 ricaviamo y 1 = 0.9155439 (per confronto, il valore esatto è<br />

0.90909090).<br />

Calcoliamo ora y 2 :<br />

y 2 = y 1 + h f (t 2 , y 2 ) = 0.9155439 − 0.1(y 2 2 )<br />

Ora la funzione <strong>di</strong> punto fisso <strong>di</strong>venta g (y) = 0.9155439 − 0.1(y 2 ). Applichiamo lo schema <strong>di</strong> punto fisso<br />

partendo da y (0) = y 1 = 0.9155439.<br />

y (1) = g (y (0) ) = 0.9155439 − 0.1(0.9155439 2 ) = 0.8317218367<br />

y (2) = g (y (1) ) = 0.9155439 − 0.1(0.8317218367 2 ) = 0.8463677786<br />

y (3) = g (y (2) ) = 0.9155439 − 0.1(0.8463677786 2 ) = 0.8439100583<br />

Troviamo quin<strong>di</strong> y 2 = 0.8439100583 (valore esatto 0.8333333333).<br />

Ve<strong>di</strong>amo cosa accade in Eulero implicito se il punto iniziale del metodo <strong>di</strong> punto fisso è dato da un passo<br />

del metodo <strong>di</strong> Eulero esplicito.<br />

Per ricavare y 1 , considero come y (0) = y 0 + h f (t 0 , y 0 ) = 1 − 0.1 = 0.9<br />

In tal caso, l’approssimazione iniziale è quella che, nel caso <strong>di</strong> prima, era il valore y (1) .<br />

Applichiamo tre volte lo schema <strong>di</strong> punto fisso:<br />

y (1) = g (y (0) ) = 1 − 0.1(0.9 2 ) = 0.919<br />

y (2) = g (y (1) ) = 1 − 0.1(0.919 2 ) = 0.9155439<br />

y (3) = g (y (2) ) = 1 − 0.1(0.9155439 2 ) = 0.9161779367<br />

Quin<strong>di</strong> y 1 = 0.9161779367.<br />

Al secondo passo, lo schema <strong>di</strong> punto fisso è dato dalla funzione g (y) = y 1 − h(y 2 ) = 0.9161779367 − 0.1y 2 .<br />

Come approssimazione iniziale pren<strong>di</strong>amo y (0) = y 1 + h f (t 1 , y 1 ) = g (y 1 ) = 0.8322397355. Si ha:<br />

y (1) = g (y (0) ) = 0.9161779367 − 0.1(0.8322397355 2 ) = 0.8469156390<br />

y (2) = g (y (1) ) = 0.9161779367 − 0.1(0.8469156390 2 ) = 0.8444513267<br />

y (3) = g (y (2) ) = 0.9161779367 − 0.1(0.84445132672) = 0.8448681324<br />

Ricaviamo y 2 = 0.8448681324.<br />

153


10. EQUAZIONI ALLE DERIVATE ORDINARIE<br />

10.5 Metodo <strong>di</strong> Crank-Nicolson<br />

Partiamo dall’ODE 3 y ′ = f (t, y(t)). Integriamo ambo i membri dell’equazione sull’intervallo [t i , t i+1 ]:<br />

∫ y(ti+1 )<br />

y(t i )<br />

∫ ti+1<br />

∫ ti+1<br />

dy = f (t, y(t)) dt =⇒ y(t i+1 ) − y(t i ) = f (t, y(t)) dt<br />

t i t i<br />

A secondo membro, applichiamo la formula dei trapezi trascurando l’errore <strong>di</strong> integrazione:<br />

y i+1 − y i = h 2 [f (t i , y i ) + f (t i+1 , y i+1 )]<br />

Si ha la formula <strong>di</strong> Crank-Nicolson: y i+1 = y i + h 2 [f (t i , y i ) + f (t i+1 , y i+1 )]<br />

Altro<br />

approccio<br />

La stessa formula la si può ricavare prendendo la me<strong>di</strong>a aritmetica delle formule <strong>di</strong> Eulero esplicito e<br />

implicito:<br />

y i+1 − y i = h f (t i , y i )<br />

y i+1 − y i = h f (t i+1 , y i+1 )<br />

sommando e <strong>di</strong>videndo per 2:<br />

y i+1 − y i = h 2 [f (t i , y i ) + f (t i+1 , y i+1 )] =⇒ y i+1 = y i + h 2 [f (t i , y i ) + f (t i+1 , y i+1 )]<br />

Esempio 10.5.1 Lo stesso esempio <strong>di</strong> prima (y ′ = −y con y(0) = 1) risolto con Crank-Nicolson dà: y i+1 =<br />

y i + h 2 [−y i − y i+1 )] cioè<br />

(1 + h 2 )y i+1 = (1 − h ( ) 2 − h<br />

2 )y i =⇒ (2 + h)y i+1 = (2 − h)y i =⇒ y i+1 = y i<br />

2 + h<br />

Per h = 0.5, confrontiamo i valori ottenuti dai meto<strong>di</strong> <strong>di</strong> Eulero esplicito, implicito e Crank-Nicolson, con la<br />

soluzione esatta:<br />

t i y(t i ) y i Eul. Espl. y i Eul. Impl. y i C-N<br />

0.0 1.000000 1.0000000 1.000000 1.000000<br />

0.5 0.606531 0.5000000 0.666667 0.600000<br />

1.0 0.367879 0.2500000 0.444444 0.360000<br />

1.5 0.223130 0.1250000 0.296296 0.216000<br />

2.0 0.135335 0.0625000 0.197531 0.129600<br />

2.5 0.082085 0.0312500 0.131687 0.077760<br />

3.0 0.049787 0.0156250 0.087791 0.046656<br />

3.5 0.030197 0.0078125 0.058528 0.027994<br />

4.0 0.018316 0.0039062 0.039018 0.016796<br />

3 John Crank (1916-2006) è stato un matematico inglese che si è de<strong>di</strong>cato soprattutto allo stu<strong>di</strong>o <strong>di</strong> soluzioni numeriche <strong>di</strong> equazioni<br />

alle derivate parziali, in particolare <strong>di</strong> problemi <strong>di</strong> conduzione del calore. È noto soprattutto per il lavoro svolto con Phyllis Nicolson.<br />

Phyllis Nicolson (1917-1968) è stata una matematica inglese. Negli anni della seconda guerra mon<strong>di</strong>ale lavorò sulla teoria del<br />

magnetron. È nota, appunto, per il metodo <strong>di</strong> Crank-Nicolson.<br />

154


10.6. Stu<strong>di</strong>o dell’errore<br />

10.6 Stu<strong>di</strong>o dell’errore<br />

Nel costruire i meto<strong>di</strong> (<strong>di</strong> Eulero esplicito, implicito, Crank-Nicolson) abbiamo trascurato un termine (il<br />

resto della formula <strong>di</strong> Taylor o l’errore della formula dei trapezi): questo termine che abbiamo trascurato<br />

rappresenta l’errore <strong>di</strong> troncamento locale. Nel caso <strong>di</strong> Eulero esplicito avevamo (usando la formula <strong>di</strong><br />

Taylor):<br />

y ′ (t i+1 ) = y(t i+1) − y(t i )<br />

− h h 2 y′′ (ξ i ) = f (t i , y(t i ))<br />

Per costruire il metodo, abbiamo trascurato il termine del resto, vale a <strong>di</strong>re la quantità<br />

d i = y(t i+1) − y(t i )<br />

− f (t i , y(t i )) = h h<br />

2 y′′ (ξ i ) = O (h)<br />

Questa quantità ci <strong>di</strong>ce <strong>di</strong> quanto la soluzione esatta “fallisce” nel sod<strong>di</strong>sfare la relazione della formula <strong>di</strong><br />

Eulero esplicito e rappresenta l’errore <strong>di</strong> troncamento locale.<br />

Definizione 10.6.1 Si definisce errore totale <strong>di</strong> troncamento ε i la quantità:<br />

ε i = y(t i ) − y i .<br />

Ci aspettiamo che sia dello stesso or<strong>di</strong>ne <strong>di</strong> grandezza dell’errore <strong>di</strong> troncamento locale.<br />

Definizione 10.6.2 Per effetto dell’arrotondamento, al tempo t i al posto <strong>di</strong> y i otteniamo il valore arrotondato<br />

y i . Si definisce errore totale <strong>di</strong> arrotondamento la quantità:<br />

ε i = y i − y i<br />

Definizione 10.6.3 L’errore globale dello schema numerico è dato dal contributo dell’errore totale <strong>di</strong><br />

troncamento e dell’errore totale <strong>di</strong> arrotondamento<br />

ɛ i = y(t i ) − y i = ε i + ε i<br />

Gli errori <strong>di</strong> arrotondamento nell’approssimare la derivata prima <strong>di</strong> una funzione si comportano come<br />

O ( 1 ) (si veda l’esempio fatto sulla propagazione <strong>degli</strong> errori a pag. 29). Tuttavia questo aspetto <strong>di</strong>venta secondario<br />

nella risoluzione delle ODE sia perchè il passo h nelle applicazioni non è mai troppo (esagerata-<br />

h<br />

mente) piccolo per ragioni <strong>di</strong> efficienza sia perchè è la y e non la y ′ la funzione che dobbiamo approssimare.<br />

Inoltre, nell’eseguire i calcoli in doppia precisione (come si fa nei moderni linguaggi <strong>di</strong> programmazione),<br />

l’aspetto dovuto all’arrotondamento si vede poco rispetto ad altri fenomeni che influenzano la propagazione<br />

<strong>degli</strong> errori.<br />

10.7 Errori <strong>di</strong> troncamento locale<br />

G Nel metodo <strong>di</strong> Eulero esplicito:<br />

G Nel metodo <strong>di</strong> Eulero implicito:<br />

d i = y(t i+1) − y(t i )<br />

− f (t i , y(t i )) = h h<br />

2 y′′ (ξ i ) = O (h)<br />

d i = y(t i+1) − y(t i )<br />

− f (t i , y(t i+1 )) = − h h<br />

2 y′′ (ξ i ) = O (h)<br />

155


10. EQUAZIONI ALLE DERIVATE ORDINARIE<br />

G Nel metodo <strong>di</strong> Crank-Nicolson (derivando la formula dai trapezi e includendo il termine dell’errore):<br />

y(t i+1 ) − y(t i ) = h 2 [f (t i , y(t i )) + f (t i+1 , y(t i+1 ))] − f ′′ (ξ i ,τ i )<br />

h 3<br />

12<br />

dove ξ i e τ i sono opportuni punti. Ma f = y ′ da cui f ′ = y ′′ e f ′′ = y ′′′ .<br />

Perciò<br />

y(t i+1 ) − y(t i ) = h 2 [f (t i , y(t i )) + f (t i+1 , y(t i+1 ))] − y′′′ (ξ i )<br />

h 3<br />

12<br />

d i = y(t i+1) − y(t i )<br />

h<br />

10.8 Convergenza e stabilità<br />

Definizione 10.8.1 Un metodo si <strong>di</strong>ce convergente se lim h→0<br />

− 1 2 [f (t i , y(t i )) + f (t i+1 , y(t i+1 ))] = − y′′′ (ξ i )<br />

h 2 = O (h 2 )<br />

12<br />

i→+∞<br />

ɛ i = 0 cioè se l’errore va a zero al tendere del<br />

passo h a zero e <strong>di</strong> i all’infinito in modo che il prodotto i h si mantenga costante (così t 0 +i h tende ad un valore<br />

<strong>di</strong> t fissato: stu<strong>di</strong>amo l’errore fissato t).<br />

Esempio 10.8.1 Ve<strong>di</strong>amo come, fissato un certo istante t, possiamo fare tendere h a zero e far crescere i<br />

all’infinito in modo che t 0 + i h sia sempre uguale a t. Sia t 0 = 0 e t = 0.5:<br />

h i i h<br />

0.5 1 0.5<br />

0.25 2 0.5<br />

0.125 4 0.5<br />

0.0625 8 0.5<br />

.<br />

.<br />

.<br />

2.4414e-4 2048 0.5<br />

Definizione 10.8.2 Un metodo si <strong>di</strong>ce stabile se l’errore iniziale si mantiene limitato al crescere <strong>di</strong> i (per i → ∞):<br />

con M costante positiva.<br />

|ɛ i | ≤ M|ɛ 0 |<br />

Stu<strong>di</strong>eremo la convergenza e la stabilità dei meto<strong>di</strong> <strong>di</strong> Eulero esplicito, implicito e Crank-Nicolson<br />

applicati all’equazione test y ′ = −λy (λ > 0 in modo che −λ < 0) con con<strong>di</strong>zione iniziale y(0) = y 0 .<br />

La soluzione esatta <strong>di</strong> questo IVP è y(t) = y 0 e −λt : tende a zero per valori <strong>di</strong> t crescenti. Ci aspettiamo che<br />

anche la soluzione numerica si comporti in maniera simile.<br />

10.8.1 Convergenza <strong>di</strong> Eulero esplicito<br />

Per semplicità, applichiamo la formula del metodo <strong>di</strong> Eulero esplicito all’equazione test con λ = 1.<br />

y 1 = y 0 + h f (t 0 , y 0 ) = y 0 − hy 0 = (1 − h)y 0<br />

y 2 = y 1 + h f (t 1 , y 1 ) = y 1 − hy 1 = (1 − h)y 1<br />

.<br />

y i = y i−1 + h f (t i−1 , y i−1 ) = y i−1 − hy i−1 = (1 − h)y i−1<br />

156


10.8. Convergenza e stabilità<br />

Andando a ritroso troviamo una formula che lega y i <strong>di</strong>rettamente a y 0 .<br />

y 1 = (1 − h)y 0<br />

y 2 = (1 − h)y 1 = (1 − h) 2 y 0<br />

.<br />

y i = (1 − h)y i−1 = (1 − h) i y 0<br />

La soluzione numerica al tempo t i è data da y i = (1 − h) i y 0 . Fissato un tempo t = i h, ve<strong>di</strong>amo se<br />

cioè se<br />

lim<br />

h→0<br />

i→+∞<br />

y i = y(t).<br />

i h<br />

⎡<br />

1<br />

⎤<br />

Osserviamo che: (1 − h) i = (1 − h) h = ⎣(1 − h) h ⎦<br />

t<br />

lim<br />

h→0<br />

i→+∞<br />

Ricor<strong>di</strong>amo la proprietà per la quale x α = e ln(xα) = e αln(x) . Perciò: (1 − h) h = e ln(1−h)(1/h) = e h<br />

Quando facciamo il limite per h → 0 e per i → +∞ consideriamo che, per il teorema dell’ Hôpital, vale<br />

Di conseguenza lim h→0 e<br />

Allora<br />

lim<br />

h→0<br />

i→+∞<br />

ln(1 − h)<br />

h<br />

y i = lim<br />

h→0<br />

i→+∞<br />

ln(1 − h) −1<br />

lim = lim<br />

h→0 h h→0 1 − h = −1<br />

= e −1<br />

⎡<br />

y 0 (1 − h) i = lim y 0 h→0<br />

i→+∞<br />

1<br />

⎤t<br />

⎣(1 − h) h ⎦ = y 0 e −t = y(t)<br />

1<br />

ln(1 − h)<br />

ɛ i = 0<br />

In questo modo abbiamo provato che il metodo converge. Il <strong>di</strong>scorso si ripete in maniera del tutto simile,<br />

per λ ≠ 1.<br />

10.8.2 Stabilità <strong>di</strong> Eulero esplicito<br />

Per quanto riguarda la stabilità, dobbiamo provare che l’errore si mantiene limitato. Sia λ > 0. Abbiamo<br />

y i+1 = y i − hλy i = (1 − hλ)y i , vale a <strong>di</strong>re y i+1 = y 0 (1 − hλ) i+1 . La soluzione esatta <strong>di</strong> questo problema è<br />

y(t) = y 0 e −λt e tende a zero per valori <strong>di</strong> t crescenti. Vogliamo che tenda a zero anche la soluzione numerica<br />

(in modo da mantenere limitato l’errore). La soluzione numerica (fissato h e per i grande, cioè per valori <strong>di</strong> t<br />

crescente) tende a zero se |1 − hλ| < 1 cioè per −1 < 1 − hλ < 1 ⇐⇒ 0 < hλ < 2 ⇐⇒ h < 2 λ .<br />

Il metodo <strong>di</strong> Eulero esplicito è stabile sotto con<strong>di</strong>zione.<br />

10.8.3 Convergenza <strong>di</strong> Eulero implicito<br />

Il metodo <strong>di</strong> Eulero implicito applicato all’equazione test <strong>di</strong>venta:<br />

y i+1 =<br />

y i<br />

(1 + hλ)<br />

157


10. EQUAZIONI ALLE DERIVATE ORDINARIE<br />

Quin<strong>di</strong><br />

y 0<br />

y 1 =<br />

(1 + hλ)<br />

y 1<br />

y 2 =<br />

(1 + hλ) = y 0<br />

(1 + hλ) 2<br />

y 2<br />

y 3 =<br />

(1 + hλ) = y 0<br />

(1 + hλ) 3<br />

.<br />

y i =<br />

y i−1<br />

(1 + hλ) = y 0<br />

(1 + hλ) i<br />

In tal caso<br />

lim<br />

h→0<br />

i→+∞<br />

y i = lim<br />

h→0<br />

i→+∞<br />

y 0<br />

(1 + hλ) i = lim<br />

h→0<br />

i→+∞<br />

⎡<br />

1<br />

⎤<br />

y 0 (1 + hλ) −i = y 0<br />

⎣(1 + hλ) h ⎦<br />

(i passaggi sono del tutto simili a quelli visti per Eulero esplicito).<br />

Abbiamo provato la convergenza.<br />

−i h<br />

= y 0 e −tλ = y(t)<br />

10.8.4 Stabilità <strong>di</strong> Eulero implicito<br />

y 0<br />

Per la stabilità, dalla soluzionei numerica y i = , si osserva che, per i → +∞, qualunque sia il valore<br />

<strong>di</strong> h, la soluzione tende a zero in quanto lim i→+∞ = 0 Si parla <strong>di</strong> metodo incon<strong>di</strong>zionatamente<br />

(1 + λh)<br />

i<br />

1<br />

(1 + λh)<br />

i<br />

stabile.<br />

10.8.5 Convergenza <strong>di</strong> Crank-Nicolson<br />

Il metodo <strong>di</strong> Crank-Nicolson applicato all’equazione test <strong>di</strong>venta: y i+1 = y i + hλ<br />

2 [−y i − y i+1 ] da cui<br />

Andando a ritroso si ricava<br />

( ) 2 − hλ<br />

y i+1 = y i<br />

2 + hλ<br />

( ) 2 − hλ i+1<br />

y i+1 = y 0<br />

2 + hλ<br />

Per verificare che il metodo converge stu<strong>di</strong>amo il limite<br />

lim<br />

h→0<br />

i→+∞<br />

⎡<br />

( ) 2 − hλ i ( ) 1 ⎤<br />

⎢ 2 − hλ<br />

= ⎣<br />

h ⎥<br />

⎦<br />

2 + hλ 2 + hλ<br />

i h<br />

y i . Partiamo dalla relazione<br />

⎡<br />

( ) 1 ⎤t<br />

⎢ 2 − hλ<br />

= ⎣<br />

h ⎥<br />

⎦<br />

2 + hλ<br />

Ma<br />

( 2 − hλ<br />

2 + hλ<br />

) 1 1 2 − hλ<br />

ln(<br />

h = e h 2 + hλ )<br />

158


10.8. Convergenza e stabilità<br />

Nel fare il limite per h → 0 e i → +∞ della quantità che si trova all’esponente, applichiamo l’Hôpital e<br />

ricor<strong>di</strong>amo che la derivata <strong>di</strong> 2 − hλ −λ(2 + hλ) − (2 − hλ)λ<br />

vale<br />

2 + hλ (2 + hλ) 2 = −4λ<br />

(2 + hλ) 2 :<br />

Quin<strong>di</strong><br />

lim<br />

h→0<br />

i→+∞<br />

lim<br />

h→0<br />

i→+∞<br />

ln( 2 − hλ<br />

2 + hλ )<br />

h<br />

y i = lim<br />

La convergenza è provata.<br />

h→0<br />

i→+∞<br />

= lim<br />

h→0<br />

i→+∞<br />

( 2 − hλ<br />

y 0<br />

2 + hλ<br />

2 + hλ −4λ<br />

2 − hλ (2 + hλ) 2 = lim −4λ<br />

h→0 (2 + hλ)(2 − hλ) = −λ<br />

) i<br />

= lim<br />

h→0<br />

i→+∞<br />

i→+∞<br />

⎡<br />

( ) 1 ⎤<br />

⎢ 2 − hλ<br />

y 0 ⎣<br />

h ⎥<br />

⎦<br />

2 + hλ<br />

i h<br />

= y 0 e −tλ = y(t)<br />

10.8.6 Stabilità <strong>di</strong> Crank-Nicolson<br />

( ) 2 − λh i<br />

Per la stabilità, si vede che la soluzione numerica è y i = y 0 . Per i → +∞, qualunque sia il valore<br />

2 + λh<br />

( ) 2 − λh i<br />

<strong>di</strong> h, la soluzione tende a zero in quanto lim i→+∞ = 0. Il metodo è incon<strong>di</strong>zionatamente stabile.<br />

2 + λh<br />

10.8.7 Sulla stabilità<br />

La stabilità <strong>di</strong> questi meto<strong>di</strong> la si può verificare anche considerando <strong>di</strong>rettamente l’errore ɛ i , <strong>di</strong>mostrando<br />

che gli errori al passo i e al passo i +1 verificano la stessa relazione che hanno y i+1 e y i e mostrando che l’errore<br />

rimane limitato sotto con<strong>di</strong>zione per Eulero esplicito mentre è incon<strong>di</strong>zionatamente stabile per gli altri<br />

meto<strong>di</strong>. In Figura 10.2 si vede come il metodo <strong>di</strong> Eulero esplicito sia stabile sotto con<strong>di</strong>zione mentre i meto<strong>di</strong><br />

<strong>di</strong> Eulero implicito e Crank-Nicolson sono stabili qualunque passo <strong>di</strong> <strong>di</strong>scretizzazione venga utilizzato.<br />

Esempio 10.8.2 Consideriamo il metodo <strong>di</strong> Eulero esplicito e applichiamolo all’equazione test. Sappiamo<br />

che y i+1 = y i + hλy i .<br />

Per la soluzione esatta, sappiamo che vale y(t i+1 ) = y(t i ) + hλy(t i ) + hd i (con d i l’errore <strong>di</strong> troncamento<br />

locale).<br />

Sottraendo la prima equazione dalla seconda abbiamo<br />

ɛ i+1 = ɛ i + hλɛ i + hd i<br />

Considerato che d i = h 2 y′′ (ξ i ) e che, per stu<strong>di</strong>are la stabilità, h è fissato mentre i tende a +∞, il termine hd i<br />

non influisce sull’andamento dell’errore e possiamo trascurarlo. Si ha allora la relazione:<br />

ɛ i+1 = ɛ i + hλɛ i<br />

Ricaviamo ɛ i = ɛ 0 (1 + hλ) i .<br />

Il ragionamento da fare è lo stesso che abbiamo fatto in precedenza e troviamo gli stessi risultati. Dobbiamo<br />

infatti verificare quando ɛ i tende a zero per i che tende a +∞. . .<br />

159


10. EQUAZIONI ALLE DERIVATE ORDINARIE<br />

Figura 10.2: Confronto dei meto<strong>di</strong> <strong>di</strong> Eulero esplicito, implicito e Crank-Nicolson sull’equazione test y ′ = −y,<br />

prendendo come h il valore h = 2 (a sinistra) e h = 0.5 (a destra).<br />

10.9 <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 10.9.1 Stu<strong>di</strong>are la stabilità del metodo <strong>di</strong> Eulero esplicito applicato all’equazione <strong>di</strong>fferenziale<br />

y ′ = −2y + 1, con y(0) = 1 (soluzione esatta y(t) = e−2t + 1<br />

)<br />

2<br />

Svolgimento<br />

Per provare la stabilità del metodo dobbiamo verificare che l’errore iniziale si mantiene limitato per valori<br />

crescenti del tempo.<br />

Il metodo <strong>di</strong> Eulero esplicito applicato all’ODE del problema <strong>di</strong>venta<br />

y i+1 = y i + h(−2y i + 1) = (1 − 2h)y i + h<br />

La soluzione esatta sod<strong>di</strong>sfa un’equazione del tipo<br />

y(t i+1 ) = y(t i ) + h(−2y(t i ) + 1) + hd i = (1 − 2h)y(t i ) + h + hd i<br />

Nel calcolare l’errore ɛ i+1 = y(t i+1 ) − y i+1 abbiamo<br />

ɛ i+1 = (1 − 2h)ɛ i + hd i<br />

Il termine hd i (d i errore locale <strong>di</strong> troncamento) si può trascurare. Abbiamo allora ɛ i+1 = (1 − 2h)ɛ i .<br />

Possiamo trovare con facilità che ɛ i+1 = (1 − 2h) i+1 ɛ 0 o, ancora, ɛ i = (1 − 2h) i ɛ 0 .<br />

Se vogliamo che l’errore rimanga limitato per i → ∞ la quantità (1 − 2h) i non deve crescere.<br />

Quin<strong>di</strong> deve essere |1 − 2h| < 1, vale a <strong>di</strong>re −1 < 1 − 2h < 1 cioè 2h < 2, quin<strong>di</strong> h < 1: stabilità sotto<br />

con<strong>di</strong>zione.<br />

160


C A P I T O L O<br />

11<br />

INTRODUZIONE AL FORTRAN 77<br />

:–Almeno hai trovato i files?<br />

:– Non so nemmeno come... come<br />

sono fatti?<br />

:– Sono dentro il computer.<br />

:– Sono “dentro” il computer?<br />

.<br />

:– Com’è che i files non escono?<br />

Zoolander<br />

11.1 Introduzione alla programmazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162<br />

11.2 FORTRAN: FORmula TRANslator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162<br />

11.3 Problemi e Algoritmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163<br />

11.4 Elementi <strong>di</strong> un linguaggio <strong>di</strong> programmazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />

11.5 Prime regole sul FORTRAN77 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />

11.6 Le variabili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165<br />

11.7 I tipi <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />

11.8 Espressioni aritmetiche e funzioni elementari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />

11.9 I pre<strong>di</strong>cati elementari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167<br />

11.10 Struttura alternativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170<br />

11.11 Programma sul metodo <strong>di</strong> punto fisso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172<br />

11.12 I sottoprogrammi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />

11.12.1 Le functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />

11.12.2 Le subroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178<br />

11.13 Il formato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180<br />

11.14 Files <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182<br />

11.15 Vettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182<br />

11.16 Ciclo do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183<br />

11.16.1 I vettori nei sottoprogrammi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184<br />

11.16.2 Leggere i dati <strong>di</strong> input da file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185<br />

11.17 Matrici in FORTRAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />

11.17.1 Le matrici nei sottoprogrammi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />

11.17.2 Parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189<br />

161


11. INTRODUZIONE AL FORTRAN 77<br />

11.17.3 Memorizzazione delle matrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190<br />

11.17.4 Un programma <strong>di</strong> esempio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191<br />

11.18 La formula dei trapezi in FORTRAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193<br />

11.19 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />

11.1 Introduzione alla programmazione<br />

Prendono il nome <strong>di</strong> software quei programmi che vengono fatti eseguire al calcolatore e consentono<br />

all’hardware <strong>di</strong> svolgere il proprio compito.<br />

Esistono due categorie <strong>di</strong> linguaggi per scrivere programmi:<br />

G linguaggi <strong>di</strong> alto livello (come FORTRAN, C, C++)<br />

G linguaggi <strong>di</strong> basso livello (come assembler).<br />

Il linguaggio macchina, invece, è il linguaggio specifico dell’elaboratore e consiste <strong>di</strong> cifre binarie 0 e 1 che<br />

identificano istruzioni elementari. Ogni elaboratore ha il suo linguaggio macchina.<br />

I linguaggi <strong>di</strong> basso e alto livello si possono tradurre in un qualsiasi linguaggio macchina e possono essere<br />

utilizzati su qualsiasi elaboratore (sono portabili).<br />

Con i linguaggi <strong>di</strong> basso livello, i co<strong>di</strong>ci binari (fatti da 0 e 1) vengono sostituiti da opportune ”parole<br />

chiave” che permettono una corrispondenza uno-uno tra il linguaggio <strong>di</strong> basso livello e il linguaggio<br />

macchina.<br />

Con i linguaggi <strong>di</strong> alto livello, una singola istruzione può tradurre più istruzioni <strong>di</strong> linguaggio macchina.<br />

Inoltre un linguaggio <strong>di</strong> alto livello è facile da capire (nella sua sintassi, nelle sue regole, nel suo modo <strong>di</strong><br />

essere utilizzato) da chi programma.<br />

Perciò, quando si programma con un linguaggio <strong>di</strong> alto livello, il programmatore deve conoscere e sapere<br />

bene la grammatica, la sintassi, il vocabolario del linguaggio stesso.<br />

Uno volta scritto il programma in modo corretto, occorre fare capire al computer che c’è un programma da<br />

eseguire: bisogna quin<strong>di</strong> tradurre in linguaggio macchina il programma scritto con il linguaggio <strong>di</strong> alto livello:<br />

questo passaggio lo si fa me<strong>di</strong>ante la compilazione. Useremo un comando (un’istruzione da scrivere nella<br />

finestra <strong>di</strong> shell, nella stessa <strong>di</strong>rectory in cui si trova il programma che abbiamo scritto) che ci permetterà<br />

<strong>di</strong> tradurre il programma scritto nel linguaggio <strong>di</strong> alto livello (che chiamamo programma sorgente) in un<br />

programma equivalente scritto in linguaggio macchina e che potrà essere eseguito dal calcolatore, detto<br />

programma eseguibile.<br />

Programma sorgente<br />

compi l ator e<br />

−−−−−−−−−→ Programma eseguibile<br />

11.2 FORTRAN: FORmula TRANslator<br />

FORTRAN è una sigla per FORMula TRANslator.<br />

Anche se il FORTRAN si è molto evoluto, ci soffermeremo in particolare sulla versione 77 perchè (a parte<br />

alcuni punti ormai obsoleti) la sintassi e il modo <strong>di</strong> imparare a scrivere un programma è più semplice.<br />

Inoltre è possibile scaricare gratuitamente in rete compilatori del FORTRAN77 da poter installare sul proprio<br />

computer (anche con sistema operativo Windows).<br />

Un programma FORTRAN va prima scritto me<strong>di</strong>ante un e<strong>di</strong>tor <strong>di</strong> testo, salvandolo con un nome che abbia<br />

l’estensione .f, per esempio prova.f. Poi va tradotto in linguaggio macchina in modo da poterlo eseguire<br />

al calcolatore: questo passo viene fatto attraverso la compilazione. Un compilatore è il g77. Me<strong>di</strong>ante<br />

l’istruzione<br />

g77 -o prova prova.f<br />

tradurremo in linguaggio macchina il programma prova.f e il risultato sarà la creazione <strong>di</strong> un nuovo file<br />

chiamato prova che potremo eseguire. Analogo è il comando<br />

g77 prova.f -o prova<br />

162


11.3. Problemi e Algoritmi<br />

Notiamo l’or<strong>di</strong>ne dei coman<strong>di</strong>. L’importante è che la scrittura -o sia imme<strong>di</strong>atamente precedente il nome<br />

del file eseguibile!<br />

Possiamo scrivere anche<br />

g77 -o prova.exe prova.f<br />

Possiamo mettere un’estensione al file eseguibile, prova.exe, oppure no.<br />

Per eseguire il programma prova, scriveremo da shell l’istruzione<br />

prova<br />

oppure<br />

./prova<br />

a seconda del calcolatore.<br />

Altri tipi <strong>di</strong> compilatore sono f77, gfortran.<br />

11.3 Problemi e Algoritmi<br />

Ci sono tante definizioni per problema:<br />

G etimologicamente, viene dal verbo greco ”pro-ballein” pro: davanti, ballein: mettere, da cui problema<br />

ha il significato <strong>di</strong> ostacolo, promontorio, impe<strong>di</strong>mento;<br />

G sul <strong>di</strong>zionario troviamo: Questione da risolvere partendo da elementi noti me<strong>di</strong>ante il ragionamento, e<br />

per la quale si propongono soluzioni; 1<br />

G o ancora quesito con cui si chiede <strong>di</strong> trovare, me<strong>di</strong>ante un proce<strong>di</strong>mento <strong>di</strong> calcolo, uno o più dati<br />

sconosciuti, partendo dai dati noti contenuti...; 2<br />

G in senso figurato, invece, per problema si intende Questione, situazione <strong>di</strong>fficile o complessa <strong>di</strong> cui<br />

si cerca la spiegazione o la soluzione: 3 e questione, situazione, caso <strong>di</strong>fficile da risolvere e che genera<br />

preoccupazione, . . . , complicazione, <strong>di</strong>fficoltà, ostacolo; 4<br />

G estendendo ancora il significato, si trova Persona misteriosa, incomprensibile, il cui comportamento<br />

preoccupa o mette in <strong>di</strong>fficoltà; 5<br />

G . . .<br />

Qualunque sia la definizione che <strong>di</strong>amo, il tratto comune è <strong>di</strong> avere a che fare con una questione cui vogliamo<br />

dare una risposta o che vogliamo risolvere. Una delle prime cose da considerare quando si cerca <strong>di</strong> risolvere<br />

un problema è, dunque, come porre il problema.<br />

Il linguaggio naturale viene usato per descrivere un problema. Ma bisogna porre attenzione:<br />

G Lo stesso evento è descritto <strong>di</strong>versamente da un bambino <strong>di</strong> 3 anni rispetto a un uomo adulto.<br />

G Lo stesso evento viene descritto <strong>di</strong>versamente da un ingegnere, un fisico, un matematico.<br />

G A volte, le stesse parole possono essere usate per <strong>di</strong>re cose completamente <strong>di</strong>verse!<br />

C’è poi il linguaggio artificiale, che si presenta sotto forma <strong>di</strong> termini tecnici (dalla fisica, ingegneria, etc) e<br />

notazioni (dall’algebra, dal calcolo, dalla logica).<br />

Termini come temperatura, pressione, massa, espansione isotermica e a<strong>di</strong>abatica, possono essere usati in<br />

un’officina per riparare il motore <strong>di</strong> un’automobile, da un me<strong>di</strong>co che sta misurando la pressione del sangue,<br />

da un ingegnere che lavora su una turbina a gas. . .<br />

Una volta che il problema è stato descritto e se ne ha una buona conoscenza (con l’aiuto del linguaggio<br />

naturale e artificiale), si può passare alla fase <strong>di</strong> soluzione del problema stesso.<br />

Ecco l’approccio dell’algoritmo. Un algoritmo è una sequenza <strong>di</strong> passi che permettono <strong>di</strong> risolvere tutto<br />

Algoritmo<br />

1 Dal Dizionario online della Hoepli http://<strong>di</strong>zionari.hoepli.it<br />

2 Dal Dizionario online della Garzanti http://www.garzantilinguistica.it<br />

3 Da http://<strong>di</strong>zionari.hoepli.it<br />

4 Da il Sabatini Colletti Dizionario della Lingua Italiana http://<strong>di</strong>zionari.corriere.it/<strong>di</strong>zionario_italiano<br />

5 Da http://<strong>di</strong>zionari.hoepli.it<br />

163


11. INTRODUZIONE AL FORTRAN 77<br />

o parte <strong>di</strong> un problema. 6<br />

Un algoritmo si può paragonare ad una ricetta <strong>di</strong> cucina: la ricetta consiste <strong>di</strong> due parti<br />

G la lista <strong>degli</strong> ingre<strong>di</strong>enti<br />

G la sequenza dei passi da fare per realizzare la ricetta.<br />

Nel realizzare una ricetta si possono avere problemi nel cercare alcuni ingre<strong>di</strong>enti. Una parte dell’esecuzione<br />

richiederà poco tempo, altre parti richiederanno più tempo. Alcuni passi non richiedono che si segua un<br />

certo or<strong>di</strong>ne, altri passi richiedono che si mantenga l’or<strong>di</strong>ne scritto sulla ricetta. . . Le stesse analogie troviamo<br />

in un algoritmo.<br />

11.4 Elementi <strong>di</strong> un linguaggio <strong>di</strong> programmazione<br />

Come tutti i linguaggi, anche un linguaggio <strong>di</strong> programmazione ha le sue regole <strong>di</strong> grammatica, sintassi,<br />

ortografia. . .<br />

Inoltre, un programma non può essere ambiguo, in quanto <strong>di</strong>venta il preciso risultato delle istruzioni in<br />

esse contenute.<br />

Alcune attività (non <strong>di</strong> programmazione) possono essere vaghe o ambigue:<br />

stu<strong>di</strong>a molto per superare l’esame. . . – quanto molto?<br />

compra un po’ <strong>di</strong> pane prima <strong>di</strong> tornare a casa. . . – quanto pane?<br />

Siamo noi che capiamo quanto dobbiamo stu<strong>di</strong>are, quanto pane dobbiamo comprare, a seconda dell’esame<br />

da fare, della fame che abbiamo. . .<br />

In un programma non si può lasciare spazio al vago! Occorre essere precisi.<br />

I linguaggi <strong>di</strong> programmazione sono fatti da <strong>di</strong>chiarazioni (statements):<br />

G descrizione dei dati: che genere <strong>di</strong> dati abbiamo? Se vogliamo scrivere un programma in cui per<br />

ogni studente calcoliamo la me<strong>di</strong>a dei suoi voti, c’è <strong>di</strong>fferenza tra i nomi <strong>degli</strong> studenti (una stringa <strong>di</strong><br />

caratteri) e la loro me<strong>di</strong>a (un numero). Si parla <strong>di</strong> tipo <strong>di</strong> dati.<br />

G strutture <strong>di</strong> controllo. Un programma può essere visto come una sequenza <strong>di</strong> istruzioni per risolvere<br />

un certo problema. Alcune istruzioni vanno ripetute, altre vanno eseguite solo in determinate<br />

con<strong>di</strong>zioni. . .<br />

G lavorazione dei dati (data processing). In un programma occorre poter lavorare sui dati e poterli<br />

”manipolare” opportunamente.<br />

G <strong>di</strong>chiarazioni <strong>di</strong> ingresso e uscita (input e output). In genere, un programma è scritto in modo che i<br />

dati su cui si lavora possano esistere fuori del programma stesso.<br />

11.5 Prime regole sul FORTRAN77<br />

Scriviamo il nostro primo programma <strong>di</strong> prova, prova.f (apriamo un e<strong>di</strong>tor <strong>di</strong> testo e scriviamo le<br />

seguenti righe, poi salviamo il file dando il nome prova.f):<br />

program prova<br />

C<br />

C questo e ’ un programma <strong>di</strong> prova<br />

C<br />

write ( * , * ) ’programma <strong>di</strong> prova ’<br />

write ( * , * ) ’ questo e ’ ’ un programma <strong>di</strong> prova ’<br />

stop<br />

end<br />

6 La parola algoritmo è entrata in uso negli anni ’50 in sostituzione <strong>di</strong> algorismo, termine con cui si in<strong>di</strong>cava il processo <strong>di</strong> calcolo<br />

utilizzando i numeri arabi. Il termine algoritmo deriva dal nome <strong>di</strong> “al-Khwarizmi”, importante matematico arabo del nono secolo grazie<br />

al quale l’Europa imparò ad usare i numeri arabi, oltre alla notazione in base 10. Le procedure che permettevano <strong>di</strong> effettuare calcoli in<br />

notazione decimale presero il nome <strong>di</strong> algorismi o algoritmi. Anche la parola algebra viene da questo matematico e, in particolare, dalla<br />

sua opera “Al-mukhtasar fi hisab al-jabr wa al-muqabala”.<br />

Nel me<strong>di</strong>oevo (e forse anche per qualche studente <strong>di</strong> oggi!!!), si pensava che questa parola derivasse dal greco algiros (panico, dolore)<br />

e arithmos (numero).<br />

164


11.6. Le variabili<br />

G In FORTRAN77 tutte le istruzioni vanno scritte tra la 7-ima e la 72-sima colonna 7 ;<br />

G le colonne da 1 a 6 hanno un significato particolare.<br />

– sulla prima colonna si mette una C (o un altro carattere) se ciò che segue è una riga <strong>di</strong> commento<br />

– sulla colonna 6 si mette un carattere qualunque (meglio una lettera dell’alfabeto) se l’istruzione<br />

scritta sulla riga precedente è troppo lunga e va oltre la 72-sima colonna per cui si deve andare a<br />

capo oppure si vuole andare a capo per leggere meglio l’istruzione. Nella riga in cui si mette un<br />

carattere sulla colonna 6, continua l’istruzione iniziata nella riga precedente.<br />

G Il programma inizia con l’istruzione program seguito dal nome del programma.<br />

G L’istruzione stop arresta l’esecuzione del programma.<br />

G L’istruzione end segnala che non vi sono altre righe nel programma.<br />

Con questo programma <strong>di</strong> esempio, vogliamo far scrivere al computer, sulla finestra <strong>di</strong> shell in cui eseguiamo<br />

il programma, le due frasi programma <strong>di</strong> prova e questo e’ un programma <strong>di</strong> prova.<br />

L’istruzione write(*,*) ’programma <strong>di</strong> prova’<br />

rende <strong>di</strong>sponibile all’esterno le informazioni contenute tra i due apici, vale a <strong>di</strong>re la stringa <strong>di</strong> caratteri<br />

programma <strong>di</strong> prova.<br />

Al posto <strong>di</strong> write(*,*) ’programma <strong>di</strong> prova’ potremmo scrivere, in modo del tutto equivalente,<br />

write(6,*) ’programma <strong>di</strong> prova’<br />

Il primo simbolo “*” <strong>di</strong> write(*,*) o il numero “6” <strong>di</strong> write(6,*) sono due mo<strong>di</strong> equivalenti per in<strong>di</strong>care che il<br />

<strong>di</strong>spositivo <strong>di</strong> uscita su cui mostrare la stringa <strong>di</strong> caratteri è il terminale (la finestra <strong>di</strong> shell da cui eseguiamo<br />

il programma).<br />

Vedremo che ci sono anche altri mo<strong>di</strong> per rendere <strong>di</strong>sponibile l’output del programma non su video ma<br />

su file.<br />

L’apice viene usato per in<strong>di</strong>care l’inizio e la fine della stringa <strong>di</strong> caratteri da stampare. Quin<strong>di</strong>, per stampare<br />

e’ dobbiamo usare gli apici due volte:<br />

write(*,*) ’questo e’’ un programma <strong>di</strong> prova’<br />

11.6 Le variabili<br />

Scriviamo ora un programma più complicato<br />

program a r e a t r i a<br />

C programma per c a l c o l a r e l ’ area <strong>di</strong> un triangolo<br />

C dando in input i v a l o r i della base e dell ’ altezza<br />

implicit none<br />

real *8 a , b , area<br />

write ( * , * ) ’ base a ’<br />

read ( * , * ) a<br />

write ( * , * ) ’ base ’ , a<br />

write ( * , * ) ’ altezza b ’<br />

read ( * , * ) b<br />

write ( * , * ) ’ altezza ’ , b<br />

area =(a*b ) * 0 . 5<br />

write ( * , * ) ’ area del triangolo ’ , area<br />

stop<br />

end<br />

G L’istruzione implicit none <strong>di</strong>ce che nessuna variabile può essere <strong>di</strong>chiarata implicitamente: dobbiamo<br />

<strong>di</strong>chiarare tutte le variabili che utilizziamo all’interno del programma!<br />

G Introduciamo tre variabili <strong>di</strong> tipo reale in doppia precisione, me<strong>di</strong>ante real*8 a,b,c.<br />

7 Questo limite è dovuto al fatto che fino alla fine <strong>degli</strong> anni settanta, la programmazione veniva fatta utilizzando schede perforate,<br />

dei cartoncini rettangolari <strong>di</strong> <strong>di</strong>mensione standard, ciascuna delle quali era sud<strong>di</strong>visa in un numero fisso <strong>di</strong> colonne e righe<br />

(generalmente 80 colonne e 12 righe).<br />

165


11. INTRODUZIONE AL FORTRAN 77<br />

integer<br />

real<br />

real*8<br />

double precision<br />

logical<br />

character<br />

variabile intera<br />

variabile reale in precisione semplice<br />

variabile reale in doppia precisione<br />

(occupa esattamente 8 byte<br />

<strong>di</strong> memoria)<br />

variabile reale in doppia precisione<br />

(accuratezza <strong>di</strong>versa a seconda<br />

della macchina usata)<br />

variabile logica<br />

stringhe <strong>di</strong> caratteri<br />

Tabella 11.1: Tipi <strong>di</strong> dati<br />

G Con read(*,*) a si impone al calcolatore <strong>di</strong> prendere un valore e memorizzarlo nella variabile a, e questo<br />

valore lo si dà tramite tastiera. Analogamente potremmo scrivere read(5,*) a : il numero 5 in<strong>di</strong>ca<br />

che l’acquisizione dei dati avviene da tastiera.<br />

G Prima dell’istruzione <strong>di</strong> read c’è una write che ci in<strong>di</strong>ca quale valore dobbiamo mettere: è importante<br />

altrimenti vedremmo che l’elaboratore si mette in attesa <strong>di</strong> un valore e rimane così fino a quando non<br />

lo riceve. Ma se noi non sappiamo che valore dargli, possiamo aspettare anche ore. . . . (vedere cosa<br />

succede togliendo le istruzioni <strong>di</strong> write!)<br />

G Una volta dati i valori <strong>di</strong> input, si effettua un’istruzione <strong>di</strong> assegnazione: si prende il valore memorizzato<br />

nella variabile a lo si moltiplica per il valore <strong>di</strong> b e per 0.5 e il risultato viene memorizzato in una nuova<br />

variabile chiamata area. Il simbolo * è il simbolo <strong>di</strong> moltiplicazione.<br />

G Quando effettuiamo un’assegnazione, il valore contenuto nella variabile a sinistra del segno = viene<br />

perso. Nel nostro caso, in area non era memorizzato nessun valore, ma se avessimo posto in area un<br />

qualche valore iniziale, esso andrebbe perso perchè sostituito dall’operazione a*b*0.5. I valori <strong>di</strong> a e<br />

b non cambiano.<br />

G Nel momento in cui viene lanciato il programma, il valore delle variabili è incognito. Me<strong>di</strong>ante tastiera,<br />

noi <strong>di</strong>amo i valori ad a e b. Me<strong>di</strong>ante assegnazione, <strong>di</strong>amo il valore ad area. Una volta terminata<br />

l’esecuzione del programma, il valore delle variabili viene perso. Perciò ci facciamo stampare il loro<br />

valore prima dell’istruzione <strong>di</strong> stop. torna ad essere incognitoo<br />

11.7 I tipi <strong>di</strong> dati<br />

Una variabile rappresenta un ”posto” (o locazione) della memoria del calcolatore, contrassegnato da<br />

un nome che identifica la variabile, e dove possono essere scritte delle informazioni che l’elaboratore può<br />

utilizzare (per esempio il valore della variabile se la variabile è <strong>di</strong> tipo reale o intero).<br />

Le variabili possono essere <strong>di</strong> vario tipo: intere, reali, logiche (per le variabili logiche il valore può essere<br />

solo o vero o falso), complesse, <strong>di</strong> caratteri (stringhe <strong>di</strong> caratteri). Si veda la Tabella 11.1 per una sintesi dei<br />

vari tipi <strong>di</strong> dati.<br />

Le variabili <strong>di</strong> tipi intero possono variare in un intervallo limitato (tra un minimo e un massimo interi<br />

rappresentabili). La stessa cosa vale per le variabili <strong>di</strong> tipo reale: esiste un valore minimo e massimo reale<br />

rappresentabile. Questi valori <strong>di</strong> minimo e massimo <strong>di</strong>pendono dall’elaboratore (si veda il Capitolo 1).<br />

G Osserviamo che in FORTRAN una variabile può essere scritta con i caratteri maiuscoli o minuscoli<br />

senza <strong>di</strong>stizioni: XOLD è la stessa cosa <strong>di</strong> xold o XoLd.<br />

11.8 Espressioni aritmetiche e funzioni elementari<br />

Nel fare le operazioni matematiche, in FORTRAN viene data la precedenza (priorità) agli elevamenti a potenza,<br />

poi alle moltiplicazioni e <strong>di</strong>visioni, infine a sottrazione e ad<strong>di</strong>zione (si veda Tabella 11.2 per i simboli<br />

166


11.9. I pre<strong>di</strong>cati elementari<br />

∗∗ elevamento a potenza<br />

∗ moltiplicazione<br />

/ <strong>di</strong>visione<br />

+ ad<strong>di</strong>zione<br />

− sottrazione<br />

Tabella 11.2: Operazioni aritmetiche<br />

Funzione FORTRAN<br />

sin(x)<br />

cos(x)<br />

tan(x)<br />

asin(x)<br />

acos(x)<br />

atan(x)<br />

exp(x)<br />

log(x)<br />

log10(x)<br />

sqrt(x)<br />

Significato<br />

sin(x)<br />

cos(x)<br />

tan(x)<br />

asi n(x)<br />

acos(x)<br />

at an(x)<br />

e x<br />

ln(x)<br />

log(x)<br />

x<br />

Tabella 11.3: Principali funzioni<br />

usati per ciascuna <strong>di</strong> queste operazioni). Quando due operatori hanno la stessa priorità vengono eseguite<br />

le operazioni partendo da sinistra e andando verso destra. Tuttavia, quando le espressioni sono abbastanza<br />

complicate e c’è il rischio <strong>di</strong> non capire bene quali operazioni vanno fatte prima e quali dopo, conviene<br />

mettere sempre le parentesi.<br />

In FORTRAN ci sono già molte funzioni matematiche che possiamo utilizzare per i nostri programmi. In<br />

Tabella 11.3, ne ve<strong>di</strong>amo elencate alcune.<br />

11.9 I pre<strong>di</strong>cati elementari<br />

Gli algoritmi che tradurremo in programmi quasi mai hanno solo istruzioni sequenziali (vale a <strong>di</strong>re istruzioni<br />

da eseguire l’una <strong>di</strong> seguito all’altra). Molte volte, infatti, viene eseguita una istruzione piuttosto che<br />

un’altra se certe con<strong>di</strong>zioni sono vere. Oppure vengono ripetute alcune istruzioni fintantochè sono vere determinate<br />

con<strong>di</strong>zioni. Gli operatori mostrati in Tabella 11.4 ci serviranno per poter scrivere istruzioni legate<br />

ad una con<strong>di</strong>zione.<br />

Dato P un pre<strong>di</strong>cato (vale a <strong>di</strong>re una proposizione logica che può assumere solo valore vero o falso) si<br />

hanno gli operatori logici <strong>di</strong> Tabella 11.5.<br />

Esempio 11.9.1 Sia a=5 e b=10.<br />

G La proposizione (a.le.b) è una proposizione vera (.true.) perchè il valore assunto da a (5) è minore o<br />

uguale al valore <strong>di</strong> b (10).<br />

G La proposizione (a.eq.b) è falsa (.false.) perchè il valore <strong>di</strong> a è <strong>di</strong>verso da quello <strong>di</strong> b.<br />

G La proposizione (a.gt.b) è falsa.<br />

G La proposizione (a.ge.b) è falsa.<br />

G La proposizione (a.ne.b) è vera.<br />

G La proposizione (a.lt.b) è vera.<br />

167


11. INTRODUZIONE AL FORTRAN 77<br />

Operatore Significato Esempio Valore<br />

.GT. > (a.gt.b) Vero se a > b<br />

Falso se a ≤ b<br />

.GE. >= (a.ge.b) Vero se a ≥ b<br />

Falso se a < b<br />

.LT. < (a.lt.b) Vero se a < b<br />

Falso se a ≥ b<br />

.LE. b<br />

.EQ. == (a.eq.b) Vero se a = b<br />

Falso se a ≠ b<br />

.NE. ∼= (a.ne.b) Vero se a ≠ b<br />

Falso se a = b<br />

Tabella 11.4: Operatori logici ( È la stessa cosa scrivere .GT. o .gt. .GE. o .ge. e così via.)<br />

Operatore Significato Esempio<br />

.NOT. negazione .not.(P)<br />

∼<br />

.AND. congiunzione (P1).and.(P2)<br />

&<br />

.OR. <strong>di</strong>sgiunzione (P1).or.(P2)<br />

inclusiva<br />

|<br />

Tabella 11.5: Operatori logici<br />

Esempio 11.9.2 Sia a=5, b=10, c=2<br />

G (a.le.b).and.(c.le.b) è una proposizione vera perchè composta da due proposizioni vere.<br />

G .not.(a.le.b) è una proposizione falsa. Negare (a.le.b) vuol <strong>di</strong>re scrivere (a.gt.b). Ma a non è maggiore<br />

stretto <strong>di</strong> b, quin<strong>di</strong> il risultato è falso.<br />

G .not.(b.eq.c) è una proposizione vera, in quanto stiamo negando (b.eq.c): (b.eq.c) è falsa quin<strong>di</strong> la sua<br />

negazione è vera.<br />

G (a.le.b).or.(c.ge.b) è una proposizione vera perchè basta che una delle due proposizioni sia vera per<br />

rendere vero l’intero pre<strong>di</strong>cato.<br />

G (a.le.b).and.(c.ge.b) è un pre<strong>di</strong>cato falso perchè devono essere vere tutte e due le proposizioni che la<br />

compongono per rendere vero il pre<strong>di</strong>cato.<br />

G (a.eq.b).and.(c.ge.b) è un pre<strong>di</strong>cato falso perchè composto da due proposizioni false.<br />

G (a.eq.b).or.(c.ge.b) è un pre<strong>di</strong>cato falso.<br />

168<br />

Riassumendo<br />

G Negare un pre<strong>di</strong>cato falso dà come risultato un pre<strong>di</strong>cato vero.<br />

G Negare un pre<strong>di</strong>cato vero dà come risultato un pre<strong>di</strong>cato falso.<br />

G Congiungere (con .and.) due pre<strong>di</strong>cati veri dà come risultato un pre<strong>di</strong>cato vero.<br />

G Congiungere (con .and.) due pre<strong>di</strong>cati falsi dà come risultato un pre<strong>di</strong>cato falso.


11.9. I pre<strong>di</strong>cati elementari<br />

G Congiungere (con .and.) due pre<strong>di</strong>cati, uno vero ed uno falso, dà come risultato un pre<strong>di</strong>cato falso.<br />

G Disgiungere (con .or.) due pre<strong>di</strong>cati veri dà come risultato un pre<strong>di</strong>cato vero.<br />

G Disgiungere (con .or.) due pre<strong>di</strong>cati falsi dà come risultato un pre<strong>di</strong>cato falso.<br />

G Disgiungere (con .or.) due pre<strong>di</strong>cati, uno vero ed uno falso, dà come risultato un pre<strong>di</strong>cato vero.<br />

Importanti sono da ricordare le regole <strong>di</strong> De Morgan. Dati due pre<strong>di</strong>cati P1 e P2<br />

G ( .not. ( (P1).and.(P2) ) equivale a scrivere ( .not.(P1) .or. .not.(P2) )<br />

Negare una congiunzione significa <strong>di</strong>sgiungere le negazioni dei due pre<strong>di</strong>cati che la compongono.<br />

G ( .not. ( (P1).or.(P2) ) equivale a scrivere ( .not.(P1) .and. .not.(P2) )<br />

Negare una <strong>di</strong>sgiunzione significa congiungere la negazione dei due pre<strong>di</strong>cati che la compongono.<br />

Esempio 11.9.3 (.not.( (oggi fa freddo).and.(oggi è piovuto) ) ) =<br />

(oggi NON fa freddo) .or. (oggi NON è piovuto)<br />

(.not.( (oggi fa freddo).or.(oggi NON ho voglia <strong>di</strong> fare niente) ) ) =<br />

(oggi NON fa freddo) .and. (oggi ho voglia <strong>di</strong> fare tante cose)<br />

(.not.( it.le.100). and. ( x.ge.0.001) ) ) = ( (it.gt.100). or. (x.lt.0.001) )<br />

(.not.( it.le.100). or. ( x.ge.0.001) ) ) = ( (it.gt.100). and. (x.lt.0.001) )<br />

program p r e d i c a t i l o g i c i<br />

C programma <strong>di</strong> esempio s u l l e proposizioni logiche<br />

implicit none<br />

real *8 a , b , c<br />

l o g i c a l p1 , p2 , p<br />

write ( * , * ) ’ s c r i v i i l valore <strong>di</strong> a ’<br />

read ( * , * ) a<br />

write ( * , * ) ’ a= ’ , a<br />

write ( * , * ) ’ s c r i v i i l valore <strong>di</strong> b ’<br />

read ( * , * ) b<br />

write ( * , * ) ’b= ’ , b<br />

write ( * , * ) ’ s c r i v i i l valore <strong>di</strong> c ’<br />

read ( * , * ) c<br />

write ( * , * ) ’ c= ’ , c<br />

p1= ( a . l t . b)<br />

p2=(b . gt . c )<br />

write ( * , * ) ’p1= a . l t . b ’ , p1<br />

write ( * , * ) ’p2= b . gt . c ’ , p2<br />

p= p1 . and . p2<br />

write ( * , * ) ’p1 and p2 ’ , p<br />

p= . not . ( p1 . and . p2 )<br />

write ( * , * ) ’ not ( p1 and p2 ) ’ , p<br />

p= p1 . or . p2<br />

write ( * , * ) ’p1 or p2 ’ , p<br />

p= . not . ( p1 . or . p2 )<br />

write ( * , * ) ’ not ( p1 or p2 ) ’ , p<br />

stop<br />

end<br />

169


11. INTRODUZIONE AL FORTRAN 77<br />

11.10 Struttura alternativa<br />

Ciclo if<br />

I programmi in cui le istruzioni devono essere eseguite una <strong>di</strong> seguito all’altra si <strong>di</strong>cono a struttura sequenziale.<br />

Questa struttura è pero abbastanza limitata in quanto non permette <strong>di</strong> risolvere problemi anche<br />

semplici.<br />

Supponiamo <strong>di</strong> risolvere il problema <strong>di</strong> trovare le ra<strong>di</strong>ci <strong>di</strong> un’equazione <strong>di</strong> secondo grado ax 2 +bx +c = 0.<br />

G i dati <strong>di</strong> input sono i coefficienti a,b,c<br />

G si calcola il <strong>di</strong>scriminante ∆ = b 2 − 4ac<br />

G se ∆ < 0 allora le ra<strong>di</strong>ci sono complesse<br />

G se ∆ = 0 allora sappiamo che le ra<strong>di</strong>ci coincidono<br />

G se ∆ > 0 allora applichiamo la formula per trovare le due ra<strong>di</strong>ci. Sappiamo però che si può verificare<br />

il fenomeno <strong>di</strong> cancellazione numerica se b 2 − 4ac ≈ b 2 e quin<strong>di</strong> possiamo applicare una formula<br />

alternativa. . .<br />

Come fare a scrivere un programma che tenga conto <strong>di</strong> tutte le con<strong>di</strong>zioni che abbiamo visto prima, che<br />

faccia quin<strong>di</strong> qualcosa piuttosto che un’altra a seconda che sia vera o falsa una certa con<strong>di</strong>zione? Si ha il<br />

cosidetto ciclo if.<br />

i f ( espressione logica ) then<br />

{ istruzione 1a }<br />

{ istruzione 2a }<br />

{ . . . . }<br />

else<br />

{ istruzione 1b }<br />

{ istruzione 2b }<br />

{ . . . . }<br />

end i f<br />

Se è vera l’espressione logica allora si<br />

eseguono le istruzioni 1a, 2a, . . . .<br />

Altrimenti – cioè se è falsa l’espressione<br />

logica – allora si eseguono le istruzioni 1b,<br />

2b, . . .<br />

i f ( espressione logica ) then<br />

{ istruzione 1a }<br />

{ istruzione 2a }<br />

{ . . . . }<br />

end i f<br />

Se è vera l’espressione logica allora si eseguono<br />

le istruzioni 1a, 2a, . . . , altrimenti<br />

non si fa nulla.<br />

Ciclo if –<br />

struttura più<br />

generale<br />

i f ( espressione logica1 ) then<br />

{ istruzione 1a }<br />

{ istruzione 2a }<br />

{ . . . . }<br />

else i f ( espressione logica2 ) then<br />

{ istruzione 1b }<br />

{ istruzione 2b }<br />

{ . . . . }<br />

. . . .<br />

else<br />

{ istruzione 1z }<br />

{ istruzione 2z }<br />

{ . . . . }<br />

end i f<br />

170


11.10. Struttura alternativa<br />

Ve<strong>di</strong>amo un programma che calcola le ra<strong>di</strong>ci <strong>di</strong> un’equazione <strong>di</strong> secondo grado.<br />

program r a d i c i<br />

implicit none<br />

real a , b , c , delta<br />

real x1 , x2<br />

C calcolo d e l l e r a d i c i r e a l i <strong>di</strong> ax **2 +bx+c = 0<br />

C x = [−b +/− s q r t { b**2 − 4ac } ] / 2a<br />

C<br />

write ( * , * ) ’ c o e f f i c i e n t i <strong>di</strong> un’ ’ equazione <strong>di</strong> secondo grado ’<br />

write ( * , * ) ’ a = ’<br />

read ( * , * ) a<br />

write ( * , * ) ’ a = ’ , a<br />

write ( * , * ) ’b = ’<br />

read ( * , * ) b<br />

write ( * , * ) ’b = ’ , b<br />

write ( * , * ) ’ c = ’<br />

read ( * , * ) c<br />

write ( * , * ) ’ c = ’ , c<br />

delta=b**2 − 4 . * a* c<br />

i f ( delta . l t . 0 ) then<br />

write ( * , * ) ’ l e r a d i c i sono complesse ’<br />

else<br />

x1= ( −b + sqrt ( delta ) ) / ( 2 . * a )<br />

write ( * , * ) ’ x1 = ’ , x1<br />

x2= ( −b − sqrt ( delta ) ) / ( 2 . * a )<br />

write ( * , * ) ’ x2 = ’ , x2<br />

end i f<br />

stop<br />

end<br />

Complichiamo la seconda parte del programma, andando a scrivere le ra<strong>di</strong>ci coincidenti nel caso in cui<br />

∆ = 0 e utilizzando la formula alternativa (dalla considerazione che x 1 x 2 = c/a) per evitare il fenomeno <strong>di</strong><br />

cancellazione numerica.<br />

i f ( delta . l t . 0 ) then<br />

write ( * , * ) ’ l e r a d i c i sono complesse ’<br />

else i f ( delta . eq . 0 . d0 ) then<br />

x1= −b/ ( 2 . 0 d0*a )<br />

x2=x1<br />

write ( * , * ) ’ l e r a d i c i sono : ’ , x1 , x2<br />

else<br />

x1= ( −b + sqrt ( delta ) ) / ( 2 . * a )<br />

x2= ( −b − sqrt ( delta ) ) / ( 2 . * a )<br />

write ( * , * ) ’ l e r a d i c i sono : ’ , x1 , x2<br />

i f ( ab ( x1 ) . gt . abs ( x2 ) ) then<br />

x2= c / ( x1 *a )<br />

write ( * , * ) ’ x2 con formula a lternativa ’ , x2<br />

else<br />

x1= c / ( x2 *a )<br />

write ( * , * ) ’ x1 con formula a lternativa ’ , x1<br />

end i f<br />

end i f<br />

Il ciclo if non basta per scrivere tutti i nostri programmi. Pensiamo ad un blocco <strong>di</strong> istruzioni da ripetere<br />

molte volte, fino a quando è vera una determinata con<strong>di</strong>zione. In questo caso, si usa il ciclo do while<br />

(pensiamo all’algoritmo visto per il metodo <strong>di</strong> bisezione, o allo schema <strong>di</strong> punto fisso).<br />

Ciclo do<br />

while<br />

171


11. INTRODUZIONE AL FORTRAN 77<br />

do while ( espressione logica )<br />

{ istruzione 1 }<br />

{ istruzione 2 }<br />

{ . . . }<br />

{ istruzione n }<br />

end do<br />

Fintantochè è vera l’espressione logica<br />

allora esegui istruzione 1, 2, . . . , n.<br />

Le istruzioni 1, 2, . . . vengono ripetute ciclicamente (non una volta sola come nel ciclo if). Quando si<br />

esegue l’ultima istruzione posta all’interno del ciclo, si torna all’espressione logica e si controlla se è vera o<br />

falsa. Se è vera, si eseguono <strong>di</strong> nuovo le istruzioni 1, 2, . . . ,n. Se non è vera, si esce dal ciclo while. Occorre<br />

dunque prestare attenzione a non creare cicli infiniti!<br />

11.11 Programma sul metodo <strong>di</strong> punto fisso<br />

Consideriamo l’algoritmo dello schema <strong>di</strong> punto fisso<br />

x n+1 = cos(x n )<br />

e proviamo a scrivere un programma FORTRAN che ci permetta <strong>di</strong> trovare una buona approssimazione del<br />

punto fisso ξ (sempre che lo schema converga). I dati <strong>di</strong> input che dobbiamo dare al programma sono:<br />

G l’approssimazione iniziale x 0<br />

G la tolleranza ε con cui vogliamo approssimare il punto fisso<br />

G il numero massimo <strong>di</strong> iterazioni entro cui cercare la convergenza dello schema (per evitare cicli infiniti).<br />

I dati <strong>di</strong> output che possiamo chiedere al programma sono:<br />

G l’approssimazione x n+1 ad ogni passo<br />

G l’iterazione n<br />

G lo scarto ad ogni passo: |x n+1 − x n |<br />

G una stima della costante asintotica dell’errore M.<br />

Cerchiamo ora <strong>di</strong> capire come gestire le variabili per x n e x n+1 e per gli scarti ad ogni passo. Con il metodo<br />

<strong>di</strong> punto fisso, si crea una successione <strong>di</strong> valori: x 0 , x 1 , x 2 , . . . x n . . . . Nella teoria, per n che tende all’infinito,<br />

la successione può convergere al punto fisso. Nella pratica ci si arresta quando lo scarto (il valore assoluto tra<br />

due iterazioni successive) è minore <strong>di</strong> una certa tolleranza. A priori, tuttavia, non sappiamo quante iterazioni<br />

dobbiamo fare. Potremmo pensare <strong>di</strong> memorizzare le varie approssimazioni x n in un vettore che abbia una<br />

<strong>di</strong>mensione molto elevata. Ma ci sono due inconvenienti:<br />

1. Non sappiamo ancora come scrivere in un programma FORTRAN un vettore.<br />

2. Supposto <strong>di</strong> saperlo fare, possiamo e dobbiamo evitarlo perchè non serve conservare in memoria tutti<br />

le approssimazioni che generiamo (x n+1 <strong>di</strong>pende dal valore x n e basta). Se ci interessano i valori generati<br />

dall’algoritmo, li possiamo scrivere <strong>di</strong> volta in volta sul video (meglio su un file! vedremo poi come<br />

scrivere dati <strong>di</strong> output su un file).<br />

Lavoreremo facendo uso <strong>di</strong> due variabili: xold che corrisponde a x n e xnew che corrisponde a x n+1 . Diamo<br />

in input il valore iniziale x 0 . Dobbiamo effettuare la prima iterazione cioè trovare x 1 = cos(x 0 ).<br />

G Porremo xold=x0 e poi xnew= cos(xold) per l’iterazione iter=1. xnew ha il significato <strong>di</strong> x 1 .<br />

G Una volta fatta la prima iterazione, il valore <strong>di</strong> xold=x0 non ci interessa più. Per iter=iter+1=2,<br />

ci serve calcolare x 2 = cos(x 1 ). Proprio perchè il valore <strong>di</strong> xold non serve più assegniamo a xold il<br />

valore calcolato per x 1 =xnew in modo da poter sfruttare la relazione <strong>di</strong> prima. Applicheremo <strong>di</strong> nuovo<br />

la formula xnew= cos(xold) dove ora xnew ha il significato <strong>di</strong> x 2 e xold <strong>di</strong> x 1 .<br />

G Alla fine del secondo passo, quin<strong>di</strong> xnew=x 2 e xold=x 1<br />

G Ora x 1 non serve più. Per iter=iter+1=3, ci serve solo x 2 . Perciò faremo xold=xnew,<br />

xnew=cos(xold) e avremo xnew=x 3 . E così via. . .<br />

172


11.11. Programma sul metodo <strong>di</strong> punto fisso<br />

xold=x0<br />

i t e r =0<br />

scartonew =2.0d0* t o l l<br />

do while ( ( scartonew . ge . t o l l ) . and . ( i t e r . l e . itmax ) )<br />

i t e r = i t e r +1<br />

xnew=cos ( xold )<br />

scartonew=abs (xnew− xold )<br />

write ( * , * ) i t e r , xnew<br />

xold=xnew<br />

end do<br />

La variabile scartonew ha il significato dello scarto x n − x n−1 | e, <strong>di</strong>fatti, viene <strong>di</strong> volta in volta aggiornata<br />

come scartonew=abs(xnew−xold). Prima <strong>di</strong> iniziare il ciclo do while è posto scartonew=2.0d0*toll, una quantità<br />

più grande della tolleranza, perchè così, la prima volta che si entra nel ciclo do while, la proposizione<br />

logica ad essa legata è vera. Difatti, quando si entra nel ciclo do while scartonew=2.0d0*toll > toll<br />

e iter=0< itmax. Si eseguono le istruzioni del ciclo do while fino a quando rimane vera la proposizione<br />

(scartonew.ge.toll) .and. (iter . le .itmax) . Si esce dal ciclo do while quando scartonew < toll oppure<br />

quando iter > itmax.<br />

Sappiamo che, per lo schema <strong>di</strong> punto fisso, vale lim n→∞<br />

|ξ − x n |<br />

|ξ − x n−1<br />

= M = |g ′ (ξ)|. Poichè non conosciamo<br />

l’errore, ma possiamo calcolare lo scarto e, per n → ∞, vale |ξ − x n | ≈ |x n − x n−1 |, abbiamo due mo<strong>di</strong> per<br />

stimare M:<br />

1. calcolare il rapporto tra gli scarti a due passi successivi<br />

2. calcolare |g ′ (x n )|.<br />

Per calcolare il rapporto tra gli scarti a due passi successivi introduciamo un’altra variabile, che chiamiamo<br />

scartold, che corrisponde allo scarto |x n−1 −x n−2 |. L’aggiornamento <strong>di</strong> scartonew e scartold viene<br />

fatto in maniera del tutto analoga a quanto visto per xold e xnew.<br />

Nel co<strong>di</strong>ce calcoliamo quin<strong>di</strong> due stime <strong>di</strong> M, utilizzando le variabili che chiamiamo asint1 e asint2.<br />

Ve<strong>di</strong>amo il co<strong>di</strong>ce completo.<br />

program puntofisso<br />

C programma per i l calcolo del punto f i s s o per g ( x)= cos ( x ) in [ 0 , pi / 2 ]<br />

implicit none<br />

C<br />

C s i g n i f i c a t o d e l l e v a r i a b i l i<br />

C i t e r : i t e r a z i o n e del metodo del punto f i s s o<br />

C itmax : numero massimo <strong>di</strong> i t e r a z i o n i<br />

C t o l l : tolleranza p r e f i s s a t a per l ’ approssimazione<br />

C del punto f i s s o<br />

C x0 : punto i n i z i a l e della successione<br />

C xold : approssimazione al passo n−1<br />

C xnew : approssimazione al passo n<br />

C s c a r t o l d : scarto all ’ i t e r a t a precedente<br />

C scartonew : valore assoluto tra l ’ i t e r a t a corrente e quella al<br />

C passo precedente<br />

C asint1 : scartonew / s c a r t o l d − approssimazione <strong>di</strong> M<br />

C asint2 : abs(− sin (xnew ) ) − approssimazione <strong>di</strong> M<br />

integer i t e r , itmax<br />

real *8 x0 , xold , xnew , scartold , scartonew , t o l l<br />

real *8 asint1 , asint2<br />

write ( * , * ) ’ approssimazione i n i z i a l e ’<br />

read ( * , * ) x0<br />

write ( * , * ) ’ x0 = ’ , x0<br />

itmax=100<br />

t o l l =1.d−10<br />

173


11. INTRODUZIONE AL FORTRAN 77<br />

scartonew =2.0* t o l l<br />

scartold=scartonew<br />

i t e r = 0<br />

xold=x0<br />

write ( * , * ) ’ i t xnew scarto<br />

1 asint1 asint2 ’<br />

write ( * , * ) i t e r , xold , scartonew<br />

do while ( ( scartonew . ge . t o l l ) . and . ( i t e r . l e . itmax ) )<br />

i t e r = i t e r +1<br />

xnew=cos ( xold )<br />

scartonew=abs (xnew− xold )<br />

asint1= scartonew/ scartold<br />

asint2=abs(− sin (xnew ) )<br />

write ( * , * ) i t e r , xnew , scartonew , asint1 , asint2<br />

xold=xnew<br />

scartold=scartonew<br />

end do<br />

stop<br />

end<br />

11.12 I sottoprogrammi<br />

Quando l’algoritmo e il problema su cui stiamo lavorando sono complicati, conviene spezzare il problema<br />

in sottoproblemi in modo da semplificare la programmazione.<br />

Analogamente, al posto <strong>di</strong> avere un unico programma in FORTRAN, conviene scrivere il programma<br />

facendo uso <strong>di</strong> sottoprogrammi. Si hanno due tipi <strong>di</strong> sottoprogrammi in FORTRAN:<br />

G subroutines,<br />

G functions.<br />

In tal modo un programma FORTRAN può risultare composto da:<br />

G programma principale,<br />

G una o più subroutines,<br />

G una o più functions.<br />

11.12.1 Le functions<br />

Esempio <strong>di</strong><br />

function gfun<br />

Il programma che abbiamo scritto funziona bene ma ha un punto debole: se vogliamo applicare lo<br />

schema <strong>di</strong> punto fisso ad un’altra funzione g , dobbiamo andare a cambiare le istruzioni xnew=cos(xold) e<br />

asint2=abs(−sin(xnew)). E se la funzione è complicata? E se dobbiamo valutare la stessa funzione (o le stesse<br />

funzioni) anche su altre parti del programma?<br />

Introduciamo il concetto <strong>di</strong> function in FORTRAN. Una function è del tutto simile al concetto <strong>di</strong><br />

funzione scalare, che può essere definita in un sottoinsieme <strong>di</strong> R n ma ha valori in R. Difatti una function<br />

può avere uno o più dati <strong>di</strong> input e un solo dato <strong>di</strong> output.<br />

Ve<strong>di</strong>amo come scrivere il programma precedente facendo uso delle functions.<br />

Nello stesso file (per semplicità) in cui abbiamo scritto il programma principale fisso.f, dopo le istruzioni<br />

stop e end che chiudono il programma principale, dopo aver lasciato qualche riga bianca per mostrare che<br />

finisce il programma principale, andremo a scrivere la nostra prima function<br />

stop<br />

end<br />

C f i n e del programma principale<br />

real *8 function gfun ( x )<br />

C funzione <strong>di</strong> punto f i s s o<br />

implicit none<br />

174


11.12. I sottoprogrammi<br />

real *8 x<br />

gfun=cos ( x )<br />

return<br />

end<br />

La funzione che stiamo scrivendo è <strong>di</strong> tipo real*8 ed è la prima cosa che scriviamo per identificarla. C’è poi<br />

la parola function e poi gfun(x). gfun ha un duplice significato: è il nome della function ma è anche<br />

il nome della variabile che contiene il risultato dell’esecuzione della function gfun.<br />

Il corpo della function è del tutto analogo a quello che si ha in un programma principale: implicit none,<br />

<strong>di</strong>chiarazione delle variabili, istruzioni. Tutte le istruzioni servono ad assegnare il valore alla variabile gfun.<br />

La function termina con le istruzioni return (per ritornare nel programma da cui è stata chiamata) e<br />

end.<br />

La funzione in questo caso <strong>di</strong>pende da una sola variabile, che chiamiamo x. La variabile (o le variabili)<br />

da cui <strong>di</strong>pende una function deve essere dello stesso tipo (<strong>di</strong>chiarata allo stesso modo) sia all’interno della<br />

function sia nel programma principale, ma può avere nomi <strong>di</strong>versi (x, xold).<br />

Per la derivata prima la function è la seguente:<br />

real *8 function dgfun ( x )<br />

C derivata della funzione <strong>di</strong> punto f i s s o<br />

implicit none<br />

real *8 x<br />

dgfun= −sin ( x )<br />

return<br />

end<br />

Esempio <strong>di</strong><br />

function<br />

dgfun<br />

Come cambia il programma principale?<br />

Nella <strong>di</strong>chiarazione delle variabili dobbiamo <strong>di</strong>chiarare le due function gfun e dgfun<br />

integer i t e r , itmax<br />

real *8 x0 , xold , xnew , scartold , scartonew , t o l l<br />

real *8 asint1 , asint2<br />

real *8 gfun , dgfun<br />

Un’altra istruzione (opzionale) è <strong>di</strong>re che ci sono due sottoprogrammi esterni al programma principale,<br />

subito dopo la <strong>di</strong>chiarazione delle variabili:<br />

integer i t e r , itmax<br />

real *8 x0 , xold , xnew , scartold , scartonew , t o l l<br />

real *8 asint1 , asint2<br />

real *8 gfun , dgfun<br />

external gfun , dgfun<br />

Infine, nel ciclo while, dove abbiamo bisogno della funzione <strong>di</strong> punto fisso e della sua derivata, si ha:<br />

do while ( ( scartonew . ge . t o l l ) . and . ( i t e r . l e . itmax ) )<br />

i t e r = i t e r +1<br />

xnew=gfun ( xold )<br />

scartonew=abs (xnew− xold )<br />

asint1= scartonew/ scartold<br />

asint2=abs ( dgfun (xnew ) )<br />

write ( * , * ) i t e r , xnew , scartonew , asint1 , asint2<br />

xold=xnew<br />

scartold=scartonew<br />

end do<br />

G Una function, dunque, è un sottoprogramma del programma principale.<br />

G Una function viene chiamata <strong>di</strong>rettamente: xnew=gfun(xold).<br />

G La function restituisce un valore ben preciso – il valore assunto dalla funzione stessa in funzione dei<br />

parametri. Perciò deve essere <strong>di</strong>chiarato il tipo della function (integer, real, real*8, . . . )<br />

175


11. INTRODUZIONE AL FORTRAN 77<br />

G La function restituisce un solo valore: gfun=cos(x).<br />

G La function può avere uno o più parametri in ingresso.<br />

G Per scrivere una function si usa l’istruzione <strong>di</strong> implicit none, si <strong>di</strong>chiarano tutte le variabili che sono<br />

usate all’interno della function, si scrivono tutte le istruzioni che servono (anche cicli if, o while se<br />

occorrono).<br />

G La function termina con le istruzioni <strong>di</strong> return e end.<br />

Ve<strong>di</strong>amo ora un altro esempio per cercare <strong>di</strong> capire meglio il concetto e l’uso delle functions.<br />

Esempio 11.12.1 Supponiamo <strong>di</strong> dover scrivere un semplice programma che, dati in input, due valori a e<br />

b, valuta la funzione f (x) = x 2 + 1 + e −x per x = a e per x = b, stampando i risultati. Per la funzione f (x)<br />

si deve utilizzare una function che chiameremo fun. Il programma può essere <strong>di</strong> questo tipo<br />

program esempiousofunzioni<br />

implicit none<br />

real *8 a , b , c , d<br />

real *8 fun<br />

write ( * , * ) ’ s c r i v i valore a ’<br />

read ( * , * ) a<br />

write ( * , * ) ’ s c r i v i valore b ’<br />

read ( * , * ) b<br />

C la v a r i a b i l e c ha i l valore della funzione fun in a<br />

c=fun ( a )<br />

C la v a r i a b i l e d ha i l valore della funzione fun in b<br />

d=fun (b)<br />

write ( * , * ) ’ a = ’ , a , ’ f ( a)= ’ , c<br />

write ( * , * ) ’b = ’ , b , ’ f (b)= ’ , d<br />

return<br />

end<br />

real *8 function fun ( x )<br />

implicit none<br />

real *8 x<br />

fun=sqrt ( x **2+1.0) +exp(−x )<br />

return<br />

end<br />

Un errore molto comune, nel fare programmi <strong>di</strong> questo tipo, in cui una function viene chiamata più volte in<br />

modo sequenziale (cioè non all’interno <strong>di</strong> un ciclo while) è quello <strong>di</strong> scrivere la stessa function tante volte<br />

quante viene chiamata all’interno del programma!!! In questo caso un programma ERRATO sarebbe scritto<br />

in questo modo<br />

program esempiousofunzioni<br />

C ATTENZIONE ! ! ! ! ! ! ! ! !<br />

C QUESTO E ’ UN ESEMPIO DI PROGRAMMA NON CORRETTO ! ! ! !<br />

C Durante la compilazione s i ha i l seguente messaggio <strong>di</strong> e r r o r e :<br />

C Global name ’ fun ’ at ( 1 ) i s already being used as a FUNCTION at ( 2 )<br />

implicit none<br />

real *8 a , b , c , d<br />

real *8 fun<br />

write ( * , * ) ’ s c r i v i valore a ’<br />

read ( * , * ) a<br />

write ( * , * ) ’ s c r i v i valore b ’<br />

read ( * , * ) b<br />

C la v a r i a b i l e c ha i l valore della funzione fun in a<br />

176


11.12. I sottoprogrammi<br />

c=fun ( a )<br />

C la v a r i a b i l e d ha i l valore della funzione fun in b<br />

d=fun (b)<br />

write ( * , * ) ’ a = ’ , a , ’ f ( a)= ’ , c<br />

write ( * , * ) ’b = ’ , b , ’ f (b)= ’ , d<br />

stop<br />

end<br />

real *8 function fun ( a )<br />

implicit none<br />

real *8 a<br />

fun=sqrt ( a **2+1.0) +exp(−a )<br />

return<br />

end<br />

real *8 function fun (b)<br />

implicit none<br />

real *8 b<br />

fun=sqrt (b**2+1.0) +exp(−b)<br />

return<br />

end<br />

La function fun è sempre la stessa. Perchè riscriverla due volte? All’interno del programma principale,<br />

la function viene dapprima chiamata per essere valutata nel punto a e poi per essere valutata nel punto b.<br />

La function fun va scritta solo una volta (noi l’abbiamo fatta <strong>di</strong>pendere da una generica variabile scalare<br />

x, ma potremmo farla <strong>di</strong>pendere anche da una variabile che chiamiamo a o b). Sottolineiamo il fatto che<br />

le variabili da cui <strong>di</strong>pende la function devono avere lo stesso significato nel programma principale, ma non<br />

necessariamente gli stessi nomi.<br />

Quello che succede nel programma potrebbe essere descritto sinteticamente nel modo seguente:<br />

programma<br />

.<br />

.<br />

.<br />

c=fun(a) −→<br />

Il programma chiama la<br />

function fun.<br />

Nella function x = a.<br />

La function restituisce in c<br />

il valore<br />

fun(a).<br />

d=fun(b) −→<br />

.<br />

.<br />

Il programma chiama la<br />

function fun.<br />

Nella function x = b.<br />

La function restituisce in c<br />

il valore<br />

fun(b).<br />

177


11. INTRODUZIONE AL FORTRAN 77<br />

11.12.2 Le subroutines<br />

Possiamo pensare <strong>di</strong> cambiare ancora il programma per l’approssimazione del punto fisso, utilizzando<br />

un <strong>di</strong>verso approccio: la parte che riguarda le iterazioni dello schema del punto fisso la facciamo fare ad un<br />

sottoprogramma che chiameremo, in qualche modo, nel programma principale. Scomporre il programma<br />

principale in più sottoprogrammi ha il suo vantaggio nel momento in cui gli algoritmi che dobbiamo implementare<br />

<strong>di</strong>ventano via via più complicati, oppure se una parte <strong>di</strong> un programma viene ripetuta più volte (e<br />

anzichè scrivere righe e righe <strong>di</strong> istruzioni da eseguire, le scriviamo solo una volta nel sottoprogramma e poi<br />

le richiamiamo dove occorre).<br />

program puntofisso<br />

implicit none<br />

integer i t e r , itmax<br />

real *8 x0 , xnew , t o l l<br />

external i t e r p f i s s o<br />

write ( * , * ) ’ approssimazione i n i z i a l e ’<br />

read ( * , * ) x0<br />

write ( * , * ) ’ x0 = ’ , x0<br />

itmax=100<br />

t o l l =1.d−10<br />

i t e r = 0<br />

c a l l i t e r p f i s s o ( i t e r , itmax , x0 , t o l l , xnew)<br />

write ( * , * ) ’ approssimazione f i n a l e ’ , xnew<br />

write ( * , * ) ’ i t e r a z i o n i e f f e t t u a t e ’ , i t e r<br />

stop<br />

end<br />

Osserviamo che la subroutine è chiamata tramite l’istruzione<br />

call iterpfisso( iter ,itmax,x0,toll,xnew)<br />

G Abbiamo parametri <strong>di</strong> input: iter, itmax, x0, toll.<br />

G Ci sono parametri <strong>di</strong> output: xnew.<br />

G Alcuni dei parametri <strong>di</strong> input (in questo caso iter), vengono mo<strong>di</strong>ficati all’interno della subroutine, altri<br />

no.<br />

G Nel programma principale non sono <strong>di</strong>chiarate le variabili che usiamo soltanto all’interno della<br />

subroutine (xold, scartonew, scartold, asint1, asint2, le due functions gfun e dgfun).<br />

Per scrivere la subroutine, lasciamo qualche riga vuota dopo le istruzioni stop e end del programma principale<br />

e scriviamo la subroutine prima delle functions (o dopo, non cambia niente). L’importante è che si<br />

scriva tutto il programma principale completo, tutta la/le subroutine complete, tutte la/le functions complete<br />

(senza che pezzi <strong>di</strong> subroutine o <strong>di</strong> functions o <strong>di</strong> programma principale si intersechino tra <strong>di</strong> loro nella<br />

scrittura!!!!)<br />

Esempio <strong>di</strong><br />

subroutine:<br />

iterpfisso subroutine i t e r p f i s s o ( i t e r , itmax , x0 , t o l l , xnew)<br />

C sottoprogramma che implementa l ’ algoritmo del metodo <strong>di</strong> punto f i s s o<br />

178<br />

implicit none<br />

integer i t e r , itmax<br />

real *8 x0 , xnew , xold , t o l l , scnew , scold , asint1 , asint2<br />

real *8 gfun , dgfun<br />

external gfun , dgfun<br />

scnew=2.0* t o l l<br />

scold=scnew<br />

xold=x0<br />

write ( * , * ) ’ i t xkp1 scarto<br />

1 asint1 asint2 ’<br />

write ( * , * ) i t e r , xold , scnew<br />

do while ( ( scnew . ge . t o l l ) . and . ( i t e r . l e . itmax ) )<br />

i t e r = i t e r +1<br />

xnew=gfun ( xold )


11.12. I sottoprogrammi<br />

scnew=abs (xnew− xold )<br />

asint1= scnew/ scold<br />

asint2=abs ( dgfun (xnew ) )<br />

write ( * , * ) i t e r , xnew , scnew , asint1 , asint2<br />

xold=xnew<br />

scold=scnew<br />

end do<br />

return<br />

end<br />

G Una subroutine inizia con l’istruzione subroutine nomesubroutine(lista <strong>di</strong> parametri)<br />

G il nome <strong>di</strong> una subroutine non può essere uguale a quello <strong>di</strong> altre variabili utilizzate;<br />

G il “corpo” della subroutine è analogo a quello <strong>di</strong> un programma principale (implicit none, <strong>di</strong>chiarazione<br />

delle variabili, istruzioni, cicli. . . );<br />

G la subroutine si chiude con le istruzioni return e end<br />

G la subroutine è chiamata nel programma principale tramite l’istruzione<br />

call nomesubroutine(parametri)<br />

Il fatto che noi chiamiamo una subroutine nel programma principale (call) <strong>di</strong>ce che la subroutine non è un<br />

programma a sè stante. Quando termina l’esecuzione <strong>di</strong> ciò che è scritto all’interno della subroutine si torna<br />

in<strong>di</strong>etro nel programma principale e si continua l’elaborazione da quel punto. L’istruzione return fa tornare<br />

al programma principale. Le variabili non devono avere necessariamente lo stesso nome nel programma<br />

principale e nella subroutine. Per esempio, possiamo scrivere:<br />

call iterpfisso( iter ,itmax,x0,toll,xnew) nel programma principale<br />

subroutine iterpfisso(it,itmassime,x0,toll,xnew) nella subroutine.<br />

L’importante è che le variabili abbiamo lo stesso significato (stesso tipo <strong>di</strong> variabile, ma anche stessa<br />

valenza <strong>di</strong> variabile) e devono essere messe nello stesso or<strong>di</strong>ne: se nel programma principale scriviamo<br />

call iterpfisso(itmax,iter,x0, toll ,xnew) ma poi nella subroutine scambiamo il ruolo <strong>di</strong> itmax e <strong>di</strong> iter,<br />

subroutine iterpfisso(it,itmassime,x0,toll,xnew) ,<br />

all’interno della subroutine è assegnato a it il valore <strong>di</strong> itmax, mentre a itmassime è assegnato il valore <strong>di</strong> iter<br />

(che è zero all’inizio). . . ..<br />

All’interno della subroutine si possono utilizzare altre variabili oltre a quelle che sono presenti tra i parametri<br />

della stessa. L’importante è <strong>di</strong>chiararle nella subroutine. Tali variabili non passano nel programma<br />

principale ma sono usate solo nella subroutine. In questo esempio xold, scnew, scold, asint1, asint2, gfun,<br />

dgfun sono usate solo nella subroutine.<br />

Ve<strong>di</strong>amo un altro esempio <strong>di</strong> programma con uso <strong>di</strong> subroutines.<br />

Esempio 11.12.2 Scriviamo un programma che, assegnate tre variabili, che chiamiamo a, b e c, considera<br />

le possibili coppie <strong>di</strong> punti che si possono formare e calcola la corrispondente me<strong>di</strong>a geometrica e me<strong>di</strong>a<br />

aritmetica. Le possibili coppie <strong>di</strong> punti sono: a-b, a-c, b-c. Per calcolare il valor me<strong>di</strong>o <strong>di</strong> ciascuna coppia,<br />

utilizziamo una subroutine che chiamiamo me<strong>di</strong>e. Un possibile programma è il seguente.<br />

program me<strong>di</strong>e_arit_geom<br />

implicit none<br />

real *8 a , b , c<br />

real *8 me<strong>di</strong>a1 , me<strong>di</strong>a2<br />

write ( * , * ) ’ s c r i v i t r e numeri a , b , c ’<br />

read ( * , * ) a , b , c<br />

c a l l me<strong>di</strong>e ( a , b , me<strong>di</strong>a1 , me<strong>di</strong>a2 )<br />

write ( * , * ) ’ coppie <strong>di</strong> punti : ’ , a , b<br />

write ( * , * ) ’me<strong>di</strong>a aritmetica ’ , me<strong>di</strong>a1<br />

write ( * , * ) ’me<strong>di</strong>a geometrica ’ , me<strong>di</strong>a2<br />

179


11. INTRODUZIONE AL FORTRAN 77<br />

c a l l me<strong>di</strong>e ( a , c , me<strong>di</strong>a1 , me<strong>di</strong>a2 )<br />

write ( * , * ) ’ coppie <strong>di</strong> punti : ’ , a , c<br />

write ( * , * ) ’me<strong>di</strong>a aritmetica ’ , me<strong>di</strong>a1<br />

write ( * , * ) ’me<strong>di</strong>a geometrica ’ , me<strong>di</strong>a2<br />

c a l l me<strong>di</strong>e (b , c , me<strong>di</strong>a1 , me<strong>di</strong>a2 )<br />

write ( * , * ) ’ coppie <strong>di</strong> punti : ’ , b , c<br />

write ( * , * ) ’me<strong>di</strong>a aritmetica ’ , me<strong>di</strong>a1<br />

write ( * , * ) ’me<strong>di</strong>a geometrica ’ , me<strong>di</strong>a2<br />

stop<br />

end<br />

subroutine me<strong>di</strong>e ( a , b , me<strong>di</strong>a_aritm , me<strong>di</strong>a_geom)<br />

implicit none<br />

real *8 a , b , me<strong>di</strong>a_aritm , me<strong>di</strong>a_geom<br />

me<strong>di</strong>a_aritm= ( a+b ) * 0 . 5<br />

me<strong>di</strong>a_geom=sqrt ( a*b)<br />

return<br />

end<br />

In questo caso la subroutine ha come variabili, nell’or<strong>di</strong>ne, i due punti <strong>di</strong> cui calcolare la me<strong>di</strong>a aritmetica e<br />

geometrica, il valore della me<strong>di</strong>a aritmetica, il valore della me<strong>di</strong>a geometrica. Osserviamo che, nel programma<br />

principale, la subroutine viene chiamata tre volte. Poichè, dopo ogni chiamata, ci facciamo stampare il<br />

valore della me<strong>di</strong>a aritmetica e della me<strong>di</strong>a geometrica, abbiamo usato solo due variabili, rispettivamente<br />

me<strong>di</strong>a1 e me<strong>di</strong>a2. Ad ogni chiamata della subroutine, i valori ottenuti alla chiamata precedente vengono persi<br />

perchè sostituiti dai nuovi valori che si ottengono. Se, nel programma, dovessimo utilizzare tutti i valori<br />

delle me<strong>di</strong>e ottenute per le tre coppie <strong>di</strong> punti, non potremmo sovrascriverli ma dovremmo utilizzare sei variabili<br />

<strong>di</strong>stinte. Osserviamo, ancora una volta, che abbiamo un’unica subroutine che viene chiamata più volte<br />

all’interno del programma principale.<br />

11.13 Il formato<br />

Programma<br />

<strong>di</strong> punto fisso<br />

con<br />

l’istruzione<br />

format<br />

Fino ad ora abbiamo stampato i risultati dei nostri programmi su video e senza aver dato nessuna<br />

in<strong>di</strong>cazione su come visualizzare i dati.<br />

Per avere un output elegante e or<strong>di</strong>nato, conviene usare l’istruzione format.<br />

Ve<strong>di</strong>amo questa istruzione <strong>di</strong>rettamente all’interno <strong>di</strong> un programma d’esempio (quello del punto fisso<br />

appena visto nelle le righe <strong>di</strong> co<strong>di</strong>ce relative al ciclo do while, il resto rimane invariato)<br />

do while ( ( scartonew . ge . t o l l ) . and . ( i t e r . l e . itmax ) )<br />

i t e r = i t e r +1<br />

xnew=gfun ( xold )<br />

scartonew=abs (xnew− xold )<br />

asint1= scartonew/ scartold<br />

asint2=abs ( dgfun (xnew ) )<br />

write ( * , 1 0 0 ) i t e r , xnew , scartonew , asint1 , asint2<br />

xold=xnew<br />

scartold=scartonew<br />

end do<br />

100 format (1 x , i4 , 1 x , f15 .12 ,1 x , e14 . 6 , 1x , 2e13 . 5 )<br />

Nell’istruzione write, non abbiamo scritto write(*,*) ma write(*,100). Al posto del secondo simbolo *<br />

abbiamo messo un numero (un’etichetta).<br />

Questo numero lo si trova scritto alla fine del ciclo while (ma possiamo metterlo ovunque all’interno del<br />

programma – dopo la <strong>di</strong>chiarazione delle variabili e prima della end finale) a partire dalla seconda colonna.<br />

Dopo aver scritto il numero che contrad<strong>di</strong>stingue il formato, abbiamo l’istruzione format e, tra parentesi,<br />

abbiamo tutte le in<strong>di</strong>cazioni su come rappresentare le variabili della stampa cui ci si riferisce:<br />

format(1x,i4,1x,f15.12,1x,e14.6,1x,2e13.5)<br />

Nell’esempio particolare:<br />

180


11.13. Il formato<br />

G 1x significa: lascia uno spazio bianco sulla riga;<br />

G i4 significa: 4 caratteri riservati per la prima variabile che è <strong>di</strong> tipo intero (iter);<br />

G f15.12 : scrivi il valore della variabile xnew in formato fisso, riservando 15 caratteri per il numero <strong>di</strong> cui<br />

12 per la parte decimale;<br />

G e14.6: scrivi il valore <strong>di</strong> scartonew in formato esponenziale, riservando 14 caratteri per il numero, <strong>di</strong><br />

cui 6 per la mantissa;<br />

G 2e13.5 : scrivi i 2 numeri successivi asint1 e asint2 nello stesso formato esponenziale, riservando a<br />

ciascuno <strong>di</strong> essi 13 caratteri <strong>di</strong> cui 5 per la mantissa.<br />

formato<br />

i<br />

e<br />

f<br />

a<br />

x<br />

Significato<br />

formato intero<br />

esponenziale<br />

fisso<br />

alfanumerico<br />

spazi bianchi<br />

Tabella 11.6: Il formato<br />

formato<br />

i<br />

e<br />

f<br />

a<br />

x<br />

Esempio<br />

i5 – 5 caratteri per un intero<br />

e14.6 – 14 caratteri, 6 per la mantissa<br />

e18.10 – 18 caratteri, 10 per la mantissa<br />

f14.6 – 14 caratteri, 6 per le cifre decimali<br />

f15.12 – 15 caratteri, 12 per le cifre decimali<br />

a5 – una stringa <strong>di</strong> al più 5 caratteri<br />

1x – 1 carattere bianco<br />

3x – 3 caratteri bianchi<br />

Tabella 11.7: Esempi <strong>di</strong> formato<br />

Specificando il formato, occorre prestare attenzione al fatto che non tutti i numeri possono essere stampati<br />

correttamente. Per esempio se un intero ha più <strong>di</strong> 5 caratteri (per esempio 100150) ma il formato per esso<br />

è i5, vengono stampati <strong>degli</strong> * o altri caratteri a seconda del compilatore. Se si hanno strani risultati in output<br />

usando un formato, togliere il formato, compilare e rieseguire il programma per verificare se l’errore <strong>di</strong>pende<br />

dal formato!<br />

Lo stesso formato può essere utilizzato da più righe <strong>di</strong> write se il formato si riferisce a variabili dello<br />

stesso tipo. Le stringhe <strong>di</strong> caratteri possono essere scritte me<strong>di</strong>ante un formato opportuno.<br />

Ve<strong>di</strong>amo <strong>di</strong> nuovo il programma <strong>di</strong> prima:<br />

i t e r = 0<br />

xold=x0<br />

write ( * , 9 8 ) ’ i t ’ , ’ xk ’ , ’ scarto ’ , ’ asint1 ’ , ’ asint2 ’<br />

write ( * , 9 9 ) i t e r , xold , scartonew<br />

do while ( ( scartonew . ge . t o l l ) . and . ( i t e r . l e . itmax ) )<br />

C t u t t o invariato come prima<br />

write ( * , 1 0 0 ) i t e r , xnew , scartonew , asint1 , asint2<br />

xold=xnew<br />

scartold=scartonew<br />

end do<br />

98 format (1 x , a4 , 1 x , a15 , 1 x , a14 , 1 x , 2 a13 )<br />

99 format (1 x , i4 , 1 x , f15 .12 ,1 x , e14 . 6 )<br />

100 format (1 x , i4 , 1 x , f15 .12 ,1 x , e14 . 6 , 1x , 2e13 . 5 )<br />

181


11. INTRODUZIONE AL FORTRAN 77<br />

stop<br />

end<br />

Per le stringhe è stato usato un formato riservando a ciascuna stringa lo stesso numero <strong>di</strong> caratteri riservati<br />

alle variabili corrispondenti cui si riferiscono le stringhe. In tal modo, si riesce a creare una tabellina <strong>di</strong><br />

risultati messi in colonna l’uno dopo l’altro in maniera or<strong>di</strong>nata.<br />

11.14 Files <strong>di</strong> dati<br />

Esempio <strong>di</strong><br />

file <strong>di</strong> dati<br />

Piuttosto che visualizzarli sulla finestra <strong>di</strong> shell del computer, conviene salvare i risultati in un file <strong>di</strong> dati.<br />

Il modo più semplice per fare questo è far sì che durante l’esecuzione del programma venga generato un file<br />

<strong>di</strong> scrittura <strong>di</strong> dati: si apre il file all’interno del programma principale associando ad esso un numero (label)<br />

me<strong>di</strong>ante l’istruzione open. Per esempio, dopo la <strong>di</strong>chiarazione delle variabili, scriviamo<br />

open(10, file=’rispuntofisso.txt’)<br />

Le istruzioni <strong>di</strong> write saranno poi associate a quella label e scritte su quel file.<br />

Quin<strong>di</strong>, al posto <strong>di</strong> scrivere write(*,98) andremo a scrivere write(10,98) perchè dobbiamo scrivere la stampa<br />

dei risultati sul file contrassegnato dall’etichetta 10.<br />

Prima <strong>di</strong> chiudere il programma, chiu<strong>di</strong>amo il file con l’istruzione close.<br />

close(10)<br />

program puntofisso<br />

C programma <strong>di</strong> punto f i s s o<br />

C t u t t o come prima<br />

C <strong>di</strong>chiarazione d e l l e v a r i a b i l i<br />

open(10 , f i l e = ’ rispuntofisso . txt ’ )<br />

write ( * , * ) ’ approssimazione i n i z i a l e ’<br />

read ( * , * ) x0<br />

write ( * , * ) ’ x0 = ’ , x0<br />

C i l programma continua con l e i s t r u z i o n i gia ’ v i s t e<br />

C l e uniche mo<strong>di</strong>fiche saranno n e l l e write :<br />

write (10 ,98) ’ i t ’ , ’ xk ’ , ’ scarto ’ , ’ asint1 ’ , ’ asint2 ’<br />

write (10 ,99) i t e r , xold , scartonew<br />

C ora i l c i c l o do while<br />

C all ’ interno abbiamo<br />

write (10 ,100) i t e r , xnew , scartonew , asint1 , asint2<br />

C f i n i s c e i l c i c l o do while<br />

C scriviamo i formati<br />

close (10)<br />

stop<br />

end<br />

Una volta che il programma è stato compilato correttamente ed eseguito, la stampa dei risultati non sarà<br />

più sul video ma verrà generato un file (con il nome che abbiamo dato all’interno del programma) sul quale<br />

troveremo i risultati che prima erano sul video.<br />

Se rieseguiamo il programma questo file sarà riscritto da capo. Quin<strong>di</strong> se dobbiamo eseguire il<br />

programma più volte per <strong>di</strong>verse simulazioni, il file <strong>di</strong> output conviene rinominarlo in modo da non perderlo.<br />

11.15 Vettori<br />

Quando si programma in FORTRAN, un vettore va <strong>di</strong>chiarato in un certo modo e usato in maniera quasi<br />

simile a come li abbiamo stu<strong>di</strong>ati.<br />

Supponiamo <strong>di</strong> voler calcolare la me<strong>di</strong>a <strong>di</strong> un vettore x.<br />

Nello scrivere il programma, dobbiamo pensare ad una lunghezza massima per il vettore che dobbiamo<br />

dare in input: questo perchè in FORTRAN77 si ha un’allocazione statica delle variabili (e non <strong>di</strong>namica).<br />

Se <strong>di</strong>amo 20 come lunghezza massima del vettore, il programma che scriveremo potrà essere eseguito su<br />

vettori che avranno al più <strong>di</strong>mensione 20.<br />

182


11.16. Ciclo do<br />

Ci sono vari mo<strong>di</strong> per dare questa <strong>di</strong>mensione massima ai vettori. Noi partiremo dal modo più semplice.<br />

Supponiamo <strong>di</strong> voler scrivere un programma che calcola la me<strong>di</strong>a delle componenti <strong>di</strong> un vettore. Come<br />

procedere?<br />

G I dati <strong>di</strong> input sono: n, la <strong>di</strong>mensione effettiva del vettore e x i per i = 1,2,...n le componenti del vettore<br />

x.<br />

G L’output è la variabile me<strong>di</strong> a = (∑ n<br />

i=1 x i )<br />

n<br />

Per calcolare la variabile me<strong>di</strong> a faremo la somma in questo modo (me<strong>di</strong> a è la cosiddetta variabile <strong>di</strong><br />

accumulo):<br />

partiamo da me<strong>di</strong> a = 0<br />

quin<strong>di</strong> facciamo me<strong>di</strong> a = me<strong>di</strong> a + x 1 (prima componente della somma)<br />

poi me<strong>di</strong> a = me<strong>di</strong> a + x 2 (il risultato è x 1 + x 2 )<br />

poi me<strong>di</strong> a = me<strong>di</strong> a + x 3 (avremo x 1 + x 2 + x 3 )<br />

e così via fino a me<strong>di</strong> a = me<strong>di</strong> a + x n (in me<strong>di</strong> a avremo tutta la somma dei vettori)<br />

Dopo si fa me<strong>di</strong> a = me<strong>di</strong> a/n e avremo il risultato finale.<br />

11.16 Ciclo do<br />

Per applicare la formula per ottenere la variabile me<strong>di</strong> a possiamo pensare a un ciclo do while scritto<br />

come:<br />

me<strong>di</strong>a =0.d0<br />

i =0<br />

do while ( i . l e . n)<br />

i = i +1<br />

me<strong>di</strong>a = me<strong>di</strong>a + x ( i )<br />

end do<br />

me<strong>di</strong>a= me<strong>di</strong>a/n<br />

Noi non useremo questo approccio ma una struttura equivalente ad essa che prende il nome <strong>di</strong> ciclo do:<br />

me<strong>di</strong>a = 0 . d0<br />

do i =1 ,n<br />

me<strong>di</strong>a = me<strong>di</strong>a + x ( i )<br />

end do<br />

me<strong>di</strong>a= me<strong>di</strong>a/n<br />

program me<strong>di</strong>avettori<br />

C programma che calcola la me<strong>di</strong>a d e l l e componenti <strong>di</strong> un v e t t o r e<br />

implicit none<br />

integer n , i<br />

real *8 x (20) , me<strong>di</strong>a<br />

write ( * , * ) ’ lunghezza e f f e t t i v a del vettore ’<br />

read ( * , * ) n<br />

write ( * , * ) ’ lunghezza del vettore ’ , n<br />

i f (n . gt . 2 0 ) then<br />

write ( * , * ) ’n > massimo consentito ’ , n<br />

stop<br />

en<strong>di</strong>f<br />

do i =1 ,n<br />

write ( * , * ) ’componente ’ , i , ’−sima del vettore ’<br />

read ( * , * ) x ( i )<br />

end do<br />

do i =1 ,n<br />

write ( * , * ) ’ elemento ’ , i , ’ = ’ , x ( i )<br />

end do<br />

me<strong>di</strong>a=0.d0<br />

Programma<br />

sulla me<strong>di</strong>a<br />

dei vettori<br />

183


11. INTRODUZIONE AL FORTRAN 77<br />

do i =1 ,n<br />

me<strong>di</strong>a = me<strong>di</strong>a + x ( i )<br />

end do<br />

me<strong>di</strong>a =me<strong>di</strong>a/n<br />

write ( * , * ) ’me<strong>di</strong>a ’ , me<strong>di</strong>a<br />

stop<br />

end<br />

G Il vettore è stato <strong>di</strong>chiarato come real*8 x(20):<br />

il vettore può avere al più 20 componenti.<br />

Osserviamo che questo tipo <strong>di</strong> <strong>di</strong>chiarazione non fa <strong>di</strong>stinzione tra vettore riga e vettore colonna.<br />

G La <strong>di</strong>mensione effettiva del vettore è data dalla variabile intera n che viene data in input (per il<br />

momento da tastiera);<br />

G Le singole componenti vengono inserite da tastiera tramite un’applicazione del ciclo do;<br />

G Facciamo un controllo su n, se è più piccolo o più grande della <strong>di</strong>mensione massima. Attenzione: il<br />

ciclo if si può usare anche per interrompere il programma! Se n > 20 interrompiamo bruscamente il<br />

programma me<strong>di</strong>ante l’istruzione stop all’interno del ciclo if.<br />

Con il ciclo do che abbiamo visto, la variabile intera i varia da 1 a n (la <strong>di</strong>mensione del vettore).<br />

In generale la struttura del ciclo do è la seguente:<br />

do in<strong>di</strong>ce= v a l o r e i n i z i a l e , valorefinale , incremento<br />

{ i s t r u z i o n i }<br />

end do<br />

Quando incremento=1 possiamo evitare <strong>di</strong> scriverlo.<br />

Esempio 11.16.1 Vogliamo fare la somma delle componenti <strong>di</strong> in<strong>di</strong>ce pari del vettore x:<br />

sommapari=0.d0<br />

do i =2 ,n, 2<br />

sommapari=sommapari + x ( i )<br />

end do<br />

L’in<strong>di</strong>ce i vale i = 2, i = 2 + 2 = 4, i = 4 + 2 = 6. . . .<br />

Attenzione: se valoreiniziale > valorefinale e l’incremento è positivo, non si entra nel ciclo do.<br />

Si può anche trovare il ciclo do scritto nella forma (ormai obsoleta, ma può capitare <strong>di</strong> trovarlo su vecchi<br />

programmi):<br />

do l a bel in<strong>di</strong>ce= v a l i n i z i a l e , v a l f i n a l e , incremento<br />

{ i s t r u z i o n i }<br />

l a bel continue<br />

dove label è un numero (etichetta) che si trova all’inizio del ciclo e poi alla fine per chiuderlo (label<br />

continue). La label dell’istruzione label continue va scritta a partire dalla seconda colonna.<br />

11.16.1 I vettori nei sottoprogrammi<br />

I vettori si possono usare come variabili <strong>di</strong> input nelle functions (e non <strong>di</strong> output in quanto la function<br />

deve dare un unico valore come output e quin<strong>di</strong> non può dare un vettore) e come variabili <strong>di</strong> input e output<br />

nelle subroutines.<br />

Quando <strong>di</strong>chiariamo i vettori in un sottoprogramma, possiamo <strong>di</strong>chiararli con la loro <strong>di</strong>mensione<br />

effettiva. Ve<strong>di</strong>amo un esempio <strong>di</strong> function che calcola la norma euclidea <strong>di</strong> un vettore.<br />

184


11.16. Ciclo do<br />

real *8 function norma2(n , x )<br />

implicit none<br />

integer n , i<br />

real *8 x (n)<br />

norma2=0.d0<br />

do i =1 ,n<br />

norma2=norma2 + x ( i ) * * 2<br />

end do<br />

norma2=dsqrt (norma2)<br />

return<br />

end<br />

Attenzione a come si passano i vettori nelle functions! Abbiamo scritto real*8 function norma2(n,x). Nel<br />

programma principale (che qui non abbiamo scritto) la function sarà chiamata, ad esempio, tramite le<br />

istruzioni<br />

a l f a =norma2(n , x )<br />

beta=norma2(n , y )<br />

In questo caso, nel programma principale calcoliamo la norma dei vettori x e y e il valore <strong>di</strong> queste norme è<br />

assegnato alle variabili alfa e beta.<br />

Attenzione! Un errore frequente nell’uso <strong>di</strong> functions o <strong>di</strong> subroutines è <strong>di</strong> passare i vettori con la loro<br />

<strong>di</strong>mensione! Nel programma principale si scrive (in maniera non corretta!!!):<br />

alfa=norma2(n,x(n))<br />

Nella function, in maniera non corretta, si scrive:<br />

real*8 function norma2(n,x(n))<br />

Non si deve scrivere x(n): la <strong>di</strong>mensione del vettore viene passata me<strong>di</strong>ante la variabile n che è già tra i<br />

parametri della function. Si deve scrivere solo x.<br />

11.16.2 Leggere i dati <strong>di</strong> input da file<br />

È chiaro che se un vettore ha molte componenti <strong>di</strong>venta proibitivo assegnare le componenti del vettore<br />

tramite tastiera. . . È possibile leggere i dati <strong>di</strong> input da un file già esistente, cui viene associata una label e che<br />

viene aperto all’inizio del programma. Ora sono le istruzioni <strong>di</strong> read che vengono associate alla label del<br />

file <strong>di</strong> lettura dati. Ve<strong>di</strong>amo il programma <strong>di</strong> prima come cambia (e nello stesso calcoliamo la me<strong>di</strong>a delle<br />

componenti del vettore utilizzando una function).<br />

program me<strong>di</strong>avettori<br />

C programma che calcola la me<strong>di</strong>a d e l l e componenti <strong>di</strong> un v e t t o r e<br />

implicit none<br />

integer n , i<br />

real *8 x ( 2 0 ) , me<strong>di</strong>a , funme<strong>di</strong>a<br />

open(10 , f i l e = ’ vettoreinput . dat ’ )<br />

read ( 1 0 , * ) n<br />

i f (n . gt . 2 0 ) then<br />

write ( * , * ) ’n > massimo consentito ’ , n<br />

stop<br />

en<strong>di</strong>f<br />

C nella riga seguente troviamo i l c i c l o do implicito<br />

read ( 1 0 , * ) ( x ( i ) , i =1 ,n)<br />

C analogamente possiamo applicare i l do e s p l i c i t o<br />

C che ora e ’ commentato<br />

c do i =1 ,n<br />

c read ( 1 0 , * ) x ( i )<br />

c end do<br />

do i =1 ,n<br />

write ( * , * ) ’ elemento ’ , i , ’ = ’ , x ( i )<br />

end do<br />

185


11. INTRODUZIONE AL FORTRAN 77<br />

me<strong>di</strong>a= funme<strong>di</strong>a (n , x )<br />

write ( * , * ) ’me<strong>di</strong>a ’ , me<strong>di</strong>a<br />

close (10)<br />

stop<br />

end<br />

real *8 function funme<strong>di</strong>a (n , x )<br />

implicit none<br />

integer i , n<br />

real *8 x (n)<br />

funme<strong>di</strong>a=0.d0<br />

do i =1 ,n<br />

funme<strong>di</strong>a = funme<strong>di</strong>a + x ( i )<br />

end do<br />

funme<strong>di</strong>a =funme<strong>di</strong>a/n<br />

return<br />

end<br />

Esempi <strong>di</strong> file<br />

vettoreinput.dat<br />

Per la lettura dei dati <strong>di</strong> input si può utilizzare sia il ciclo do che abbiamo visto fino ad ora sia quello che è<br />

chiamato do implicito.<br />

Essenzialmente quando si devono leggere dei dati da un file, il compilatore FORTRAN leggerà delle<br />

stringhe <strong>di</strong> caratteri e le convertirà in numeri.<br />

Ci sono delle <strong>di</strong>fferenze sulle modalità <strong>di</strong> come avviene la lettura me<strong>di</strong>ante il do esplicito o implicito, ma<br />

non entriamo nei dettagli. Ciò che importa ricordare è che ci deve essere corrispondenza nell’or<strong>di</strong>ne in cui le<br />

variabili sono scritte sul file <strong>di</strong> dati e la lettura delle variabili stesse nel programma FORTRAN.<br />

Conviene, poi, lasciare almeno uno spazio bianco tra un valore e il successivo se li scriviamo sulla stessa<br />

riga nel file <strong>di</strong> dati.<br />

Le variabili <strong>di</strong> tipo reale vanno scritte con il punto decimale. Le variabili <strong>di</strong> tipo intero vanno scritte senza<br />

il punto decimale.<br />

Le componenti <strong>di</strong> un vettore vanno scritte o su una riga o in colonna componente per componente, in<br />

maniere del tutto in<strong>di</strong>fferente se usiamo il ciclo do implicito nel programma principale. Vanno scritte in<br />

colonna, se usiamo il ciclo do esplicito.<br />

Se usiamo il do implicito per la lettura dei dati del vettore, possiamo scrivere in<strong>di</strong>fferentemente il file dei<br />

dati nei due mo<strong>di</strong> seguenti.<br />

Il primo modo è <strong>di</strong> scrivere sul file <strong>di</strong> dati, sulla prima riga il valore <strong>di</strong> n e sulla seconda riga le componenti<br />

del vettore.<br />

4<br />

1. 2. 3. 4.<br />

Il secondo modo è <strong>di</strong> scrivere sulla prima riga il valore <strong>di</strong> n e sulle righe successive le componenti del<br />

vettore.<br />

4<br />

1.<br />

2.<br />

3.<br />

4.<br />

Se usiamo il ciclo do esplicito per la lettura dei dati <strong>di</strong> input, il vettore deve essere scritto come vettore<br />

colonna, quin<strong>di</strong> dobbiamo usare il secondo approccio.<br />

186


11.17. Matrici in FORTRAN<br />

11.17 Matrici in FORTRAN<br />

In FORTRAN, le matrici vanno <strong>di</strong>chiarate dando una <strong>di</strong>mensione massima sia sulle righe sia sulle colonne.<br />

Possiamo lavorare sia su matrici rettangolari, sia su matrici quadrate. Per semplicità, poichè noi avremo a che<br />

fare con matrici quadrate, descriveremo e faremo programmi solo su matrici quadrate.<br />

Supponiamo <strong>di</strong> voler fare il prodotto <strong>di</strong> una matrice A per un vettore x.<br />

Il risultato del prodotto <strong>di</strong> una matrice per un vettore è un vettore.<br />

Come scrivere un programma che fa questa operazione?<br />

G I dati <strong>di</strong> input sono: n, la <strong>di</strong>mensione effettiva della matrice A e del vettore, le componenti A(i , j ) (i<br />

in<strong>di</strong>ce <strong>di</strong> riga e j in<strong>di</strong>ce <strong>di</strong> colonna) per i , j = 1,2,...n della matrice, e le componenti x(i ) del vettore,<br />

per i = 1,2,...n.<br />

G L’output è il vettore y <strong>di</strong> componenti y(i ) dove y = Ax<br />

Sappiamo che y i = (Ax) i = ∑ n<br />

j =1 A i j x j .<br />

Traduciamo il tutto in FORTRAN con il seguente programma.<br />

program matrvett<br />

C programma per i l calcolo del prodotto <strong>di</strong> una matrice A per un<br />

C v e t t o r e x<br />

C dati <strong>di</strong> input :<br />

C n − <strong>di</strong>mensione e f f e t t i v a della matrice ( quadrata ) e<br />

C del v e t t o r e x<br />

C A − matrice <strong>di</strong> <strong>di</strong>mensione nxn<br />

C x − v e t t o r e <strong>di</strong> lunghezza n<br />

C dati <strong>di</strong> output<br />

C y − v e t t o r e <strong>di</strong> lunghezza n uguale al prodotto Ax<br />

C<br />

implicit none<br />

integer i , j , n<br />

real *8 A( 2 0 , 2 0 ) , x ( 2 0 ) , y (20)<br />

open(10 , f i l e = ’ matrvett . dat ’ )<br />

open(11 , f i l e = ’ matrvett . r i s ’ )<br />

C l e t t u r a della <strong>di</strong>mensione n<br />

read ( 1 0 , * ) n<br />

C l e t t u r a della matrice A<br />

C usiamo un c i c l o do i =1 ,n e s p l i c i t o e un c i c l o do implicito<br />

C leggiamo g l i elementi che s i trovano s u l l a riga i−sima<br />

C e la l e t t u r a viene f a t t a riga per riga<br />

do i =1 ,n<br />

read ( 1 0 , * ) (A( i , j ) , j =1 ,n)<br />

end do<br />

C<br />

C l e t t u r a del v e t t o r e x<br />

read ( 1 0 , * ) ( x ( i ) , i =1 ,n)<br />

C s c r i t t u r a dei dati <strong>di</strong> input sul f i l e dei r i s u l t a t i<br />

write ( 1 1 , * ) ’ <strong>di</strong>mensione ’ , n<br />

write ( 1 1 , * ) ’ matrice A ’<br />

do i =1 ,n<br />

write ( 1 1 , * ) (A( i , j ) , j =1 ,n)<br />

end do<br />

write ( 1 1 , * ) ’ vettore x ’<br />

write ( 1 1 , * ) ( x ( i ) , i =1 ,n)<br />

C prodotto matrice−v e t t o r e : l ’ elemento i−simo del prodotto<br />

C matrice−v e t t o r e e ’ dato dalla somma per j =1 ,n <strong>di</strong> A( i , j ) * x ( j )<br />

do i =1 ,n<br />

y ( i ) = 0 . d0<br />

do j =1 ,n<br />

y ( i ) = y ( i ) + A( i , j ) * x ( j )<br />

Programma<br />

sul prodotto<br />

matricevettore<br />

187


11. INTRODUZIONE AL FORTRAN 77<br />

end do<br />

end do<br />

write ( 1 1 , * ) ’ vettore y=Ax ’<br />

write ( 1 1 , * ) ( y ( i ) , i =1 ,n)<br />

stop<br />

end<br />

G La matrice è stata <strong>di</strong>chiarata come<br />

real*8 A(20,20): significa che il programma va bene per matrici che<br />

possono avere al massimo 20 righe per 20 colonne.<br />

G Abbiamo usato un ciclo do i=1, n e un ciclo do j=1,n concatenato al primo per fare il prodotto<br />

matrice-vettore.<br />

G Per calcolare le componenti del prodotto matrice-vettore abbiamo prima posto y(i)=0.d0 in modo<br />

da poter fare la somma dei vari termini “accumulandoli” <strong>di</strong> volta in volta.<br />

G Abbiamo letto i dati <strong>di</strong> input da file. Ricor<strong>di</strong>amo che il numero che scriviamo all’interno dell’istruzione<br />

che apre il file open(10, file=’nomefile.dat’) lo scegliamo noi. Se apriamo più files a ciascun<br />

file deve essere associato un numero <strong>di</strong>verso, in modo da poter leggere (se il file è <strong>di</strong> lettura) o scrivere<br />

(se il file è <strong>di</strong> scrittura) in modo appropriato.<br />

11.17.1 Le matrici nei sottoprogrammi<br />

Quando una (o più matrici) devono essere passate in un sottoprogramma (sia esso una function o una<br />

subroutine), all’interno del sottoprogramma si deve necessariamente <strong>di</strong>chiarare la matrice (o le matrici) con<br />

la loro <strong>di</strong>mensione massima sulle righe.<br />

Facciamo un esempio e successivamente ne vedremo le ragioni.<br />

Scriviamo un programma in cui, me<strong>di</strong>ante una subroutine, data la matrice A si crea la matrice B = A T .<br />

program matrtrasposta<br />

C programma che crea la matrice B=A^T<br />

C dati <strong>di</strong> input :<br />

C n − <strong>di</strong>mensione e f f e t t i v a della matrice ( quadrata )<br />

C A − matrice <strong>di</strong> <strong>di</strong>mensione nxn<br />

C dati <strong>di</strong> output<br />

C B − matrice trasposta <strong>di</strong> A<br />

C<br />

implicit none<br />

integer i , j , n<br />

real *8 A( 2 0 , 2 0 ) , B(20 ,20)<br />

open(10 , f i l e = ’ matrice . dat ’ )<br />

open(11 , f i l e = ’ r i s t r a s p o s t a . dat ’ )<br />

C l e t t u r a della <strong>di</strong>mensione n<br />

read ( 1 0 , * ) n<br />

C l e t t u r a della matrice A<br />

C usiamo un c i c l o do i =1 ,n e s p l i c i t o e un c i c l o do implicito<br />

C leggiamo g l i elementi che s i trovano s u l l a riga i−sima e<br />

C la l e t t u r a viene f a t t a riga per riga<br />

do i =1 ,n<br />

read ( 1 0 , * ) (A( i , j ) , j =1 ,n)<br />

end do<br />

write ( 1 1 , * ) ’ <strong>di</strong>mensione ’ , n<br />

write ( 1 1 , * ) ’ matrice A ’<br />

do i =1 ,n<br />

write ( 1 1 , * ) (A( i , j ) , j =1 ,n)<br />

end do<br />

c a l l trasposta (n , A , B)<br />

188


11.17. Matrici in FORTRAN<br />

write ( 1 1 , * ) ’ matrice trasposta B ’<br />

do i =1 ,n<br />

write ( 1 1 , * ) (B( i , j ) , j =1 ,n)<br />

end do<br />

stop<br />

end<br />

subroutine trasposta (n , A , B)<br />

implicit none<br />

integer i , j , n<br />

real *8 A(20 ,n) , B(20 ,n)<br />

do i =1 ,n<br />

do j =1 ,n<br />

B( i , j )=A( j , i )<br />

end do<br />

end do<br />

return<br />

end<br />

Anche per le matrici, vale la stessa osservazione che abbiamo fatto per i vettori: quando si lavora con<br />

functions o subroutines, le matrici vanno passate con il nome della loro variabile. È corretto scrivere<br />

subroutine trasposta(n,A,B). Non è corretto scrivere subroutine trasposta(n,A(20,n),B(20,n)).<br />

11.17.2 Parameter<br />

Supponiamo <strong>di</strong> dover scrivere più sottoprogrammi che richiamano matrici e vettori. Per le matrici, in<br />

ciascuno dei sottoprogrammi dobbiamo dare la <strong>di</strong>mensione massima delle righe: per esempio A(20,20)<br />

nel programma principale e A(20,n) o A(20,20) (vanno bene entrambe le forme) nei sottoprogrammi.<br />

Supponiamo però <strong>di</strong> voler eseguire il programma già fatto, e che funziona bene, per una matrice <strong>di</strong> <strong>di</strong>mensione<br />

50 × 50. Possiamo andare ad aumentare la <strong>di</strong>mensione massima delle matrici e dei vettori da 20 a<br />

50, ricompilare il programma ed eseguirlo.<br />

Cosa può succedere? Se da qualche parte ci siamo <strong>di</strong>menticati <strong>di</strong> correggere il 20 con il 50. . . il co<strong>di</strong>ce<br />

darà risultati sbagliati. . . Per evitare questo inconveniente possiamo usare una variabile che si chiama parameter<br />

per in<strong>di</strong>care la <strong>di</strong>mensione massima delle matrici. Nel programma principale (supponiamo <strong>di</strong> voler<br />

mo<strong>di</strong>ficare il programma della trasposta <strong>di</strong> una matrice), scriveremo<br />

program matrtrasposta<br />

C programma che crea la matrice B=A^T<br />

C t u t t i g l i a l t r i commenti come prima<br />

C<br />

implicit none<br />

integer nmax<br />

parameter (nmax=20)<br />

integer i , j , n<br />

real *8 A(nmax,nmax) , B(nmax,nmax)<br />

C t u t t o i l r e s t o i n a l t e r a t o fino alla chiamata della subroutine<br />

c a l l trasposta (nmax, n , A , B)<br />

subroutine trasposta (nmax, n , A , B)<br />

implicit none<br />

integer i , j , n ,nmax<br />

real *8 A(nmax, n) , B(nmax, n)<br />

do i =1 ,n<br />

do j =1 ,n<br />

B( i , j )=A( j , i )<br />

end do<br />

end do<br />

189


11. INTRODUZIONE AL FORTRAN 77<br />

return<br />

end<br />

Parameter<br />

nmax La variabile nmax è un parametro che viene definito una volta per tutte me<strong>di</strong>ante l’istruzione<br />

parameter (nmax=20): all’interno del programma noi non possiamo cambiare il valore dato a nmax.<br />

Al posto <strong>di</strong> scrivere A(20,20) noi scriviamo A(nmax,nmax). Se ci sono vettori, li <strong>di</strong>chiariamo come<br />

x(nmax).<br />

Nei sottoprogrammi, dove ci sono matrici, passiamo nmax nella lista delle variabili <strong>di</strong> input del<br />

sottoprogramma e <strong>di</strong>chiariamo A(nmax,n).<br />

In questo modo, se vogliamo cambiare la <strong>di</strong>mensione massima, an<strong>di</strong>amo a cambiare solo l’istruzione<br />

parameter (nmax=20) Per esempio scriviamo parameter (nmax=50), compiliamo il programma e possiamo eseguirlo<br />

per matrici e vettori al più <strong>di</strong> <strong>di</strong>mensione 50. Ma an<strong>di</strong>amo a cambiare solo una riga <strong>di</strong> co<strong>di</strong>ce e non<br />

tutte le righe in cui sono <strong>di</strong>chiarate le matrici e i vettori. . .<br />

11.17.3 Memorizzazione delle matrici<br />

Le matrici sono memorizzate colonna per colonna – prima gli elementi <strong>di</strong> tutta la prima colonna dalla<br />

prima all’ultima riga, poi tutti gli elementi della seconda colonna dalla prima all’ultima riga, e così via . . .<br />

Sia nmax=6, A(nmax,nmax)<br />

A può avere al più nmax righe per nmax colonne. nmax * nmax = 36 celle <strong>di</strong> memoria sono pre<strong>di</strong>sposte<br />

per i valori della matrice, a partire da A(1,1)<br />

1 7 13 19 25 31<br />

2 8 14 20 26 32<br />

3 9 15 21 27 33<br />

4 10 16 22 28 34<br />

5 11 17 23 29 35<br />

6 12 18 24 30 36<br />

Cosa succede se la <strong>di</strong>mensione effettiva della matrice è n < nmax? All’interno del programma principale<br />

i valori della matrice vengono memorizzati nelle celle <strong>di</strong> memoria che corrispondono alla “sottomatrice” <strong>di</strong><br />

<strong>di</strong>mensione n x n.<br />

Sia n=4. Si ha:<br />

1○ 7○ 13○ 19○ 25 31<br />

2○ 8○ 14○ 20○ 26 32<br />

3○ 9○ 15○ 21○ 27 33<br />

4○ 10○ 16○ 22○ 28 34<br />

5 11 17 23 29 35<br />

6 12 18 24 30 36<br />

Se nel sottoprogramma si <strong>di</strong>chiara correttamente la matrice A<br />

real*8 A(nmax,n)<br />

allora anche il passaggio della matrice avviene correttamente.<br />

Se nel sottoprogramma si <strong>di</strong>chiara invece<br />

real*8 A(n, n)<br />

allora la locazione <strong>di</strong> memoria all’interno del sottoprogramma è “pensata” come se fosse<br />

nmax=n<br />

1 5○ 9 13<br />

2 6○ 10 14<br />

3 7 11○ 15<br />

4 8 12○ 16<br />

190


11.17. Matrici in FORTRAN<br />

Ma nelle cellette <strong>di</strong> posto 5, 6, 11 e 12 non ci sono i valori della matrice: la memorizzazione risulta non<br />

corretta!!!<br />

11.17.4 Un programma <strong>di</strong> esempio<br />

Scriviamo ora un programma in cui dobbiamo usare subroutines e functions.<br />

Esempio 11.17.1 Assegnate due matrici quadrate A e B <strong>di</strong> <strong>di</strong>mensione n (n ≤ 20), si vuole calcolare la<br />

traccia delle matrici C = AB e D = B A.<br />

Scrivere dunque un programma in linguaggio FORTRAN che:<br />

1. legge n, A e B;<br />

2. calcola le matrici C = AB e D = B A servendosi della subroutine PRODMATR che esegue il prodotto <strong>di</strong><br />

due matrici quadrate;<br />

3. calcola α (la traccia della matrice C ) e β (la traccia della matrice D) servendosi della function TRAC<br />

che calcola la traccia <strong>di</strong> una matrice;<br />

4. stampa i risultati ottenuti.<br />

Per scrivere questo programma dobbiamo innanzitutto ricordarci la formula per fare il prodotto <strong>di</strong> due<br />

matrici e quella per la traccia <strong>di</strong> una matrice. Date due matrici quadrate A e B si ha C = AB con elementi<br />

c i j =<br />

n∑<br />

a i k b k j per i , j = 1,2,...,n.<br />

k=1<br />

Traducendo in pseudo-linguaggio questa formula abbiamo:<br />

1 Per i=1,n<br />

2 Per j=1,n<br />

3 C(i,j)=0 ;<br />

4 C inizializzo a zero i valori della matrice perchè devo fare una somma;<br />

5 Per k=1,n<br />

6 C(i,j)= C(i,j) + A(i,k)*B(k,j)<br />

7 Fine-Per<br />

8 Fine-Per<br />

9 Fine-Per<br />

Sarà proprio questo che faremo nella subroutine PRODMATR<br />

Invece la traccia <strong>di</strong> una matrice A è data da tr acci a = tr (A) = ∑ n<br />

i=1 a i i . Sotto forma <strong>di</strong> pseudo-algoritmo<br />

abbiamo<br />

1 traccia=0 ;<br />

2 C inizializzo a zero la variabile traccia perchè devo fare una somma;<br />

3 Per i=1,n<br />

4 traccia=traccia + A(i,i)<br />

5 Fine-Per<br />

Tradurremo questo algoritmo nella function TRAC.<br />

Poichè dobbiamo costruire due matrici prodotto e due tracce <strong>di</strong> matrici, vuol <strong>di</strong>re che la subroutine che<br />

costruirà la matrice prodotto verrà chiamata due volte nel programma principale (con gli opportuni parametri)<br />

e la function che calcolerà la traccia <strong>di</strong> una matrice verrà anch’essa chiamata due volte nel programma<br />

principale.<br />

Un’ultima osservazione riguarda le due variabili α e β: nel co<strong>di</strong>ce non possiamo scrivere lettere greche,<br />

quin<strong>di</strong> le chiameremo semplicemente alfa e beta.<br />

Il programma sarà dunque scritto nel modo seguente.<br />

191


11. INTRODUZIONE AL FORTRAN 77<br />

192<br />

program prodottomatricietraccia<br />

implicit none<br />

integer nmax<br />

parameter (nmax=20)<br />

integer n , i , j<br />

real *8 A(nmax,nmax) , B(nmax,nmax) , C(nmax,nmax) , D(nmax,nmax)<br />

real *8 trac , alfa , beta<br />

open(10 , f i l e = ’ input . dat ’ )<br />

read ( 1 0 , * ) n<br />

do i =1 ,n<br />

read ( 1 0 , * ) (A( i , j ) , j =1 ,n)<br />

end do<br />

do i =1 ,n<br />

read ( 1 0 , * ) (B( i , j ) , j =1 ,n)<br />

end do<br />

c a l l prodmatr (nmax, n , A , B,C)<br />

c a l l prodmatr (nmax, n , B, A ,D)<br />

a l f a =trac (nmax, n ,C)<br />

beta=trac (nmax, n ,D)<br />

write ( * , * ) ’ t r a c c i a d ella matrice C ’ , a l f a<br />

write ( * , * ) ’ t r a c c i a d ella matrice D ’ , beta<br />

close (10)<br />

stop<br />

end<br />

subroutine prodmatr (nmax, n , A , B,C)<br />

implicit none<br />

integer nmax, n , i , j , k<br />

real *8 A(nmax, n) , B(nmax, n) , C(nmax, n)<br />

do i =1 ,n<br />

do j =1 ,n<br />

C( i , j ) = 0 . d0<br />

do k=1 ,n<br />

C( i , j )= C( i , j ) + A( i , k ) *B( k , j )<br />

end do<br />

end do<br />

end do<br />

return<br />

end<br />

real *8 function trac (nmax, n , A)<br />

implicit none<br />

integer nmax, n , i<br />

real *8 A(nmax, n)<br />

trac =0.d0<br />

do i =1 ,n<br />

trac=trac+ A( i , i )<br />

end do<br />

return<br />

end<br />

Un esempio <strong>di</strong> file <strong>di</strong> input può essere il seguente:


11.18. La formula dei trapezi in FORTRAN<br />

4<br />

1. 2. 1. 0.<br />

0. 2. 6. 1.<br />

0. 1. 3. -1.<br />

0. 0. -7. 4.<br />

0. 1. 3. 5.<br />

2. 3. 6. 8.<br />

9. 10. 2. 4.<br />

5. 6. 8. 1.<br />

dove prima scriviamo n, la <strong>di</strong>mensione delle matrici (in questo caso 4), poi gli elementi della matrice A (riga<br />

per riga) e successivamente (abbiamo lasciato anche una riga vuota) gli elementi della matrice B.<br />

11.18 La formula dei trapezi in FORTRAN<br />

Proviamo a implementare la formula composta dei trapezi in FORTRAN.<br />

Scegliamo la funzione da integrare e gli estremi <strong>di</strong> integrazione e, come primo approccio, <strong>di</strong>amo in input<br />

il numero <strong>di</strong> sud<strong>di</strong>visioni n in cui applicare la formula composta. Inoltre, per vedere se il co<strong>di</strong>ce lo abbiamo<br />

scritto bene, daremo anche il valore esatto dell’integrale Iex (che avremo precedentemente calcolato con<br />

carta e penna) in modo da calcolare l’errore esatto.<br />

La funzione da approssimare, gli estremi <strong>di</strong> integrazione, il valore esatto dell’integrale saranno funzione<br />

o variabili del programma:<br />

G dati <strong>di</strong> input:<br />

– numero <strong>di</strong> sud<strong>di</strong>visioni n<br />

– estremi <strong>di</strong> integrazione a, b<br />

G dati <strong>di</strong> output:<br />

– valore approssimato dell’integrale (usiamo per esso la variabile i tr ap)<br />

– errore esatto, che chiamiamo er r tr ap.<br />

Il programma sarà così composto:<br />

G programma principale<br />

G function in cui scriviamo la funzione integranda.<br />

G function in cui scriviamo la primitiva della funzione integranda (per calcolare il valore esatto<br />

dell’integrale)<br />

G function in cui applichiamo la formula semplice dei trapezi e che chiamiamo trapsemplice.<br />

Tra i dati che ci facciamo stampare sul file <strong>di</strong> output, conviene farsi stampare una specie <strong>di</strong> promemoria<br />

sul problema che stiamo risolvendo (formula che stiamo applicando, gli estremi <strong>di</strong> integrazione a e b, il<br />

valore esatto dell’integrale Iex e, come stringa <strong>di</strong> caratteri, anche quale è la funzione integranda). In tal<br />

modo abbiamo “memoria” del problema che vogliamo risolvere e dei risultati ad esso associati.<br />

Applichiamo la formula dei trapezi su ciascun intervallino. La prima volta andrà applicata sull’intervallo<br />

[a, a + h], poi su [a + h, a + 2h] e così via, dove h è l’ampiezza dei singoli sottointervalli, che è la stessa su<br />

tutti i sottointervalli avendo scelto <strong>di</strong> sud<strong>di</strong>videre in parti uguali l’intervallo [a,b], quin<strong>di</strong> h = b − a . Su ogni<br />

n<br />

sottointervallo possiamo applicare la formula semplice dei trapezi in modo da avere il valore finale dell’integrale<br />

approssimato come somma dei contributi su ciascun sottointervallo. A tal scopo useremo, su ciascun<br />

sottointervallo, una function che applica la formula semplice dei trapezi.<br />

Possiamo quin<strong>di</strong> fare un ciclo do in modo da applicare la formula semplice all’intervallino [x0, x1], dove<br />

x0 rappresenta l’estremo inferiore e x1 l’estremo superiore <strong>di</strong> ciascun sottointervallo. Ogni volta aggiorneremo<br />

in maniera appropriata i due estremi (tenendo conto che x1 nell’intervallo successivo <strong>di</strong>venta x0:<br />

l’estremo superiore <strong>di</strong> ogni intervallino <strong>di</strong>venta l’estremo inferiore nell’intervallino successivo).<br />

193


11. INTRODUZIONE AL FORTRAN 77<br />

Scriviamo sotto forma <strong>di</strong> pseudoco<strong>di</strong>ce, quello che dobbiamo fare:<br />

Dati <strong>di</strong> input: a, b, n<br />

Dati <strong>di</strong> output: i tr ap, er r tr ap<br />

1 h ←− (b − a)/n ;<br />

2 calcolare Iex ;<br />

3 inizializzare i tr ap: i tr ap ←− 0.d0 ;<br />

4 inizializzare x0 del primo sottointervallo x0 ←− a ;<br />

5 Per i = 1,n<br />

6 assegnare il valore <strong>di</strong> x1: x1 ←− x0 + h ;<br />

7 applicare la formula dei trapezi sull’intervallino i -simo e sommare il contributo al valore i tr ap:<br />

i tr ap ←− i tr ap + tr apsempl i ce(x0, x1) ;<br />

8 aggiornare x0: x0 ←− x1 ;<br />

9 Fine-Per<br />

10 stampare l’integrale approssimato i tr ap ;<br />

11 calcolare e stampare l’errore esatto er r tr ap ;<br />

Per le functions da scrivere, si deve tener conto che, per la funzione integranda, la function da utilizzare è<br />

molto semplice: basta scrivere la funzione integranda.<br />

Per esempio, per calcolare l’integrale ∫ 0.5 π<br />

0 , f (x) = π<br />

. Per scrivere π in Fortran, basta<br />

1 − x<br />

2 1 − x<br />

2<br />

ricordare che π = 2arcsin(1). Allora la function <strong>di</strong>venta:<br />

real *8 function fun ( x )<br />

implicit none<br />

real *8 x , pi<br />

pi =2* asin ( 1 . )<br />

fun= pi / sqrt ( 1 . 0 d0 − x * * 2 )<br />

return<br />

end<br />

Per il calcolo del valore esatto dell’integrale, dobbiamo calcolare analiticamente l’integrale (faremo <strong>degli</strong><br />

esempi <strong>di</strong> applicazione delle formule <strong>di</strong> quadratura con integrali <strong>di</strong> cui è possibile conoscere l’integrale esatto,<br />

quin<strong>di</strong> preliminarmente, avremo calcolato a mano l’integrale, andando a cercare una primitiva della funzione<br />

integranda). Conviene allora utilizzare una function per la primitiva, in modo da poter assegnare il valore<br />

esatto dell’integrale me<strong>di</strong>ante l’istruzione Iex = F pr i m(b) − F pr i m(a), dove F pr i m è il nome dato alla<br />

function della primitiva. Nell’esempio, F pr i m(x) = πarcsin(x) e la function viene costruita <strong>di</strong> conseguenza.<br />

real *8 function Fprim ( x )<br />

real *8 pi , x<br />

pi =2.* asin ( 1 . )<br />

Fprim= pi * asin ( x )<br />

return<br />

end<br />

Invece, la function trapsemplice non è nient’altro che l’applicazione della formula semplice dei trapezi<br />

sull’intervallo <strong>di</strong> estremi x0 e x1 dati in input alla function stessa. All’interno della trapsemplice viene<br />

chiamata la function della funzione integranda.<br />

real *8 function trapsemplice ( a , b)<br />

real *8 a , b , fun<br />

trapsemplice =(b−a ) / 2 . * ( fun ( a)+ fun (b ) )<br />

return<br />

end<br />

Proviamo ora ad applicare la formula composta dei trapezi partendo da una sola sud<strong>di</strong>visione n = 1, e poi<br />

raddoppiando ogni volta il numero delle sud<strong>di</strong>visioni: n = 2, n = 4, n = 8, . . . In tal caso conviene mo<strong>di</strong>ficare<br />

il programma scritto per applicare la formula composta dei trapezi per tute le sud<strong>di</strong>visioni richieste introducendo<br />

un ciclo do while che permette <strong>di</strong> calcolare la formula composta dei trapezi prima per n = 1, poi<br />

194


11.19. <strong>Esercizi</strong><br />

per n = 2 e così via, raddoppiando ogni volta il numero <strong>di</strong> sud<strong>di</strong>visioni. In questo modo, conservando i valori<br />

dell’errore esatto tra due sud<strong>di</strong>visioni successive, possiamo calcolare il rapporto tra l’errore alla sud<strong>di</strong>visione<br />

n/2 e l’errore alla sud<strong>di</strong>visione n. Memorizziamo questo rapporto nella variabile r ate e la stampiamo per<br />

ogni sud<strong>di</strong>visione n > 1. Dai risultati saremo in grado <strong>di</strong> capire se l’errore decresce come 1 oppure no e,<br />

n2 quin<strong>di</strong>, se sono verificate le ipotesi per la formula composta dell’errore come descritto a pag. 130.<br />

Per esempio, se vogliamo applicare la formula dei trapezi per n = 1,2,4,8,...,128 sotto forma <strong>di</strong> pseudoco<strong>di</strong>ce,<br />

abbiamo<br />

Dati <strong>di</strong> input: a, b<br />

Dati <strong>di</strong> output: i tr ap, er r tr ap, r ate per ogni sud<strong>di</strong>visione<br />

1 n ←− 1 ;<br />

2 Fintantochè n < 128<br />

3 inizializzare i tr ap: i tr ap ←− 0.d0 ;<br />

4 porre h ←− (b − a)/n<br />

5 ; inizializzare x0 del primo sottointervallo: x0 ←− a ;<br />

6 applicare l’algoritmo della formula composta dei trapezi ;<br />

7 stampare i tr ap per quel valore <strong>di</strong> n ;<br />

8 calcolare l’errore esatto er r tr ap ;<br />

9 Se n > 1 allora<br />

10 calcolare il rapporto r ate tra l’errore al passo n/2 e l’errore al passo n<br />

11 altrimenti<br />

12 r ate ←− 1 (non ha significato per n = 1)<br />

13 Fine-Se<br />

14 stampare n, i tr ap, er r tr ap, r ate ;<br />

15 aggiornare una variabile er r tr apol d che memorizza l’errore al passo precedente:<br />

er r tr apol d ←− er r tr ap ;<br />

16 aggiornare n: n ←− 2n ;<br />

17 Fine-Fintantochè<br />

11.19 <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 11.19.1 Scrivere un programma FORTRAN che, assegnate due matrici A e B <strong>di</strong> <strong>di</strong>mensione n ≤ 30,<br />

esegua il prodotto C=AB; memorizzi in un vettore x gli elementi della <strong>di</strong>agonale principale <strong>di</strong> C; calcoli la<br />

norma euclidea <strong>di</strong> x.<br />

I dati <strong>di</strong> input siano letti da un file chiamato input.dat.<br />

Scrivere, perciò, un programma che:<br />

a) legge la <strong>di</strong>mensione n, le matrici A e B e stampa i dati letti con commento;<br />

b) calcola la matrice C=AB servendosi della subroutine MATRMATR;<br />

c) salva gli elementi C i i in un vettore chiamato x;<br />

d) calcola la norma euclidea <strong>di</strong> x servendosi della function NORMAEUC;<br />

e) stampa la norma euclidea <strong>di</strong> x.<br />

(mettere a punto la subroutine MATRMATR e la function NORMAEUC.)<br />

Svolgimento<br />

program prodottomatrici<br />

implicit none<br />

integer nmax<br />

parameter (nmax=30)<br />

195


11. INTRODUZIONE AL FORTRAN 77<br />

integer n , i , j<br />

real *8 A(nmax,nmax) ,B(nmax,nmax) , C(nmax,nmax) ,<br />

real *8 normaeuc , euc<br />

x (nmax)<br />

open(20 , f i l e = ’ input . dat ’ )<br />

open(21 , f i l e = ’ output . dat ’ )<br />

read ( 2 0 , * ) n<br />

write ( 2 1 , * ) ’ <strong>di</strong>mensione n ’ , n<br />

write ( 2 1 , * ) ’ matrice A’<br />

do i =1 ,n<br />

read ( 2 0 , * ) (A( i , j ) , j =1 ,n)<br />

write ( 2 1 , * ) (A( i , j ) , j =1 ,n)<br />

end do<br />

write ( 2 1 , * ) ’ matrice B’<br />

do i =1 ,n<br />

read ( 2 0 , * ) (B( i , j ) , j =1 ,n)<br />

write ( 2 1 , * ) (B( i , j ) , j =1 ,n)<br />

end do<br />

c a l l matrmatr (nmax, n , A , B,C)<br />

do i =1 ,n<br />

x ( i )= C( i , i )<br />

end do<br />

euc=normaeuc(n , x )<br />

write ( 2 1 , * ) ’norma euclidea <strong>di</strong> x ’ , euc<br />

stop<br />

end<br />

subroutine matrmatr (nmax, n , A , B,C)<br />

implicit none<br />

integer nmax, n , i , j , k<br />

real *8 A(nmax, n) , B(nmax, n) , C(nmax, n)<br />

do i =1 ,n<br />

do j =1 ,n<br />

C( i , j )= 0 . d0<br />

do k=1 ,n<br />

C( i , j )= C( i , j ) + A( i , k ) *B( k , j )<br />

end do<br />

end do<br />

end do<br />

return<br />

end<br />

real *8 function normaeuc(n , x )<br />

implicit none<br />

integer n , i<br />

real *8 x (n)<br />

normaeuc=0.d0<br />

do i =1 ,n<br />

normaeuc= normaeuc + x ( i ) * * 2<br />

end do<br />

normaeuc= sqrt (normaeuc)<br />

return<br />

end<br />

196


11.19. <strong>Esercizi</strong><br />

<strong>Esercizi</strong>o 11.19.2 Si vuole ricavare un’approssimazione della soluzione del sistema lineare Ax = b<br />

effettuando un passo del metodo del gra<strong>di</strong>ente coniugato, secondo il quale<br />

x 1 = x 0 + α 0 r 0<br />

dove<br />

α 0 = rT 0 r 0<br />

r T 0 Ar e r 0 = b − Ax 0 .<br />

0<br />

Il vettore x 0 sia scelto come x 0 = D −1 b dove D è la matrice <strong>di</strong>agonale che si ricava da A prendendo gli<br />

elementi della sua <strong>di</strong>agonale principale.<br />

Scrivere quin<strong>di</strong> un programma in linguaggio FORTRAN che:<br />

1. legge n, A e b;<br />

2. costruisce la matrice <strong>di</strong>agonale D;<br />

3. costruisce la matrice I NV D, che è la matrice inversa <strong>di</strong> D;<br />

4. calcola il vettore x 0 = D −1 b utilizzando la subroutine DIAGMAT che effettua il prodotto <strong>di</strong> una<br />

matrice <strong>di</strong>agonale con un vettore.<br />

5. calcola y = Ax 0 utilizzando la subroutine MATRVETT che fa il prodotto matrice vettore;<br />

6. calcola il vettore r 0 = b − y;<br />

7. calcola il prodotto z = Ar 0 utilizzando la subroutine MATRVETT;<br />

8. calcola d = r T 0 r 0 usando la function PSCAL che effettua il prodotto scalare tra due vettori;<br />

9. calcola t = r T 0<br />

z usando la function PSCAL;<br />

10. calcola α 0 = d/t<br />

11. calcola e stampa x 1 = x 0 + α 0 r 0 .<br />

Svolgimento Osserviamo che la matrice <strong>di</strong>agonale D ha tutti gli elementi uguali a zero eccetto quelli<br />

della <strong>di</strong>agonale principale, che nell’esercizio proposto, devono essere uguali agli elementi della <strong>di</strong>agonale<br />

principale <strong>di</strong> A. Per risolvere l’esercizio, si può costruire la matrice D me<strong>di</strong>ante le istruzioni<br />

do i =1 ,n<br />

do j =1 ,n<br />

D( i , j )=0.0<br />

i f ( i . eq . j ) then<br />

D( i , j )=A( i , j )<br />

end i f<br />

end do<br />

end do<br />

Oppure, si può costruire un vettore che rappresenta la <strong>di</strong>agonale principale della matrice A. Nello<br />

svolgimento, noi seguiamo questa seconda strada e ne terremo conto nelle subroutine INVD e DIAGMAT.<br />

program esgradcon<br />

implicit none<br />

integer nmax<br />

parameter (nmax=40)<br />

integer n , i , j<br />

real *8 A(nmax,nmax) , b(nmax) , matrd (nmax) , x0 (nmax) , r0 (nmax)<br />

real *8 y (nmax) , x1 (nmax) , inversad (nmax) , z (nmax)<br />

real *8 d , t , alfa , pscal<br />

C matrd e ’ i l v e t t o r e che contiene g l i elementi della <strong>di</strong>agonale principale <strong>di</strong> A<br />

open(10 , f i l e = ’ input . dat ’ )<br />

read ( 1 0 , * ) n<br />

do i =1 ,n<br />

read ( 1 0 , * ) (A( i , j ) , j =1 ,n)<br />

197


11. INTRODUZIONE AL FORTRAN 77<br />

end do<br />

read ( 1 0 , * ) (b( i ) , i =1 ,n)<br />

do i =1 ,n<br />

matrd ( i )= A( i , i )<br />

end do<br />

c a l l invd (n , matrd , inversad )<br />

c a l l <strong>di</strong>agmat (n , inversad , b , x0 )<br />

c a l l matrvett (nmax, n , A , x0 , y )<br />

do i =1 ,n<br />

r0 ( i )=b( i )−y ( i )<br />

end do<br />

c a l l matrvett (nmax, n , A , r0 , z )<br />

d=pscal (n , r0 , r0 )<br />

t =pscal (n , r0 , z )<br />

a l f a =d/ t<br />

do i =1 ,n<br />

x1 ( i )= x0 ( i )+ a l f a * r0 ( i )<br />

write ( * , * ) x1 ( i )<br />

end do<br />

stop<br />

end<br />

subroutine invd (n , d , dd)<br />

implicit none<br />

integer n , i<br />

real *8 d(n) , dd(n)<br />

do i =1 ,n<br />

dd( i ) = 1 . /d( i )<br />

end do<br />

return<br />

end<br />

subroutine <strong>di</strong>agmat (n , dd , b , x )<br />

implicit none<br />

integer n , i<br />

real *8 b(n) , dd(n) , x (n)<br />

do i =1 ,n<br />

x ( i )= dd( i ) * b( i )<br />

end do<br />

return<br />

end<br />

subroutine matrvett (nmax, n , A , x , y )<br />

implicit none<br />

integer nmax, n , i , j<br />

real *8 A(nmax, n) , x (n) , y (n)<br />

do i =1 ,n<br />

y ( i ) = 0 . d0<br />

do j =1 ,n<br />

y ( i )=y ( i )+A( i , j ) * x ( j )<br />

end do<br />

end do<br />

return<br />

end<br />

real *8 function pscal (n , x , y )<br />

198


11.19. <strong>Esercizi</strong><br />

implicit none<br />

integer n , i<br />

real *8 x (n) , y (n)<br />

pscal =0.d0<br />

do i =1 ,n<br />

pscal=pscal + x ( i ) * y ( i )<br />

end do<br />

return<br />

end<br />

199


A P P E N D I C E<br />

A<br />

CENNI SU GNUPLOT<br />

Il matematico sbircia <strong>di</strong>etro le spalle<br />

<strong>di</strong> Dio per trasmettere la bellezza<br />

della Sua creazione al resto delle Sue<br />

creature.<br />

Paul Erdös<br />

A.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201<br />

A.2 Grafici <strong>di</strong> funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201<br />

A.3 Salvare i grafici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205<br />

A.4 Grafici da files <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206<br />

A.5 Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208<br />

A.6 Print . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209<br />

A.1 Introduzione<br />

Gnuplot è un programma utile per fare grafici (sia <strong>di</strong> funzioni, sia <strong>di</strong> dati), <strong>di</strong>stribuito gratuitamente per<br />

sistemi operativi Linux, Windows, e altri ancora.<br />

Nel seguito vedremo alcuni coman<strong>di</strong> essenziali <strong>di</strong> Gnuplot al fine <strong>di</strong> poter visualizzare funzioni che <strong>di</strong>pendono<br />

da una sola variabile e creare grafici da tabelle <strong>di</strong> dati. Le potenzialità <strong>di</strong> Gnuplot sono molto <strong>di</strong> più<br />

<strong>di</strong> quanto <strong>di</strong>remo e, per chi è interessato, si rimanda al sito http://www.gnuplot.info.<br />

Ci rifacciamo alla versione 4.4 patchlevel 0, ultima mo<strong>di</strong>fica Marzo 2010, in ambiente Linux.<br />

Per poter lavorare in ambiente Gnuplot, da una finestra <strong>di</strong> shell <strong>di</strong>gitiamo gnuplot e poi clicchiamo il<br />

tasto <strong>di</strong> invio. L’ambiente gnuplot si presenta come nella Figura A.1<br />

Per uscire dall’ambiente gnuplot, si <strong>di</strong>gita exit. Per avere un help on-line si <strong>di</strong>gita help.<br />

Tutte le istruzioni per fare e salvare grafici, si basano su coman<strong>di</strong> scritti sulla finestra del gnuplot. Si possono<br />

anche scrivere piú istruzioni da eseguire in un file script che viene poi lanciato in ambiente gnuplot<br />

(vedremo successivamente come).<br />

A.2 Grafici <strong>di</strong> funzioni<br />

Per fare il grafico <strong>di</strong> una funzione, basta scrivere il comando<br />

plot [a:b] f(x)<br />

201


A. CENNI SU GNUPLOT<br />

Figura A.1: Ambiente gnuplot<br />

Figura A.2: Finestra <strong>di</strong> shell dove si sta lavorando in ambiente gnuplot e grafico della funzione cos(x)<br />

nell’intervallo [−π,π].<br />

dove, al posto <strong>di</strong> a e b scriviamo i valori numerici <strong>degli</strong> estremi dell’intervallo in cui vogliamo visualizzare<br />

la funzione f(x). La funzione f(x) si scrive usando le stesse notazioni del Fortran. Dopo aver scritto il<br />

comando precedente e cliccato il tasto <strong>di</strong> invio, si apre una finestra con il grafico della funzione, come si può<br />

vedere nella Figura A.2.<br />

Se si scrive semplicemente plot f(x) il grafico è fatto sull’intervallo [−10,10].<br />

Ve<strong>di</strong>amo <strong>degli</strong> esempi<br />

G plot [-pi: pi] cos(x) : fa il grafico della funzione cos(x) nell’intervallo [−π,π]. Osserviamo<br />

202


A.2. Grafici <strong>di</strong> funzioni<br />

Figura A.3: Istruzione: plot sin(x) with points pt 5<br />

che pi ha il significato <strong>di</strong> π.<br />

G plot x**2 -2*x+1: fa il grafico della parabola x 2 − 2x + 1 nell’intervallo [−10,10] (non essendo<br />

stato specificato).<br />

G plot [0:3] log(x): fa il grafico della funzione ln(x) nell’intervallo [0,3]<br />

Ogni volta, il grafico viene sovrascritto, perdendo quello precedente.<br />

Per fare il grafico <strong>di</strong> più funzioni definite nello stesso intervallo, sulla stessa figura, basta scrivere le <strong>di</strong>verse<br />

funzioni seguite da una virgola: plot [a:b], f(x), g(x), h(x)<br />

G plot [-pi:pi] sin(x), cos(x): abbiamo i grafici delle due funzioni seno e coseno in due colori<br />

<strong>di</strong>versi. La legenda, in alto a destra, spiega le <strong>di</strong>verse funzioni del grafico.<br />

G plot x, x**2, x**3: abbiamo i grafici delle funzioni x, x 2 e x 3 nell’intervallo [−10,10].<br />

È possibile cambiare lo stile del grafico (linee continue, punti, linee e punti), con il seguente comando:<br />

plot [a:b] f(x) with dove può essere: lines, points, linespoints, dots. Si può<br />

anche cambiare il colore (e, in alcune modalità, il tipo della linea o del punto) usando il comando with<br />

lt dove può variare nell’insieme {−1,0,1,...22}. Si provi a eseguire il<br />

comando test e vedere il grafico che viene prodotto per vedere i vari colori e stili.<br />

Per esempio:<br />

G plot sin(x) with linespoints, cos(x) with points produce un grafico in cui sin(x) è<br />

rappresentata me<strong>di</strong>ante linee e punti e cos(x) tramite punti (che possono essere date dal simbolo +<br />

o da un quadratino pieno a seconda dello spessore richiesto).<br />

G plot sin(x) with lines lt -1 produce un grafico con la linea <strong>di</strong> colore nero.<br />

Si può variare lo spessore delle linee e dei punti me<strong>di</strong>ante i coman<strong>di</strong> linewidth (o, in maniera del tutto<br />

equivalente, lw) e pointtype (o pt) rispettivamente. Ve<strong>di</strong>amo con <strong>degli</strong> esempi:<br />

G plot sin(x) with points pt 5: i punti hanno <strong>di</strong>mensione 5 pt (si veda la Figura A.3).<br />

G plot sin(x) with lines lw 2: la linea ha un’ampiezza pari 2 volte quella <strong>di</strong> default (si veda la<br />

Figura A.4).<br />

G plot sin(x) with linespoints lw 2 pt 5 :<br />

la linea è larga 2 lw mentre i punti hanno<br />

<strong>di</strong>mensione 5 pt (si veda la Figura A.5).<br />

Per fare un grafico semilogaritmico o logaritmico, prima <strong>di</strong> fare il grafico, si <strong>di</strong>gita il comando<br />

G set logscale: per avere un grafico logaritmico<br />

G set logscale y: per avere un grafico semilogaritmico lungo l’asse y.<br />

G set logscale x: per avere un grafico semilogaritmico lungo l’asse x.<br />

203


A. CENNI SU GNUPLOT<br />

Figura A.4: Istruzione: plot sin(x) with lines lw 2<br />

Figura A.5: Istruzione: plot sin(x) with linespoints lw 2 pt 5<br />

204


A.3. Salvare i grafici<br />

Dopo si scrive la funzione <strong>di</strong> cui fare il grafico in scala logaritmica (o semilogaritmica), me<strong>di</strong>ante il comando<br />

plot.<br />

Ve<strong>di</strong>amo un esempio:<br />

G set logscale y<br />

plot [0.1:10] x**2<br />

Per uscire dalla scala logaritmica, basta scrivere il comando unset logscale.<br />

A volte può essere utile un grafico che abbia la stessa scala lungo l’asse x e y. Il comando da utilizzare è il<br />

seguente:<br />

set size ratio -1<br />

Altri coman<strong>di</strong> utili sono i seguenti:<br />

G Per mettere un’etichetta sull’asse delle x o delle y, si scrive il comando<br />

set xlabel "nome da mettere su asse x"<br />

dove tra apici si scrive l’etichetta dell’asse delle x. Se il grafico è stato già fatto, si <strong>di</strong>gita il comando<br />

replot. Analogamente, per scrivere un’etichetta sull’asse delle y si usa<br />

set ylabel "nome da mettere su assse y"<br />

G Si può cambiare il tipo <strong>di</strong> formato con cui sono rappresentati i numeri sull’asse delle ascisse o delle<br />

or<strong>di</strong>nate. Il caso interessante da vedere si ha quando si hanno grafici semilogaritmi e si vuole usare una<br />

scala esponenziale per visualizzare l’asse delle y. Un esempio è:<br />

set format y "%4.2e"<br />

Si ha una rappresentazione in formato esponenziale con due cifre nella mantissa e una lunghezza totale<br />

del numero pari a quattro: per esempio 1.00e-11.<br />

A.3 Salvare i grafici<br />

Per conservare un grafico, ad esempio, in formato .gif, dobbiamo cambiare la modalità del terminale. Per<br />

vedere come è impostato il terminale nel modo default, si <strong>di</strong>gita l’istruzione<br />

show terminal.<br />

Come risposta si può avere<br />

terminal type is wxt 0.<br />

Fatta questa premessa (utile per ritornare a fare i grafici senza salvarli su file) si scrivono i seguenti<br />

coman<strong>di</strong>:<br />

set terminal gif<br />

set output "prova.gif"<br />

plot sin(x)<br />

Il grafico <strong>di</strong> sin(x) viene creato e salvato <strong>di</strong>rettamente sul file prova.gif nella <strong>di</strong>rectory in cui è stato aperto<br />

il programma gnuplot. Se si vuole salvare un grafico in un file .jpeg (o .png o .pdf), si sostituisce gif con jpeg<br />

(o png o pdf) nei coman<strong>di</strong> precedenti 1 (si veda la Figura A.6 per un esempio <strong>di</strong> grafico salvato come .png). Ad<br />

esempio<br />

set terminal png<br />

set output "prova.png"<br />

plot sin(x)<br />

Se è stato già creato un grafico, si può usare il comando replot per salvarlo su file:<br />

plot sin(x)<br />

set terminal gif<br />

set output "prova.gif"<br />

replot<br />

Per ritornare nella modalità <strong>di</strong> terminale <strong>di</strong> default si scrive<br />

set terminal wxt 0<br />

1 Osserviamo che, dopo l’istruzione set terminal gif o set terminal jpeg, sulla riga dei coman<strong>di</strong> <strong>di</strong> gnuplot viene lasciato<br />

un messaggio con le possibili opzioni che possono essere usate. Ignoriamo questo messaggio, perchè vogliamo usare gnuplot nel<br />

modo più semplice possibile.<br />

205


A. CENNI SU GNUPLOT<br />

Figura A.6: Il grafico salvato come file prova.png<br />

A.4 Grafici da files <strong>di</strong> dati<br />

A volte c’è bisogno <strong>di</strong> fare grafici da tabelli <strong>di</strong> dati (per esempio da files <strong>di</strong> output generati da programmi<br />

Fortran).<br />

Ve<strong>di</strong>amo con <strong>degli</strong> esempio come creare tali grafici. Supponiamo che nel file dati.dat ci siano due<br />

colonne corrispondenti ai valori sull’asse delle x e delle y, rispettivamente, che vogliamo mettere in grafico.<br />

Il file dati.dat sia il seguente:<br />

1.0000 1.5403<br />

2.0000 3.5839<br />

3.0000 8.0100<br />

4.0000 15.3464<br />

5.0000 25.2837<br />

6.0000 36.9602<br />

7.0000 49.7539<br />

8.0000 63.8545<br />

9.0000 80.0889<br />

10.0000 99.1609<br />

Per fare il grafico, dobbiamo caricare il file nell’ambiente gnuplot e far capire che la prima colonna<br />

corrisponde ai valori da mettere sull’asse delle x e la seconda ai valori da mettere sull’asse delle y.<br />

Sia il file dati.dat nella <strong>di</strong>rectory in cui viene lanciato il programma gnuplot. In ambiente gnuplot si<br />

<strong>di</strong>gita il comando:<br />

plot 'dati.dat'<br />

e viene creato il grafico per punti. Se si vuole un grafico per linee o per linee e punti basta scrivere<br />

plot 'dati.dat'with lines<br />

oppure<br />

plot ’dati.dat’ with linespoints. Osserviamo che sul grafico, la legenda mostra il nome del file<br />

206


A.4. Grafici da files <strong>di</strong> dati<br />

Figura A.7: Grafico del file dati.dat<br />

(nel nostro caso ’dati.dat’). Se vogliamo cambiare, si usa il comando title nel modo seguente:<br />

plot 'dati.dat' title "nuova legenda"<br />

dove la nuova legenda è scritta tra doppi apici. Il comando title si può usare anche per i grafici <strong>di</strong> funzioni.<br />

Si può lavorare sul grafico così come è stato visto per le funzioni. Se si vuole un grafico semilogaritmico<br />

o logaritmico, prima dell’istruzione plot si scrivono i coman<strong>di</strong> che abbiamo visto, set logscale ...<br />

Analogamente a quanto visto nella Sezione precedente, si può salvare il grafico su file.<br />

Se sul file <strong>di</strong> dati sono scritti dei commenti, le righe devono essere precedute dal simbolo cancelletto #.<br />

Se abbiamo dati salvati su più files, da inserire nello stesso grafico, si opera nel modo seguente. Supponiamo<br />

<strong>di</strong> avere i due files dati1.dat e dati2.dat. Il comando (base) in ambiente gnuplot da lanciare è:<br />

plot 'dati1.dat', 'dati2.dat'.<br />

Per specificare il tipo <strong>di</strong> linea, la legenda (e tutto quello che abbiamo già visto per un grafico), basta<br />

inserire le istruzioni che servono relativamente a ciascuna curva. Per esempio:<br />

plot ’dati.dat’ with linespoints lw2 title "curva 1", \<br />

’dati2.dat’ with lines lw2 title "curva 2"<br />

Osserviamo che, essendo l’istruzione molto lunga, siamo andati a capo, me<strong>di</strong>ante l’uso del backslash \<br />

Si possono avere files in cui abbiamo più colonne <strong>di</strong> dati, la prima che corrisponde ai valori dell’asse x e<br />

le successive colonne da mettere sull’asse y.<br />

Sia dato, ad esempio, il file multi.dat:<br />

# x y z<br />

# sin(x) cos(x)<br />

0.00000 0.00000 1.00000<br />

0.31416 0.30902 0.95106<br />

0.62832 0.58779 0.80902<br />

0.94248 0.80902 0.58779<br />

1.25664 0.95106 0.30902<br />

1.57080 1.00000 0.00000<br />

207


A. CENNI SU GNUPLOT<br />

Figura A.8: Grafico del file multi.dat me<strong>di</strong>ante le istruzioni che personalizzano la legenda.<br />

1.88496 0.95106 -0.30902<br />

2.19911 0.80902 -0.58779<br />

2.51327 0.58779 -0.80902<br />

2.82743 0.30902 -0.95106<br />

3.14159 0.00000 -1.00000<br />

Si può procedere in vari mo<strong>di</strong>:<br />

G plot 'multi.dat' using 1:2, 'multi.dat' using 1:3<br />

Produce un grafico con le due curve <strong>di</strong> <strong>di</strong>verso colore, prodotte utilizzando punti. La legenda dà<br />

multi.dat using 1:2 per la prima curva e multi.dat using 1:3 per la seconda curva.<br />

G plot 'multi.dat' using 1:2 with linespoints, 'multi.dat' using 1:3 with<br />

lines<br />

Con questo comando specifichiamo il tipo <strong>di</strong> curva.<br />

G plot ’multi.dat’ using 1:2 with linespoints title "valori y", \<br />

’multi.dat’ using 1:3 with lines title "valori z"<br />

Cambiamo la legenda per ogni curva. Nella Figura A.8 si può osservare il grafico risultante.<br />

A.5 Script<br />

A volte, specie se le figure devono essere salvate in un file, conviene scrivere tutte le istruzioni in uno<br />

script, cioè in un file in cui le righe <strong>di</strong> commento sono precedute dal simbolo # mentre sulle altre righe<br />

scriviamo i coman<strong>di</strong> che vanno eseguiti in ambiente gnuplot.<br />

Ad esempio, scriviamo (con un e<strong>di</strong>tor che salva in formato testo – lo stesso che usiamo per scrivere i<br />

programmi Fortran) il file istr.gnu (possiamo dare anche un’altra estensione che ci ricor<strong>di</strong> gnuplot, per<br />

esempio istr.gp):<br />

set logscale y<br />

set terminal jpeg<br />

208


A.6. Print<br />

set output "logfig.jpeg"<br />

plot [1:20] exp(2)*(1/x)**2<br />

Oppure scriviamo il file istr2.gnu:<br />

set terminal jpeg<br />

set output "fileprova.jpeg"<br />

plot ’multi.dat’ using 1:2 with lines lw 2 title "y", \<br />

’multi.dat’ using 1:3 with lines lw 2 title "z"<br />

Un modo per eseguire queste istruzioni è scrivere, da una finestra <strong>di</strong> shell (non in ambiente gnuplot):<br />

gnuplot istr.gnu<br />

In tal modo gnuplot esegue solamente le istruzioni contenute nello script istr.gnu, e, una volta eseguite,<br />

si è <strong>di</strong> nuovo nella finestra <strong>di</strong> shell (non si possono eseguire altri coman<strong>di</strong> perchè noi non entriamo<br />

nell’ambiente gnuplot).<br />

Perciò questo modo <strong>di</strong> eseguire uno script è utile per generare dei files (.jpeg, .gif, .png). Se invece vogliamo<br />

generare dei grafici su terminale e vogliamo avere il tempo <strong>di</strong> osservarli, non conviene usare il comando<br />

gnuplot istr.gnu perchè non riusciremmo a vedere niente. Invece, in ambiente gnuplot, si può <strong>di</strong>gitare<br />

il comando<br />

load ’istr.gnu’<br />

Vengono eseguite le istruzioni dello script ma si rimane in ambiente gnuplot. Bisogna dunque stare attenti al<br />

fatto che non ve<strong>di</strong>amo le istruzioni eseguite e che alcuni parametri, se sono stati posti in un certo all’interno<br />

dello script potrebbero creare problemi (per esempio abbiamo messo la scala logaritmica e non l’abbiamo<br />

tolta).<br />

I due files precedenti vanno bene se eseguiti con il comando gnuplot da una finestra <strong>di</strong> shell, mentre è<br />

meglio mo<strong>di</strong>ficarli se si vuole eseguirli me<strong>di</strong>ante il comando load, aggiungendo le seguenti ultime 2 righe<br />

per evitare <strong>di</strong> fare altri grafici in scala semilogaritmica e <strong>di</strong> sovrascriverli sul file <strong>di</strong> output:<br />

set logscale y<br />

set terminal jpeg<br />

set output "logfig.jpeg"<br />

plot [1:20] exp(2)*(1/x)**2<br />

unset logscale<br />

set terminal wxt 0<br />

Un’ultima osservazione riguarda l’uso <strong>degli</strong> apici nei coman<strong>di</strong> descritti precedentemente: usare il simbolo<br />

'o il simbolo "può essere usato in<strong>di</strong>fferentemente là dove abbiamo usato l’uno o l’altro nei coman<strong>di</strong> <strong>di</strong><br />

prima (nomi dei files <strong>di</strong> dati, legende, titoli,...).<br />

A.6 Print<br />

Gnuplot può essere usato anche come una calcolatrice: basta scrivere print seguito dalla formula da<br />

valutare.<br />

Esempi<br />

G print cos(pi)<br />

produce il risultato -1.0<br />

G print exp(-5)<br />

dà 0.00673794699908547<br />

G print 3.4**2 +log(3) - 4*20*7.6<br />

fornisce -595.341387711332<br />

209


BIBLIOGRAFIA<br />

[1] ASCHER, U. M. e GREIF, C. (2007), A First Course on Numerical Methods.<br />

[2] BJÖRK, A. e DAHLQUIST, G. (2008), Numerical Methods in Scientific Computing, Volume II, Siam.<br />

[3] BURDEN, R. L. e FAIRES, J. D. (2004), Numerical Analysis, Brooks-Cole Publishing.<br />

[4] DAHLQUIST, G. e BJÖRK, A. (2006), Numerical Methods in Scientific Computing, Volume I, Siam.<br />

[5] GAMBOLATI, G. (1994), Lezioni <strong>di</strong> Meto<strong>di</strong> Numerici, Cortina, Padova.<br />

[6] GAUTSCHI, W. (1997), Numerical Analysis: An Introduction, Birkäuser, Boston.<br />

[7] GIANGRANDI, P. (2010), <strong>Dispense</strong> del corso <strong>di</strong> Storia dell’Informatica, Università <strong>degli</strong> Stu<strong>di</strong> <strong>di</strong> U<strong>di</strong>ne,<br />

Italia.<br />

[8] GIANGRANDI, P. (ultima visita: febbraio 2012), Museo on line - Breve storia <strong>degli</strong> Strumenti <strong>di</strong> <strong>Calcolo</strong>,<br />

Tecnoteca, http://www.tecnoteca.it/museo/.<br />

[9] KEISLER, H. J. (2009), Elementary Calculus, An Infinitesimal Approach, Creative Commons Attribution<br />

Non-Commercial-ShareAlike License, http://www.math.wisc.edu/~Keisler/calc.html.<br />

[10] MOORE, H. (2008), MATLAB® per l’ingegneria, Pearson Prentice Hall, Italy.<br />

[11] O’CONNOR, J. e ROBERTSON, E. F. (ultima visita: febbraio 2012), The MacTutor History of Mathematics<br />

archive, University of St Andrews Scotland, http://www-gap-dcs.st-and.ac.uk/~history/.<br />

[12] SARTORETTO, F. e PUTTI, M. (2008), Introduzione alla Programmazione per Elaborazioni Numeriche.,<br />

E<strong>di</strong>zioni Libreria Progetto, Padova.<br />

[13] STRANG, G. (1991), Calculus, Wellesley-Cambridge Press.<br />

[14] SWADE, D. (ultima visita: febbraio 2012), The Babbage Engine, Computer History Museum, Mountain<br />

View, CA, http://www.computerhistory.org/babbage.<br />

211

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!