20.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

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Annamaria Mazzia<br />

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

Dipartimento <strong>di</strong> Meto<strong>di</strong> e Modelli Matematici per le Scienze Applicate<br />

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

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

a.a. 2010/2011


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

Dipartimento <strong>di</strong> Meto<strong>di</strong> e Modelli Matematici per le Scienze Applicate<br />

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

VERSIONE A.A. 2010/2011 .<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 2.5 ITALIA LICENSE,<br />

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

by-nc-nd/2.5/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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

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

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

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

3.7.2 Malcon<strong>di</strong>zionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />

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

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

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

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

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

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

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

8.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103<br />

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

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

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

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

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

8.6.1 Convergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />

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

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

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

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

9 Integrazione numerica 121<br />

9.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />

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

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

iv


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

10.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146<br />

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

11 Introduzione al FORTRAN 77 159<br />

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

11.15 Vettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178<br />

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

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

v


INDICE<br />

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

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

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

11.17.2 Memorizzazione delle matrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184<br />

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

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

12 Cenni su Gnuplot 191<br />

12.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191<br />

12.2 Grafici <strong>di</strong> funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191<br />

12.3 Salvare i grafici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194<br />

12.4 Grafici da files <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />

12.5 Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197<br />

12.6 Print . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199<br />

13 Primi passi in MATLAB® 201<br />

13.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201<br />

13.2 Avvio <strong>di</strong> MATLAB® . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />

13.2.1 Matrici e vettori in MATLAB® . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />

13.3 Coman<strong>di</strong> utili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205<br />

13.4 MATLAB® per scrivere ed eseguire programmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206<br />

13.4.1 Strutture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206<br />

13.5 Dati <strong>di</strong> input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209<br />

13.5.1 Programma sul metodo delle bisezioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209<br />

13.6 Dati <strong>di</strong> output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210<br />

13.7 Grafici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211<br />

13.8 Sulle potenzialità <strong>di</strong> MATLAB® . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212<br />

13.9 Applicazioni <strong>di</strong> MATLAB® nel <strong>Calcolo</strong> <strong>Numerico</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213<br />

13.9.1 Sull’instabilità numerica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213<br />

13.9.2 Sull’interpolazione e approssimazione <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . 214<br />

13.9.3 Confronto tra schemi per equazioni <strong>di</strong>fferenziali or<strong>di</strong>narie . . . . . . . . . . . . . . . . . 220<br />

14 Tabelle e grafici con il foglio elettronico 223<br />

14.1 Il foglio elettronico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223<br />

14.2 Inserire funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223<br />

14.3 Formule ricorsive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228<br />

14.4 Fare grafici nel foglio elettronico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231<br />

14.4.1 Grafici multicolonna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236<br />

14.5 Inserire dati da files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238<br />

Bibliografia 241<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 alla fine <strong>degli</strong> anni cinquanta permise non solo <strong>di</strong> ridurre via via lo spazio fisico<br />

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

1965 e del 1975, Gordon Moore 9 stabilì che il numero dei transistor inseribili su un chip raddoppia appros-<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 />

simativamente 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: su una<br />

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

questo microprocessore fu chiamato Intel 4004 ed era capace <strong>di</strong> eseguire 60 . 000 operazioni al 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,<br />

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

considerata la parte più importante del computer.<br />

La CPU esegue tutte le operazioni <strong>di</strong> elaborazione numerica e <strong>di</strong> controllo e rappresenta la parte centrale<br />

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

Cenni storici<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 auto-<br />

7


1. STRUTTURA DELL’ELABORATORE<br />

Sul software<br />

Memoria<br />

cache<br />

matico era una risorsa preziosa a <strong>di</strong>sposizione <strong>di</strong> pochi utenti. Tutto ciò portò ad un ripensamento del modo<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 />

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

G gestione delle periferiche (drivers)<br />

G 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 />

8


1.6. Il file system<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 />

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

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

doveva applicare. Successivamente venne scritto in larga parte in un linguaggio <strong>di</strong> alto livello, il C, progettato<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 <strong>di</strong> 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 />

10


1.8. Lavorare in ambiente Linux<br />

<strong>di</strong> realizzare un sistema utilizzabile gratuitamente da tutti e migliorabile con il contributo <strong>di</strong> tutti (la filosofia<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 (k f )<br />

= k f ′<br />

d x<br />

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), ar ccot(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 ar ccot(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 ) ar ccot(x) xar ccot(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>.<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 Sia<br />

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

Se f ∈ C ([a,b]) ed è <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 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.4 (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.5 (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 />

16


2.5. Teoremi utili<br />

Teorema 2.5.6 (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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

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

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

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

3.7.2 Malcon<strong>di</strong>zionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<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<br />

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

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

che si vuole risolvere). Inoltre, bisogna tener conto che i risultati numerici sono sempre affetti da<br />

un certo tipo <strong>di</strong> errore (che può <strong>di</strong>pendere, per esempio, dall’arrotondamento – π è un numero con infinite<br />

cifre decimali ma il calcolatore lo può vedere solo come un numero con finite cifre decimali, introducendo<br />

cosí un errore nei risultati – o dal troncamento – molte formule non possono essere usate così<br />

19


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

come sono ma devono necessariamente essere semplificate: basti pensare ad una somma <strong>di</strong> infiniti termini).<br />

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

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

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

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> un capannone<br />

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

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

valutazione della traiettoria del missile Scud. Col passare delle ore il ritardo accumulato fu tale da far intercettare<br />

una posizione del tutto <strong>di</strong>versa da quella in cui si trovava il missile da abbattere. Difatti, il computer<br />

Figura 3.1: Il <strong>di</strong>sastro del missile Patriot<br />

L’esplosione<br />

dell’Ariane 5<br />

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

Mars Climate<br />

Orbiter<br />

usato per controllare il missile Patriot era basato su un’aritmetica a 24 bit. Per i calcoli, il tempo veniva registrato<br />

dall’orologio interno del sistema in decine <strong>di</strong> secon<strong>di</strong> e successivamente moltiplicato per 1/10 per<br />

ottenere i secon<strong>di</strong>, utilizzando 24 bit in virgola fissa. Il numero 1/10 in base 2 ha infinite cifre decimali: la<br />

sua espansione binaria è infatti 0.0001100110011001100110011001100.... In 24 bit esso veniva registrato come<br />

0.00011001100110011001100 introducendo un errore <strong>di</strong> 0.0000000000000000000000011001100..., che, in<br />

base 10, significa circa 0.000000095.<br />

Gli errori <strong>di</strong> arrotondamento nella conversione del tempo causarono un errore nel calcolo della traiettoria:<br />

il tempo <strong>di</strong> 100 ore calcolato in secon<strong>di</strong> <strong>di</strong>ede il valore 359999.6567 invece <strong>di</strong> 360000, un errore <strong>di</strong> 0.3433<br />

secon<strong>di</strong> che portò 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 secon<strong>di</strong> dal suo lancio, esplose<br />

il razzo Ariane 5, nella Guiana Francese. Il razzo e il suo carico erano valutati per oltre 500 milioni <strong>di</strong> dollari.<br />

Perciò il costo totale della missione era stato <strong>di</strong> oltre 7 miliar<strong>di</strong> e mezzo <strong>di</strong> dollari. Fu scoperto che l’errore<br />

era nel software e, in particolare, nella componente del Sistema <strong>di</strong> Riferimento Inerziale, che era stato preso<br />

dal software dell’Ariane 4. Certe parti del software dell’Ariane 5 erano state aggiornate rispetto al software<br />

dell’Ariane 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 da un sistema a 64 bit a<br />

virgola mobile ad uno a 16 bit a virgola fissa.<br />

La velocità orizzontale del razzo rispetto alla piattaforma misurato in 64 bit era un numero più grande<br />

del massimo consentito nell’aritmetica a 16 bit. Si ebbe quin<strong>di</strong> un errore <strong>di</strong> overflow che causò l’arresto del<br />

software <strong>di</strong> controllo 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 />

Il <strong>di</strong>sastro del veicolo spaziale della missione Mars Climate Orbiter non si trova sulla pagina web del prof.<br />

Douglas, ma i dettagli della storia si possono trovare, ad esempio, sul sito http://marsprogram.jpl.<br />

nasa.gov/msp98/orbiter.<br />

20


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

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

Il 23 settembre 1999 si perdono le tracce del veicolo spaziale Mars Climate Orbiter. Gli obiettivi <strong>di</strong> questa<br />

missione della NASA erano sia <strong>di</strong> monitoraggio dei cambiamenti climatici sia <strong>di</strong> supporto per la missione<br />

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

dollari.<br />

Si era ipotizzato <strong>di</strong> entrare nell’atmosfera <strong>di</strong> Marte ad una altezza <strong>di</strong> circa 150 km mentre il veicolo spaziale<br />

entrò ad una altezza <strong>di</strong> circa 60 km. Per un errore <strong>di</strong> conversione delle unità <strong>di</strong> misura, il velivolo entrò<br />

nell’atmosfera con una traiettoria inferiore 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 anche della stessa Polar Lander.<br />

Diversi furono i motivi che portarono al fallimento <strong>di</strong> questa missione. Il principale è dovuto al fallimento<br />

dell’operazione <strong>di</strong> riconoscere e correggere un errore nel trasferimento <strong>di</strong> informazioni tra il team che lavorava<br />

sul veicolo spaziale, che si trovava in Colorado e il team della missione <strong>di</strong> navigazione, che lavorava<br />

in California. Un team usava le unità inglesi (inches, feet, pounds) mentre l’altro usava le unità metriche.<br />

L’errore fu, appunto, nella conversione delle unità <strong>di</strong> misura tra unità inglesi e unità metriche!<br />

Figura 3.3: La Mars Climate Orbiter<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 />

1<br />

3 = 0.3333333... = ( 0<br />

10 0 + 3<br />

10 1 + 3<br />

10 2 + 3<br />

10 3 + 3<br />

10 4 ... )<br />

× 10 0 21


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<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 />

Esempio<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 />

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

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

22


3.4. Rappresentazione IEEE dei numeri <strong>di</strong> macchina<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 />

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 nume-<br />

23


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

ro 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 è del tipo<br />

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

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<br />

rispettivamente per il segno della mantissa, le cifre per l’esponente e quelle per la mantissa):<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 />

24


3.4. Rappresentazione IEEE dei numeri <strong>di</strong> macchina<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 alla pagina seguente per capire perchè si ha questo<br />

1 − 2<br />

valore per b).<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 />

Per il limite inferiore abbiamo: 0000...0 < b + e cioè, equivalentemente,<br />

−b < e ⇔ −b + 0000...01 ≤ e.<br />

Quin<strong>di</strong> il limite inferiore è L = −(b − 1).<br />

In singola precisone, b = 0111...1<br />

} {{ }<br />

: in base 10 b = 127 10 , da cui l’intervallo [L,U ] = [−126,127].<br />

8 bits<br />

In doppia precisione, invece, b = 1023 10 da cui [L,U ] = [−1022,1023].<br />

Per quanto riguarda la mantissa, sono ad essa riservati n bits. Considerando anche l’1 della<br />

normalizzazione, la precisione è <strong>di</strong> n + 1 bits.<br />

Il più grande numero che si può rappresentare è, quin<strong>di</strong> 1<br />

n∑<br />

1.111...1<br />

} {{ }<br />

×2 U = ( 2 −k ) × 2 U = 1 − 2−(n+1)<br />

k=0<br />

1 − 2 −1 2 U = (2 − 2 −n )2 U ≈ 2 U+1<br />

n bits<br />

Il più piccolo numero positivo rappresentabile è dato, invece, da:<br />

1.000...0<br />

} {{ }<br />

×2 L = 2 L<br />

n bits<br />

Se si vuole rappresentare un numero al <strong>di</strong> fuori <strong>di</strong> questo intervallo si ha overflow o underflow.<br />

In singola e doppia precisione abbiamo, per il più grande e il più piccolo numero positivo rappresentabile,<br />

i seguenti valori:<br />

1 È il risultato <strong>di</strong> una somma del tipo S = 1 + a + a 2 + ... + a n e vale il risultato S = 1 − a(n+1) , con a = 1 1 − a<br />

2 = 2−1 . Osserviamo, inoltre,<br />

che, dati n valori w 1 , w 2 ,..., w n usiamo la seguente simbologia per in<strong>di</strong>care la loro somma:<br />

.<br />

n∑<br />

w i = w 1 + w 2 + w 3 + ... w n<br />

i=1<br />

25


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Singola precisione Doppia precisione<br />

Massimo ≈ 3.4 × 10 38 ≈ 10 308<br />

Minimo ≈ 1.2 × 10 −38 ≈ 2.2 × 10 −308<br />

Esempio 3.4.1 Vogliamo scrivere il numero 5.75 10 in formato IEEE in singola precisione.<br />

Effettuiamo prima la conversione in base 2:<br />

Per la parte intera:<br />

Per la parte decimale:<br />

5 2 1 x 0<br />

.75 × 2 = 1.50 x −1 = 1<br />

2 1 0 x 1<br />

.5 × 2 = 1.0 x −2 = 1<br />

1 0 1 x 2 .0 × 2 = 0.0<br />

Quin<strong>di</strong> 5.75 10 = 101.11 2 = 1.0111 × 2 2 .<br />

Memorizziamo ora il numero in singola precisione:<br />

Per l’esponente, essendo p = 2, si ha:<br />

(b + p) 10 = (127 + 2) 10 = 129 10 = 10000001 2<br />

Per la mantissa, m = 23 e si deve trascurare l’1 della normalizzazione, quin<strong>di</strong> memorizzeremo le cifre 0111<br />

e poi avremo tutti 0.<br />

0 1 1 1 0 0 0 ... 0 0 0 0 0 0 0 0 0 0<br />

Il segno è positivo, quin<strong>di</strong> s = 0<br />

Perciò la memorizzazione, considerati i bits per il segno, l’esponente e la mantissa è:<br />

0 1 0 0 0 0 0 0 1 0 1 1 1 0 ... 0 0 0 0 0<br />

}{{}<br />

s<br />

} {{ }<br />

esponente<br />

} {{ }<br />

manti ssa<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 />

} {{ }<br />

esponente<br />

} {{ }<br />

mantissa<br />

26


3.5. Precisione numerica<br />

3.5 Precisione numerica<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 />

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

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

27


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<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 />

Sulla cancellazione<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 />

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

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

28


3.6. Propagazione <strong>degli</strong> errori<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 />

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

Poichè vale x 1 x 2 = c/a, nel nostro caso deve valere x 1 x 2 = 1 da cui x 1 = 1/x 2 = 1/(5.5982·10 1 ) = 1.7863·10 −2<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 (non normalizzata, per cui scriveremo la parte<br />

frazionaria come 0.qual cosa).<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 />

29


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<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 <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, vale a <strong>di</strong>re<br />

cos(1.2) = 0.362357754476674...<br />

Il valore che otteniamo approssimando la derivata con la formula che abbiamo ricavato, per h = 0.1 non è<br />

molto accurato. Ci aspettiamo che <strong>di</strong>minuendo il passo h l’errore 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 />

30


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

In Figura 3.6 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 />

L’errore che noi valutiamo è dato dalla somma dell’errore <strong>di</strong> <strong>di</strong>scretizzazione e dell’errore <strong>di</strong> arrotondamento.<br />

Per valori <strong>di</strong> h gran<strong>di</strong>, l’errore <strong>di</strong> <strong>di</strong>scretizzazione descresce al <strong>di</strong>minuire <strong>di</strong> h e domina l’errore <strong>di</strong><br />

arrotondamento. Ma quando l’errore <strong>di</strong> <strong>di</strong>scretizzazione <strong>di</strong>venta molto piccolo, per valori <strong>di</strong> h minori <strong>di</strong><br />

10 −8 , allora l’errore <strong>di</strong> arrotondamento inizia a dominare e ad aumentare sempre più al <strong>di</strong>minuire <strong>di</strong> h.<br />

Questo è un motivo per cui si deve richiedere ad un algoritmo che l’errore <strong>di</strong> <strong>di</strong>scretizzazione sia quello<br />

che debba prevalere. Nell’errore <strong>di</strong> arrotondamento, per h via via più piccoli, si verifica un errore <strong>di</strong> cancellazione:<br />

f (x 0 + h) è praticamente uguale a f (x 0 ) per h molto piccoli! per cui l’errore che calcoliamo è<br />

|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.6 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.6, 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<br />

<strong>di</strong> <strong>di</strong>scretizzazione e <strong>di</strong> arrotondamento. La rappresentazione <strong>di</strong> f (x) è affetta da errore per cui avremo:<br />

f (x) = f ∗ (x)+e x . L’errore <strong>di</strong> arrotondamento è f (x 0 + h) − f (x 0 )<br />

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

+ e x 0 +h − e x0<br />

. Maggiorando<br />

e x con la precisione <strong>di</strong> macchina ɛ, l’errore <strong>di</strong> arrotondamento è dato da 2ɛ/h: per h piccoli è<br />

h<br />

h<br />

h<br />

l’errore che predomina!<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 />

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

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

allora l’algoritmo è instabile. Algoritmi del genere devono essere evitati!<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 />

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. 161 al Capitolo 11.<br />

32


3.7. Instabilità e malcon<strong>di</strong>zionamento<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 dovrebbe dare l’esatto valore se non fossero presenti errori <strong>di</strong> arrotondamento che<br />

ci allontanano completamente dalla soluzione vera. I numeri che generiamo, infatti, tendono a zero mentre<br />

l’errore si moltiplica. 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 />

0 9.5310e-2<br />

1 4.6898e-2<br />

2 3.1021e-2<br />

3 2.3122e-2<br />

4 1.8778e-2<br />

... ....<br />

7 -3.0229e-1<br />

8 3.1479e+0<br />

9 -3.1368e+1<br />

10 3.1378e+2<br />

18 3.1377e+10<br />

27 -3.1377e+19<br />

30 3.1377e+22<br />

n y n<br />

0 9.5310e-2<br />

1 4.6898e-2<br />

2 3.1018e-2<br />

3 2.3154e-2<br />

4 1.8465e-2<br />

... ....<br />

7 1.1481-2<br />

8 1.0194e-2<br />

9 9.1673e-3<br />

10 8.3270e-3<br />

18 -9.1694e+1<br />

27 -9.1699e+9<br />

30 -9.1699e+13<br />

33


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

Se invece, considero 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 />

1<br />

L’errore al passo n <strong>di</strong>pende, quin<strong>di</strong>, (in valore assoluto) da<br />

10 n 0−n .<br />

Se richie<strong>di</strong>amo una tolleranza ɛ = 10 −6 , per calcolare y n0 allora dovrà essere<br />

1<br />

10 n < ɛ cioè 10 n 1−n 0<br />

< ɛ<br />

0−n 1<br />

Passando al logaritmo in base 10:<br />

n 1 − n 0 < logɛ =⇒ n 0 > n 1 − logɛ<br />

Per 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 />

34


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

Figura 3.6: Esempio: malcon<strong>di</strong>zionamento<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 />

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.7.2. 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.<br />

La piccola variazione sui dati <strong>di</strong> ingresso, quin<strong>di</strong>, provoca una grande variazione sui dati in uscita, proprio<br />

perchè il problema è malcon<strong>di</strong>zionato.<br />

35


3. RAPPRESENTAZIONE DEI NUMERI NEL CALCOLATORE<br />

in<strong>di</strong>ce <strong>di</strong><br />

con<strong>di</strong>zionamento<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 />

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

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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<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.5 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 richiesta. Infatti<br />

Ma<br />

b − a<br />

2 n ≤ tol =⇒ |ξ − c n | ≤ tol<br />

b − a<br />

2 n ≤ tol ⇐⇒ 2 n ≥ b − a =⇒ n ≥<br />

tol<br />

log((b − a)/tol )<br />

.<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 />

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

2<br />

38


4.3. Metodo del Punto Fisso<br />

Figura 4.1: Metodo delle Bisezioni<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 />

( 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 />

39


4. ZERI DI FUNZIONE<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 />

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

40


4.3. Metodo del Punto Fisso<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, cerchiamo <strong>di</strong> capire se, data una<br />

funzione g , essa ammetta uno o più punti fissi o non ne ammetta affatto. Sia data una funzione continua g<br />

definita in un intervallo [a,b]. Se g (a) = a o g (b) = b allora essa ammette a e b come punti fissi. Supponiamo<br />

quin<strong>di</strong> che sia g (a) > a e g (b) < b. Definiamo 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 />

Questo risultato si può generalizzare nel seguente teorema.<br />

Teorema 4.3.1 Data una funzione g definita in [a,b], continua e tale che a ≤ g (x) ≤ b per ogni x ∈ [a,b], allora<br />

g ammette almeno un punto fisso.<br />

Infatti, dalle ipotesi, i valori della funzione g sono contenuti nell’intervallo [a,b] e, in particolare a ≤ g (a) ≤ b<br />

e a ≤ g (b) ≤ b. Ci riconduciamo, quin<strong>di</strong>, a quanto abbiamo detto prima per <strong>di</strong>mostrare che esiste almeno un<br />

punto fisso per g .<br />

Ora, oltre alle ipotesi precedenti (che ci assicurano l’esistenza del punto fisso) supponiamo che la g sia <strong>di</strong><br />

classe C 1 in [a,b] e che esista una costante m < 1 tale che |g ′ (x)| ≤ m < 1 per ogni x ∈ [a,b]. In questo caso il<br />

punto fisso per la g è unico.<br />

Che esista almeno un punto fisso è assicurato dal teorema precedente. Supponiamo, allora, che esistano<br />

due punti fissi ξ e η, con ξ ≠ η, per la 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. Riassumiamo questo risultato nel seguente teorema.<br />

Teorema 4.3.2 Data una funzione g <strong>di</strong> classe C 1 in [a,b], con a ≤ g (x) ≤ b per ogni x ∈ [a,b], e con |g ′ (x)| ≤<br />

m < 1 per ogni x ∈ [a,b] allora esiste ed è unico il punto fisso della g in tale intervallo.<br />

41


4. ZERI DI FUNZIONE<br />

Osserviamo che, data una funzione che ammette punto fisso, le ipotesi dei teoremi precedenti possono essere<br />

rilassate in un intorno del punto fisso.<br />

Possiamo ora provare un teorema <strong>di</strong> convergenza per lo schema del punto fisso.<br />

Teorema 4.3.3 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 (con ξ n un opportuno punto del<br />

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

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 al<br />

passo n con l’errore 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 />

42<br />

g (x) g ′ (x)<br />

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

1<br />

2 x + 2 1<br />

2<br />

x 2 2x


4.3. Metodo del Punto Fisso<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 />

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

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 delle maggiorazioni per l’errore che<br />

si commette approssimando ξ me<strong>di</strong>ante x n .<br />

43


4. ZERI DI FUNZIONE<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 />

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

Infatti, possiamo scrivere l’errore ξ − x n nel modo seguente:<br />

ξ − 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 intorno del punto<br />

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

44<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 |


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

Abbiamo così trovato una maggiorazione dell’errore che lega l’errore al passo n con il valore assoluto della<br />

<strong>di</strong>fferenza 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. 170):<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 />

ottenendo, con semplici passaggi,<br />

ξ = x n − f (x n)<br />

f ′ (x n )<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 />

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

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 , 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 me<strong>di</strong>ante 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 />

46


4.5. Convergenza <strong>di</strong> un metodo iterativo<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 />

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. Il<br />

numero delle cifre significative raddoppia ad ogni passo del metodo. Si parla <strong>di</strong> convergenza quadratica.<br />

Nel caso in cui ξ sia una ra<strong>di</strong>ce multipla, allora f ′ (ξ) = 0 allora 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<br />

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 47


4. ZERI DI FUNZIONE<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 />

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

48


4.6. Complessità computazionale <strong>di</strong> uno schema<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 />

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

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

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

ɛ n+1 = A<br />

dove p = 1 + 5<br />

2<br />

p<br />

p + 1 ɛ<br />

p<br />

n<br />

ɛ n+1 = A 0.618 ɛ 1.618<br />

n<br />

= 1.618 e A è la costante asitontica del metodo <strong>di</strong> Newton-Raphson, da cui<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 />

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

50


4.8. Confronto tra i meto<strong>di</strong> <strong>di</strong> Newton-Raphson e la Regula Falsi<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 />

Per la Regula Falsi:<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 />

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

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

51


4. ZERI DI FUNZIONE<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 a , richiedendo un’accuratezza<br />

dell’or<strong>di</strong>ne ɛ = 10 −8 .<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 />

a 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 />

.<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 />

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

52


4.9. Metodo <strong>di</strong> Newton-Raphson per ra<strong>di</strong>ci multiple<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 />

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

Definizione 4.9.1 Data una funzione 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 ɛ n = |ξ − x n |,<br />

poichè, se avessimo informazioni sull’errore, conosceremmo anche il valore <strong>di</strong> ξ (che, in generale, non è<br />

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. 49).<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 />

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

Riscriviamo la precedente formula come:<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 />

Quin<strong>di</strong><br />

ɛ n+1 ≤ M(ɛ n+1 + d n+1 )<br />

(1 − M)ɛ n+1 ≤ Md n+1<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 ora 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 />

54


4.11. <strong>Esercizi</strong><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 />

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

55


4. ZERI DI FUNZIONE<br />

Figura 4.9: <strong>Esercizi</strong>o sullo schema <strong>di</strong> punto fisso<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 />

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

56


4.11. <strong>Esercizi</strong><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 />

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

Per stimare la costante asintotica dell’errore del metodo <strong>di</strong> Newton-Raphson assumendo ξ ≈ x 3 ,<br />

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) = √ . 1 − (1 − x)<br />

2<br />

57


4. ZERI DI FUNZIONE<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 .<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 />

58


4.11. <strong>Esercizi</strong><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 />

(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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<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 />

per il resto l’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 />

Introduciamo anche il polinomio F (x) <strong>di</strong> grado n + 1 (che ci servirà in seguito), che si annulla nelle n + 1<br />

ascisse dei dati assegnati.<br />

F (x) =<br />

n∏<br />

(x − x k )<br />

k=0<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 />

Quale errore si commette interpolando la funzione f con un polinomio <strong>di</strong> grado n?<br />

Consideriamo un ulteriore punto t <strong>di</strong>stinto dai punti <strong>di</strong> appoggio e compreso nell’intervallo I in<strong>di</strong>viduato<br />

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

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

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<br />

per 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 . Sia<br />

ξ il punto in cui G (n+1) (ξ) = 0. Ma 7<br />

G (n+1) (ξ) = f (n+1) (ξ) − S(n + 1)!<br />

Si ha perciò:<br />

f (n+1) (ξ) − S(n + 1)! = 0<br />

ovvero<br />

f (t) − p(t)<br />

F (t)<br />

= S = f (n+1) (ξ)<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<br />

x) e scrivendo in forma estesa il polinomio F (x), otteniamo<br />

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

(n + 1)!<br />

n∏<br />

(x − x i )<br />

i=0<br />

Abbiamo in questo modo trovato una formula per l’errore, detta anche formula del resto. Il resto normalmente<br />

è incognito ma se conosciamo la f e una maggiorazione della f (n+1) , allora possiamo maggiorare il<br />

resto.<br />

Allo stesso modo, possiamo limitare l’errore <strong>di</strong> interpolazione se troviamo un limite superiore per |F (x)|.<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 />

Differenze<br />

<strong>di</strong>vise e<br />

formula <strong>di</strong><br />

Newton<br />

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

67


5. INTERPOLAZIONE<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 />

Ma f (x 2) − f (x 1 )<br />

x 2 − x 1<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 />

= 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 />

68


5.3. Interpolazione polinomiale<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 .<br />

Quin<strong>di</strong>, p 2 (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 ) Nell’esempio considerato: p 2 (x) =<br />

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<br />

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 un<br />

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

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

i=0<br />

Derivata<br />

k-sima della<br />

f<br />

Formula<br />

dell’errore<br />

5.4 Considerazioni sull’interpolazione polinomiale<br />

5.4.1 Fenomeno <strong>di</strong> Runge<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 8 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 />

8 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 porta a risultati <strong>di</strong>sastrosi, come si può vedere in Figura 5.6. Eppure, dal punto <strong>di</strong> vista<br />

teorico i 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 del sistema V ;<br />

la soluzione del sistema lineare V c = y; il 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 />

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

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

(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 />

74


5.5. <strong>Esercizi</strong><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 />

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

Si ottiene, dunque,<br />

= 9 f [1,1] = f ′ (1) = 60<br />

75


5. INTERPOLAZIONE<br />

0 2<br />

7<br />

0 2 9<br />

7 9<br />

0 2 18 8<br />

25 17<br />

1 27 35<br />

60<br />

1 27<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.2 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 />

La funzione da minimizzare è<br />

80<br />

S(a 0 , a 1 ,..., a m ) =<br />

n∑ [<br />

(a0 + a 1 x i + a 2 x 2 i + ... + a m x m ] 2<br />

i<br />

) − y i<br />

i=0


6.4. Approssimazioni <strong>di</strong> tipo esponenziale<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 />

j = 0,1,...,m<br />

Ricaviamo, quin<strong>di</strong><br />

n∑<br />

2 (a 0 + a 1 x i + ... + a m x m i<br />

− y i )x j i<br />

i=0<br />

= 0 per j = 0,1,...,m<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 />

na0 + ∑ n<br />

i=1 x i a 1 = ∑ n<br />

i=1 y i<br />

∑ n<br />

i=1 x i a 0 + ∑ n<br />

i=1 x2 i a 1 = ∑ n<br />

i=1 x i y i<br />

dove n = 5. Poichè ∑ n<br />

i=1 x i = 8, ∑ 5<br />

i=1 x2 i = 30, ∑ 5<br />

i=1 y i = 108 e ∑ 5<br />

i=1 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 />

nb0 + ∑ n<br />

i=1 y i b 1 = ∑ n<br />

i=1 x i<br />

∑ n<br />

i=1 y i b 0 + ∑ n<br />

i=1 y 2 i b 1 = ∑ n<br />

i=1 y i x i<br />

dove n = 5. Poichè ∑ n<br />

i=1 y i = 108, ∑ 5<br />

i=1 y 2 i = 7362, ∑ 5<br />

i=1 x i = 8 e ∑ 5<br />

i=1 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 />

∑ 5<br />

i=1<br />

X =<br />

x i<br />

= −1 + 2 + 3 + 4<br />

∑ 5<br />

i=1<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 />

na0 + ∑ n<br />

i=1 X i a 1 = ∑ n<br />

i=1 Y i<br />

∑ n<br />

i=1 X i a 0 + ∑ n<br />

i=1 X 2 i a 1 = ∑ n<br />

i=1 X i Y i<br />

dove n = 10.<br />

Si ha ∑ n<br />

i=1 X i = 16.6995268, ∑ n<br />

i=1 X 2 = 28.2537116, ∑ n<br />

i i=1 Y i = 52.0472913, ∑ n<br />

i=1 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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />

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

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

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

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

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

7.6 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<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 equazione i -sime e j -sime 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 a parte quelli che si trovano sopra o sotto la<br />

<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 è una matrice A T <strong>di</strong> <strong>di</strong>mensione m × n<br />

per cui la colonna i della trasposta coincide con la riga i della matrice A <strong>di</strong> partenza: 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 è possibili 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<br />

Assumiamo, ora, che la matrice A sia piena (o densa, cioè abbia quasi tutti gli elementi non nulli). Applichiamo<br />

trasformazioni elementari per riga in modo da ridurre il sistema <strong>di</strong> partenza in uno equivalente <strong>di</strong><br />

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

91


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<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<br />

(a 11 x 1 + a 12 x 2 + a 13 x 3 + ... + a 1n x n ) = a 21<br />

a 11<br />

b 1<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 />

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

b 1<br />

b (1)<br />

2<br />

b (2)<br />

3<br />

...<br />

b (n−1)<br />

n<br />

⎞<br />

⎟<br />

⎠<br />

92


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

Esempio 7.3.1 Sia A =<br />

( ) ( )<br />

2 1 2<br />

e .<br />

3 2<br />

=¯ 3.5<br />

Per applicare il metodo <strong>di</strong> Gauss, dobbiamo moltiplicare la prima equazione per 3 e sottrarla dalla seconda<br />

2<br />

3x 1 + 2x 2 = 3.5<br />

−<br />

3<br />

2 (2x 1 + 1x 2 ) = 3 2 2 =<br />

0x 1 + 0.5x 2 = 0.5<br />

Il sistema<br />

(<br />

equivalente<br />

)( ) (<br />

<strong>di</strong>venta<br />

)<br />

2 1 x1 2<br />

=<br />

0 0.5 x 2 0.5<br />

7.4 Strategie <strong>di</strong> pivoting<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 a<br />

destra e sotto l’elemento <strong>di</strong>agonale i -simo. 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 />

93


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<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à: x 3 =<br />

−10000/ − 9999 = 1.000, x 2 = 1 − 1<br />

0.0001 = 0 e 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 />

7.5 Fattorizzazione triangolare<br />

Il metodo <strong>di</strong> eliminazione <strong>di</strong> Gauss, visto in forma matriciale, decompone la matrice A nel prodotto LU<br />

<strong>di</strong> due matrici L, trangolare inferiore, e U , triangolare superiore.<br />

94


7.5. Fattorizzazione triangolare<br />

Basta considerare, ad ogni passo, la matrice<br />

⎛<br />

1<br />

0 1<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 />

. ..<br />

. ..<br />

⎞<br />

⎟<br />

1<br />

⎠<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) = M (k) b (k−1) =<br />

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 <strong>di</strong><br />

Gauss.<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 />

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

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

Minore<br />

principale<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 />

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

95


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

Matrice <strong>di</strong><br />

permutazione<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 />

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

96


7.5. Fattorizzazione triangolare<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 />

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

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

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

97


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<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 />

Matrice <strong>di</strong>agonalmente<br />

dominante<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 />

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

Matrice<br />

definita<br />

positiva<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 />

Matrice<br />

definita negativa se è simmetrica e vale x T Ax < 0 qualunque sia il vettore x ≠ 0,<br />

definita<br />

G semidefinita negativa se x T Ax ≤ 0 qualunque sia il vettore x.<br />

negativa<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 />

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 o<br />

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

Ve<strong>di</strong>amo ora una con<strong>di</strong>zione necessaria e sufficiente per matrici definite positive.<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 />

98


7.5. Fattorizzazione triangolare<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. Poichè A è simmetrica, si ha A = A T , quin<strong>di</strong> LDU = (LDU ) T = U T D T L T = U T DL T . Si<br />

deduce quin<strong>di</strong>, 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, deve valere<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 />

Perciò gli elementi <strong>di</strong> D (che è una matrice <strong>di</strong>agonale) devono necessariamente essere tutti positivi – essendo<br />

A definita positiva. In tal caso, posto M = LD 1/2 si ha A = M M T , il prodotto <strong>di</strong> una matrice triangolare<br />

inferiore con coefficienti tutti reali per la sua trasposta. Se D non fosse definita positiva (ma avesse qualche<br />

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

99


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<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 />

100


7.6. <strong>Esercizi</strong><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. 96, 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 />

Soluzione<br />

101


7. METODI DIRETTI PER LA SOLUZIONE DI SISTEMI LINEARI<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 />

102


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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103<br />

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

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

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

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

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

8.6.1 Convergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />

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

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

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

8.7 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117<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 />

103


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

A tal fine abbiamo bisogno <strong>di</strong> definire le norme <strong>di</strong> vettori e <strong>di</strong> matrici. Tratteremo solo norme <strong>di</strong> matrici e<br />

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

104


8.3. Norme <strong>di</strong> vettori<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 />

Distanza tra<br />

vettori<br />

‖x − y‖ 1 =<br />

n∑<br />

|x i − y i |<br />

i=1<br />

‖x − y‖ ∞ = max |x i − y i |<br />

1≤i≤n<br />

√ n∑<br />

‖x − y‖ 2 = |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 />

105


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<br />

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

Norma<br />

compatibile<br />

Norma<br />

naturale<br />

traccia <strong>di</strong> una<br />

matrice<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 />

‖A‖ > 0 per ogni A ≠ 0<br />

‖A‖ = 0 se e solo se A = 0<br />

‖αA‖ = |α|‖A‖<br />

‖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 />

106<br />

n∑<br />

λ i = tr (A) = a 11 + a 22 + ... + a nn<br />

i=1<br />

e<br />

n∏<br />

λ i = det A<br />

Alcune proprietà sugli autovalori e autovettori sono le seguenti:<br />

i=1


8.5. Autovalori e autovettori<br />

Figura 8.2: Autovalori e autovettori<br />

G Se λ è autovalore della matrice A, allora λ k è autovalore della matrice potenza A k (cioè A · A ··· A k<br />

volte).<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 />

ρ(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 />

Raggio<br />

spettrale<br />

Norma 2 su<br />

matrici<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 />

107


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 sia più semplice della A e, allo stesso tempo, M −1 approssimi 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 ci 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 />

108


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. 107), 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| < 0. Ma |λ 1 | = ρ(E):<br />

ritroviamo il risultato visto prima.<br />

109


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<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 />

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

Ci chie<strong>di</strong>amo se è possibile stabilire a priori quante iterazioni occorrono per ridurre la norma dell’errore<br />

iniziale <strong>di</strong> un certo fattore, ad esempio 10 (il che vuol <strong>di</strong>re ridurre l’errore <strong>di</strong> un or<strong>di</strong>ne <strong>di</strong> grandezza). Vogliamo<br />

dunque capire quale deve essere il valore <strong>di</strong> k per cui ‖e (k) ‖ = ‖e(0) ‖<br />

10 . Ma ‖e(k) ‖ ≈ ρ(E) k ‖e (0) ‖ da cui<br />

‖e (0) ‖<br />

10 ≈ ρ(E)k ‖e (0) ‖ =⇒ 1<br />

10 ≈ ρ(E)k<br />

Applicando il logaritmo in base 10 ad ambo i membri si ha<br />

1<br />

−1 ≈ k log 10 (ρ(E)) =⇒ 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. 109)<br />

e (k) ≈ λ k 1 α 1u (1)<br />

2 Questa relazione vale anche per matrici con autovalori non <strong>di</strong>stinti tra loro.<br />

110


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

Figura 8.3: La matrice A come somma delle matrici L, D e U .<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 />

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

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

Componente per componente, lo stesso metodo si scrive, per i = 1,2,...,n, come<br />

x (k+1)<br />

i<br />

=<br />

(D −1 ) i i<br />

1<br />

a i i<br />

⇑<br />

o, equivalentemente,<br />

⎡<br />

⎢<br />

⎣ b i −<br />

((L+U )x (k) ) i<br />

n∑<br />

j =1,j ≠i<br />

⇑<br />

⎤<br />

a i j x (k)<br />

⎥<br />

j ⎦<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 />

111


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<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 />

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

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

x 1 = 1 [b 1 − (a 12 x 2 + a 13 x 3 + ... + a 1n x n )]<br />

a 11<br />

x 2 = 1 [b 2 − (a 21 x 1 + a 23 x 3 + ... + a 2n x n )]<br />

a 22 . = . .<br />

x i = 1 [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 />

a i i . = . .<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 )]<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 />

112


8.6. Meto<strong>di</strong> classici<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 />

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

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

[<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 />

4 Philipp Ludwig von Seidel (1821-1896) fu un matematico tedesco. Il suo lavoro più importante riguarda le aberrazioni ottiche.<br />

113


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<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 />

a i 1 x (k+1)<br />

1<br />

+ a i 2 x (k+1)<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 />

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

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

)]<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 />

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 ω scrivendo<br />

x (k+1) = x (k) + ω(x (k+1)<br />

nonr i l − x(k) ) o, in maniera del tutto equivalente, x (k+1) = ωx (k+1)<br />

nonr i l + (1 − ω)x(k) , dove x (k+1)<br />

nonr i l<br />

è l’approssimazione del vettore x ottenuta tramite il metodo <strong>di</strong> Jacobi o <strong>di</strong> Gauss-Seidel.<br />

A <strong>di</strong>fferenza del metodo <strong>di</strong> Jacobi rilassato, che non produce effettivi miglioramenti rispetto al metodo<br />

non rilassato, il metodo <strong>di</strong> Gauss-Seidel rilassato può produrre un metodo molto più veloce in termini <strong>di</strong><br />

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, è 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 />

114


8.6. Meto<strong>di</strong> classici<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 />

E = (D + ωL) −1 [(1 − ω)D − ω(A − D − L)]<br />

E = (D + ωL) −1 [(D + ωL) − ωA]<br />

E = [ 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 />

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

( )<br />

5 P Q<br />

cioè non può essere messa sotto la forma<br />

R<br />

115


8. METODI ITERATIVI PER LA SOLUZIONE DI SISTEMI LINEARI<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 che<br />

il raggio spettrale della matrice sarà maggiore o uguale a |1 − ω| Quin<strong>di</strong>, se |1 − ω| > 1, sicuramente il metodo<br />

<strong>di</strong> rilassamento non convergerà. 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 />

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

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

116


8.7. <strong>Esercizi</strong><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 <strong>di</strong> E J , ogni λ che verifica la relazione (λ + ω − 1) 2 = λω 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 />

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 µ 2 = λ, dove λ è l’autovalore <strong>di</strong> massimo modulo della matrice <strong>di</strong> Gauss-Seidel, allora<br />

anche il metodo <strong>di</strong> Gauss-Seidel convergerà alla soluzione (da µ < 1 segue µ 2 < 1). La matrice <strong>di</strong> Jacobi<br />

è E J = I − D −1 A cioè<br />

⎛<br />

⎞ ⎛<br />

⎞<br />

0 −2/8 −6/8 0 −1/4 −3/4<br />

E J = ⎝<br />

det(E J − µI ) = 0.<br />

−7/5 0 0<br />

−1/5 0 0<br />

⎠ = ⎝<br />

−7/5 0 0<br />

−1/5 0 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 (λ = µ 2 = 0.5). Le velocità <strong>di</strong><br />

convergenza valgono<br />

R J = −log 10 (µ) = 0.1505149<br />

R S = −log 10 (λ) = 0.301029995 = −log 10 (µ 2 ) = 2R J<br />

⎠<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 />

118


8.7. <strong>Esercizi</strong><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 />

√<br />

2<br />

1+ 1−µ 2 J<br />

, valida perchè la matrice è biciclica e coerentemente<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 />

119


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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

9.8 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<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à, e si hanno i valori messi in Tabella 9.1<br />

In base ai dati in possesso, quanto è lunga la pista?<br />

Sapendo che la velocità v si può scrivere come v(t) = d s (dove s rappresenta lo spostamento e t il tempo),<br />

d t<br />

per calcolare la lunghezza della pista (lo spostamento effettuato dall’auto), dobbiamo integrare tra il tempo<br />

121


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

iniziale e quello finale la velocità.<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 />

122


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.3) 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 />

123


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 rappresenta la formula che approssima l’integrale della f mentre il secondo integrale<br />

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

124


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

Definiamo i 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 è possibile ricavare<br />

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

125


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 abbiamo considerato per interpolare la f , l’errore è dato da<br />

E(x) = f ′′′ (ξ x )<br />

(x − a)(x − c)(x − b).<br />

3!<br />

126


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 c 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 />

127


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 danno<br />

risultati inaccurati su intervalli ampi a causa della natura oscillatoria dei polinomi <strong>di</strong> grado 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<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 />

∫ b<br />

a<br />

f (x)d x =<br />

n∑<br />

i=1<br />

∫ xi<br />

x i−1<br />

f (x)d x<br />

128


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

Quin<strong>di</strong><br />

nm ≤<br />

∑<br />

n∑<br />

n<br />

f ′′ i=1<br />

(ξ i ) ≤ nM =⇒ m ≤<br />

f ′′ (ξ i )<br />

≤ M<br />

n<br />

i=1<br />

Per il teorema del Valor Interme<strong>di</strong>o (teorema 2.5.5),<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 =<br />

i=1<br />

∑ n<br />

i=1 f ′′ (ξ i )<br />

è un valore assunto dalla funzione in<br />

n<br />

−f ′′ (ξ i ) h3<br />

12 = −n f ′′ (ξ) h3<br />

12 = − f ′′ (ξ)<br />

12 (b − a)h2 = − f ′′ (ξ)<br />

12<br />

(b − a) 3<br />

n 2 129


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

130


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

131


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

132


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 133


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 ≈ E 1<br />

16<br />

supponendo che le derivate quarte della f non siano molto <strong>di</strong>verse tra loro.<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 />

134


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)] si ha un unico intervallo<br />

2<br />

A 1 = b − a<br />

2 [ f (a)<br />

2 + f ( a + b<br />

2 ) + f (b) ] si hanno 2 sottointervalli<br />

2<br />

B 1 = (b − a)[ f (a) 4f ( a + b<br />

6 + 2 )<br />

6<br />

) + f (b)<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 />

135


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]. Per le formule<br />

<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 la formula <strong>di</strong> quadratura che ricaviamo ha al più grado <strong>di</strong> precisione d = n (o<br />

d = n + 1 quando w(x) ≡ 1 e per n pari, come abbiamo visto per le formule <strong>di</strong> Newton-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 />

136


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

137


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<br />

I no<strong>di</strong> x i sono reali, <strong>di</strong>stinti e contenuti nell’intervallo aperto ]a,b[.<br />

I pesi w i sono tutti positivi.<br />

Infatti, per j = 0,1,...n 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 />

138


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

139


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

140


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à), possiamo scrivere<br />

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

141


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 è: |I − I tr ap | = 0.196067154, un valore minore della maggiorazione trovata<br />

prima.<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 />

142


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 è |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 è: |I −Q 3 | = 3.7351 · 10 −6 .<br />

143


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

144


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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146<br />

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

145


10. EQUAZIONI ALLE DERIVATE ORDINARIE<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 />

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 contengano valvole termoioniche, i cosiddetti tubi a vuoto, come il tubo cato<strong>di</strong>co del<br />

televisore o il magnetron nei forni a micro-onde. 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 />

1<br />

u ′ 2<br />

) (<br />

)<br />

u 2<br />

=<br />

−ɛ((u 1 ) 2 − 1)u 2 − u 1<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. Allora y = y(t) è tale che<br />

y ′ = y ′ (t) = dy(t) è esattamente la 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 />

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

146


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

Esempio 10.2.2 La seconda legge del moto <strong>di</strong> Newton F = ma è una ODE del secondo or<strong>di</strong>ne in quanto<br />

a = y ′′ (dove y è la coor<strong>di</strong>nata della posizione).<br />

Allora la ODE ha la forma<br />

y ′′ = F /m<br />

con F forza e m la massa. Definendo u 1 = y e u 2 = y ′ si ha il sistema (equivalente all’equazione <strong>di</strong> prima)<br />

<strong>di</strong> due equazioni del primo or<strong>di</strong>ne <strong>di</strong> ODE:<br />

( u<br />

′<br />

) ( )<br />

1<br />

u2<br />

u<br />

2<br />

′ =<br />

F /m<br />

Possiamo ora usare meto<strong>di</strong> che risolvono equazioni del primo or<strong>di</strong>ne per risolvere questo sistema. La prima<br />

componente della soluzione u 1 ci dà il valore y dell’equazione da cui siamo partiti. La seconda componente<br />

u 2 ci dà la velocità y ′ .<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/d t denota la derivata rispetto a t (per<br />

cui la i -sima componente del vettore derivata è data da y ′ i (t) = d y i (t)/d t). La funzione f è assegnata e noi<br />

vogliamo 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 approssimiamo la derivata y ′ me<strong>di</strong>ante la formula <strong>di</strong> Taylor (del<br />

secondo or<strong>di</strong>ne) applicata al punto t i :<br />

y(t) = y(t i ) + (t − t i )y ′ (t i ) + (t − t i ) 2<br />

y ′′ (ξ i )<br />

2<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 />

147


10. EQUAZIONI ALLE DERIVATE ORDINARIE<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 />

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 , dati che sono tutti espliciti.<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 />

d t d t =<br />

t 0<br />

f (t, y(t)) d t =⇒<br />

∫ y(t)<br />

y 0<br />

d y =<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 che ottienamo y 1 è 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 />

148


10.4. Metodo <strong>di</strong> Eulero implicito<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 />

Interpretazione<br />

geometrica<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 />

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

149


10. EQUAZIONI ALLE DERIVATE ORDINARIE<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 />

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

150


10.4. Metodo <strong>di</strong> Eulero implicito<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 />

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

151


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

dy =<br />

∫ ti+1<br />

t i<br />

f (t, y(t)) dt =⇒ y(t i+1 ) − y(t i ) =<br />

∫ ti+1<br />

t i<br />

f (t, y(t)) dt<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 />

152


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. 30). 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 />

153


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

154


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

Ricor<strong>di</strong>amo la proprietà per la quale x α = e ln(xα) = e αln(x) .<br />

1<br />

ln(1 − h)<br />

t<br />

lim<br />

h→0<br />

i→+∞<br />

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 h ln(1−h) = e −1<br />

Allora<br />

lim<br />

h→0<br />

i→+∞<br />

1<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 />

⎡<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 />

ɛ 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 />

Dobbiamo provare che l’errore si mantiene limitato. Sia λ > 0. Abbiamo y i+1 = y i −hλy i = (1−hλ)y i , vale<br />

a <strong>di</strong>re y i+1 = (1−hλ) i+1 y 0 La soluzione esatta <strong>di</strong> questo problema è y(t) = y 0 e −λt e tende a zero per valori <strong>di</strong> t<br />

crescenti. Vogliamo che tenda a zero anche la soluzione numerica (in modo da mantenere limitato l’errore).<br />

La soluzione numerica (fissato h e per i grande, cioè per valori <strong>di</strong> t crescente) tende a zero se |1−hλ| < 1 cioè<br />

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

155


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λ<br />

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

y 0<br />

Per la stabilità, si vede che la soluzione è y i =<br />

(1 + λh) i<br />

1<br />

Per i → +∞, qualunque sia il valore <strong>di</strong> h, la soluzione tende a zero in quanto lim i→+∞<br />

(1 + λh) i = 0 Si<br />

parla <strong>di</strong> metodo incon<strong>di</strong>zionatamente 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 />

156


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

ln( 2 − hλ<br />

2 + hλ )<br />

lim<br />

h→0<br />

i→+∞<br />

La convergenza è provata.<br />

h<br />

y i = lim<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λ<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 />

157


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

158


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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

11.15 Vettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178<br />

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

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

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

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

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

11.17.2 Memorizzazione delle matrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184<br />

159


11. INTRODUZIONE AL FORTRAN 77<br />

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

11.19 <strong>Esercizi</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188<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 liguaggio <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 />

finestre <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.<br />

Possiamo scrivere anche<br />

g77 -o prova.exe prova.f<br />

160


11.3. Problemi e Algoritmi<br />

Possiamo mettere (o meno) un’estensione al file eseguibile.<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, ostacolo, promontorio,<br />

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 (per esempio dall’algebra, dal calcolo, dalla logica).<br />

Per esempio, termini come temperatura, pressione, massa, espansione isotermica e a<strong>di</strong>abatica, possono<br />

essere usati in un’officina per riparare il motore <strong>di</strong> un’automobile, da un me<strong>di</strong>co che sta misurando la<br />

pressione del sangue, 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 />

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

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

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

161


11. INTRODUZIONE AL FORTRAN 77<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 ogni<br />

studente calcoliamo la me<strong>di</strong>a dei suoi voti, c’è un’ovvia <strong>di</strong>fferenza tra i nomi <strong>degli</strong> studenti (una stringa<br />

<strong>di</strong> 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 />

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

7 Questo limite è dovuto al fatto che fino alla fine <strong>degli</strong> anni settanta, la programmazione veniva fatta utilizzato schede perforate, dei<br />

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 (generalmente<br />

80 colonne e 12 righe).<br />

162


11.6. Le variabili<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 dalla 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<br />

in<strong>di</strong>care che il <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<br />

cui eseguiamo 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:<br />

dobbiamo <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 />

G Con read(*,*) a si impone al calcolatore <strong>di</strong> prendere un valore e memorizzarlo nella variabile a, e<br />

questo valore lo si dà tramite tastiera. Analogamente potremmo scrivere read(5,*) a: il numero 5<br />

in<strong>di</strong>ca 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 />

163


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 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 l’esecuzione<br />

del programma, il valore delle variabili torna ad essere incognito. Perciò ci facciamo stampare<br />

il loro valore prima dell’istruzione <strong>di</strong> stop.<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).<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 />

∗∗ 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 />

164


11.9. I pre<strong>di</strong>cati elementari<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 />

Nel fare le operazioni matematiche, in FORTRAN viene data la precedenza (priorità) agli elevamenti a<br />

potenza, poi alle moltiplicazioni e <strong>di</strong>visioni, infine a sottrazione e ad<strong>di</strong>zione. Quando due operatori hanno la<br />

stessa priorità vengono eseguite le operazioni partendo da sinistra e andando verso destra. Tuttavia, quando<br />

le espressioni sono abbastanza complicate e c’è il rischio <strong>di</strong> non capire bene quali operazioni vanno fatte<br />

prima e quali dopo, conviene mettere sempre le parentesi.<br />

In FORTRAN ci sono già molte funzioni matematiche che possiamo utilizzare per i nostri programmi. In<br />

Tabella 11.8, ve<strong>di</strong>amo le principali funzioni.<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.9 ci serviranno per poter scrivere istruzioni legate<br />

ad una con<strong>di</strong>zione.<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 />

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.9.<br />

165


11. INTRODUZIONE AL FORTRAN 77<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.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 />

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

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.<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 />

166


11.10. Struttura alternativa<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 />

11.10 Struttura alternativa<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 />

167


11. INTRODUZIONE AL FORTRAN 77<br />

Ciclo if<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 />

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

168


11.10. Struttura alternativa<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 />

169


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 it=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 it=it+1=2, ci serve<br />

calcolare x 2 = cos(x 1 ). Proprio perchè il valore <strong>di</strong> xold non serve più assegniamo a xold il valore<br />

calcolato per x 1 =xnew in modo da poter sfruttare la relazione <strong>di</strong> prima. Applicheremo <strong>di</strong> nuovo la<br />

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 it=it+1=3, ci serve solo x 2 . Perciò faremo xold=xnew, xnew=cos(xold)<br />

e avremo xnew=x 3 . E così via. . .<br />

170


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

Quando si entra nel ciclo do while scartonew=2.0d0*toll > toll e iter=0< itmax. Si eseguono le<br />

istruzioni del ciclo do while fino a quando rimane vera la proposizione (scartonew.ge.toll) .and.<br />

(iter.le.itmax) . Si esce dal ciclo do while quando scartonew < toll oppure quando iter ><br />

itmax.<br />

|ξ − x n |<br />

Sappiamo che, per lo schema <strong>di</strong> punto fisso, vale lim n→∞ = M = |g ′ (ξ)|. Poichè non conosciamo<br />

|ξ − x n−1<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 due variabili, che chiamiamo<br />

scartold e scartonew che corrispondono, rispettivamente, a |x n−1 −x n−2 | e |x n −x n−1 |. Le aggiorniamo in<br />

maniera del tutto analoga a quanto visto per xold e xnew. All’inizio, assegniamo a scartonew un valore più<br />

grande della tolleranza per fare in modo che si entri nel ciclo while senza problemi. Nel co<strong>di</strong>ce calcoliamo<br />

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 k<br />

C xnew : approssimazione al passo k+1<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 />

scartonew =2.0* t o l l<br />

scartold=scartonew<br />

i t e r = 0<br />

171


11. INTRODUZIONE AL FORTRAN 77<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 schema<br />

<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<br />

stesse 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 />

real *8 x<br />

gfun=cos ( x )<br />

return<br />

end<br />

172


11.12. I sottoprogrammi<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 fa 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). Per la derivata prima la<br />

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

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

Esempio <strong>di</strong><br />

function<br />

dgfun<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 />

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<br />

sono usate all’interno della function, si scrivono tutte le istruzioni che servono (anche cicli if, o while<br />

se occorrono).<br />

G La function termina con le istruzioni <strong>di</strong> return e end.<br />

173


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 , xold , xnew , scartold , scartonew , 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 />

scartonew =2.0* t o l l<br />

scartold=scartonew<br />

i t e r = 0<br />

xold=x0<br />

write ( * , * ) ’ i t xkp1 scarto<br />

1 asint1 asint2 ’<br />

write ( * , * ) i t e r , xold , scartonew<br />

c a l l i t e r p f i s s o ( i t e r , itmax , xold , t o l l , scartonew , scartold , xnew)<br />

write ( * , * ) ’ approssimazione f i n a l e ’ , xnew<br />

stop<br />

end<br />

Osserviamo che la subroutine è chiamata tramite l’istruzione<br />

call iterpfisso( iter ,itmax,xold,toll,scartonew,scartold,xnew)<br />

Abbiamo parametri <strong>di</strong> input: iter, itmax, xold, toll, scartonew, scartold<br />

G Ci sono parametri <strong>di</strong> output: xnew<br />

Alcuni dei parametri <strong>di</strong> input, vengono mo<strong>di</strong>ficati all’interno della subroutine, altri no.<br />

G Nella <strong>di</strong>chiarazione delle variabili, non ci sono più le variabili che usiamo solo all’interno della<br />

subroutine (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 , xold , t o l l , scnew , scold , xnew)<br />

C sottoprogramma che implementa l ’ algoritmo del metodo <strong>di</strong> punto f i s s o<br />

implicit none<br />

integer i t e r , itmax<br />

real *8 xnew , xold , t o l l , scnew , scold , asint1 , asint2<br />

real *8 gfun , dgfun<br />

external gfun , dgfun<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 )<br />

scnew=abs (xnew− xold )<br />

asint1= scnew/ scold<br />

174


11.13. Il formato<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 delle 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,xold,toll,scartonew,scartold,xnew) nel programma principale<br />

subroutine iterpfisso(it,imx,xold,toll,scnew,scold,xnew) nella subroutine.<br />

L’importante è che le variabili abbiamo lo stesso significato (stesso tipo <strong>di</strong> variabile, ma anche<br />

stessa valenza <strong>di</strong> variabile) e devono essere messe nello stesso or<strong>di</strong>ne: se per sbaglio scriviamo<br />

call iterpfisso(itmax,iter,xold,toll ,scartonew,scartold,xnew) nel programma principale ma poi nella subroutine<br />

scriviamo subroutine iterpfisso(it,imx,xold,toll,scnew,scold,xnew) ,<br />

all’interno della subroutine io vado ad assegnare a it il valore che passato (che è quello <strong>di</strong> itmax), mentre a<br />

imx an<strong>di</strong>amo a passare il valore <strong>di</strong> iter (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. Vedasi asint1, asint2, gfun, dgfun.<br />

11.13 Il formato<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 />

Programma<br />

<strong>di</strong> punto fisso<br />

con<br />

l’istruzione<br />

format<br />

Nell’istruzione write, non abbiamo scritto write(*,*) ma write(*,100). Al posto del secondo<br />

simbolo * abbiamo messo un numero (un’etichetta).<br />

175


11. INTRODUZIONE AL FORTRAN 77<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 />

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

176


11.14. Files <strong>di</strong> dati<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 />

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

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 è:<br />

G far sì che durante l’esecuzione del programma venga generato un file <strong>di</strong> scrittura <strong>di</strong> dati: si apre il<br />

file all’interno del programma principale associando ad esso un numero (label) me<strong>di</strong>ante l’istruzione<br />

open. Per esempio, dopo la <strong>di</strong>chiarazione delle variabili, scriviamo<br />

open(10, file=’rispuntofisso.txt’)<br />

G 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<br />

scrivere la stampa dei risultati sul file contrassegnato dall’etichetta 10.<br />

G 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 />

Esempio <strong>di</strong><br />

file <strong>di</strong> dati<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 (dal 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 />

177


11. INTRODUZIONE AL FORTRAN 77<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 />

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

Programma<br />

sulla me<strong>di</strong>a<br />

dei vettori<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 />

178


11.16. Ciclo do<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 />

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

179


11. INTRODUZIONE AL FORTRAN 77<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 />

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

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

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

180


11.17. Matrici in FORTRAN<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 />

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 e bisogna ricordare è che ci deve essere corrispondenza tra quello<br />

che viene scritto sul file e le variabili a cui assegnare quei valori. Inoltre, lasciamo almeno uno spazio tra un<br />

valore e il successivo se li scriviamo sulla stessa riga.<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.<br />

Scriviamo sulla prima riga il valore <strong>di</strong> n e sulla seconda riga le componenti del vettore.<br />

4<br />

1. 2. 3. 4.<br />

Esempi <strong>di</strong> file<br />

vettoreinput.dat<br />

Oppure scriviamo sulla prima riga il valore <strong>di</strong> n e sulle righe successive le componenti del vettore.<br />

4<br />

1.<br />

2.<br />

3.<br />

4.<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 />

i=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 />

Programma<br />

sul prodotto<br />

matricevettore<br />

181


11. INTRODUZIONE AL FORTRAN 77<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 />

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

La matrice è stata <strong>di</strong>chiarata come real*8 A(20,20): al più 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 ciascuno<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 />

182


11.17. Matrici in FORTRAN<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 />

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

Supponiamo <strong>di</strong> dover scrivere più sottoprogrammi che richiamano matrici e vettori. Per le matrici, in ciascuno<br />

dei sottoprogrammi dobbiamo dare la <strong>di</strong>mensione massima delle righe: per esempio A(20,20) nel<br />

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>-<br />

183


11. INTRODUZIONE AL FORTRAN 77<br />

mensione 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 />

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<br />

possiamo eseguirlo 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><br />

co<strong>di</strong>ce e non tutte le righe in cui sono <strong>di</strong>chiarate le matrici e i vettori. . .<br />

11.17.2 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 />

184


11.18. La formula dei trapezi in FORTRAN<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 />

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.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 />

185


11. INTRODUZIONE AL FORTRAN 77<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 />

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 valo-<br />

186


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

re 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 />

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. 128.<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 />

187


11. INTRODUZIONE AL FORTRAN 77<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 />

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

C devo f are i l prodotto <strong>di</strong> A e B<br />

188


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

C ricordo la formula C_ij = somma_k ( A_ik * B_kj )<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 />

189


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

12<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 />

12.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191<br />

12.2 Grafici <strong>di</strong> funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191<br />

12.3 Salvare i grafici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194<br />

12.4 Grafici da files <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />

12.5 Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197<br />

12.6 Print . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199<br />

12.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.2 patchlevel 6, ultima mo<strong>di</strong>fica Settembre 2009, 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 12.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 />

12.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 />

191


12. CENNI SU GNUPLOT<br />

Figura 12.1: Ambiente gnuplot<br />

Figura 12.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 la<br />

funzione f(x). La funzione f(x) si scrive usando le stesse notazioni del Fortran. Si apre una finestra con il<br />

grafico della funzione, come si può vedere nella Figura 12.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 />

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

192


12.2. Grafici <strong>di</strong> funzioni<br />

Figura 12.3: Istruzione: plot sin(x) with points pt 5<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}.<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 12.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 12.4).<br />

G plot sin(x) with linespoints lw 2 pt 5 :<br />

<strong>di</strong>mensione 5 pt (si veda la Figura 12.5).<br />

Per fare un grafico semilogaritmico o logaritmico, prima <strong>di</strong> fare il grafico, si <strong>di</strong>gita il comando<br />

la linea è larga 2 lw mentre i punti hanno<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 />

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

193


12. CENNI SU GNUPLOT<br />

Figura 12.4: Istruzione: plot sin(x) with lines lw 2<br />

Figura 12.5: Istruzione: plot sin(x) with linespoints lw 2 pt 5<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 />

12.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 />

194


12.4. Grafici da files <strong>di</strong> dati<br />

Figura 12.6: Il grafico salvato come file prova.png<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), si sostituisce .gif con .jpeg (o<br />

.png) nei coman<strong>di</strong> precedenti 1 (si veda la Figura 12.6 per un esempio <strong>di</strong> grafico salvato come .png).<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 />

12.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 />

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

195


12. CENNI SU GNUPLOT<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 plot<br />

’dati.dat’ with lines o plot ’dati.dat with linespoints. Osserviamo che sul grafico, la legenda<br />

mostra il nome del file (nel nostro caso ’dati.dat’). Se vogliamo cambiare, si usa il comando title nel<br />

modo seguente:<br />

plot ’dati.dat’ title ‘‘nuova legenda’’<br />

dove il nuovo titolo è scritto 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 />

1.88496 0.95106 -0.30902<br />

2.19911 0.80902 -0.58779<br />

196


12.5. Script<br />

Figura 12.7: Grafico del file dati.dat<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 12.8 si può osservare il grafico risultante.<br />

12.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 />

set output "logfig.jpeg"<br />

plot [1:20] exp(2)*(1/x)**2<br />

197


12. CENNI SU GNUPLOT<br />

Figura 12.8: Grafico del file multi.dat me<strong>di</strong>ante le istruzioni che personalizzano la legenda.<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 non sono stati già resettati all’interno<br />

dello script, potrebbero creare problemi.<br />

Ad esempio, i due files precedenti vanno bene se eseguiti con il comando gnuplot da una finestra <strong>di</strong><br />

shell, mentre è meglio mo<strong>di</strong>ficarli se si vuole eseguirli me<strong>di</strong>ante il comando load, aggiungendo le seguenti<br />

ultime 2 righe 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 />

198


12.6. Print<br />

unset logscale<br />

set terminal wxt 0<br />

12.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 />

199


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

13<br />

PRIMI PASSI IN MATLAB®<br />

L’universo non potrà essere letto<br />

finché non avremo imparato il<br />

linguaggio ed avremo familiarizzato<br />

con i caratteri con cui è scritto. È<br />

scritto in linguaggio matematico, e<br />

le lettere sono triangoli, cerchi ed<br />

altre figure geometriche, senza le<br />

quali è umanamente impossibile<br />

comprendere una singola parola.<br />

Galileo Galilei<br />

13.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201<br />

13.2 Avvio <strong>di</strong> MATLAB® . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />

13.2.1 Matrici e vettori in MATLAB® . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />

13.3 Coman<strong>di</strong> utili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205<br />

13.4 MATLAB® per scrivere ed eseguire programmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206<br />

13.4.1 Strutture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206<br />

13.5 Dati <strong>di</strong> input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209<br />

13.5.1 Programma sul metodo delle bisezioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209<br />

13.6 Dati <strong>di</strong> output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210<br />

13.7 Grafici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211<br />

13.8 Sulle potenzialità <strong>di</strong> MATLAB® . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212<br />

13.9 Applicazioni <strong>di</strong> MATLAB® nel <strong>Calcolo</strong> <strong>Numerico</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213<br />

13.9.1 Sull’instabilità numerica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213<br />

13.9.2 Sull’interpolazione e approssimazione <strong>di</strong> dati . . . . . . . . . . . . . . . . . . . . . . . . . . 214<br />

13.9.3 Confronto tra schemi per equazioni <strong>di</strong>fferenziali or<strong>di</strong>narie . . . . . . . . . . . . . . . . . . 220<br />

13.1 Introduzione<br />

MATLAB® può essere considerato un linguaggio <strong>di</strong> programmazione ad alto livello e, allo stesso tempo,<br />

un ambiente interattivo per lo sviluppo <strong>di</strong> algoritmi, per la visualizzazione e l’analisi <strong>di</strong> dati, e per il calcolo<br />

numerico.<br />

201


13. PRIMI PASSI IN MATLAB®<br />

Per chi ha già imparato a programmare in linguaggio FORTRAN, il passaggio a MATLAB® è semplice (basta<br />

capire come cambiano le strutture <strong>di</strong> programmazione e il modo <strong>di</strong> programmare). In più, MATLAB® ha<br />

le sue functions, permette <strong>di</strong> fare calcoli molto più sofisticati <strong>di</strong> quelli che può fare una calcolatrice, e permette<br />

<strong>di</strong> fare grafici e visualizzare i risultati in maniera <strong>di</strong>retta. Molto spesso la conoscenza <strong>di</strong> MATLAB® è<br />

un requisito richiesto per molte posizioni lavorative in ambito ingegneristico: a tal fine, è utile imparare<br />

qualcosa <strong>di</strong> MATLAB® . Ed è altrettanto importante prendere atto del fatto che non esiste un linguaggio <strong>di</strong><br />

programmazione che vada bene per risolvere tutti i problemi (quin<strong>di</strong> non basta conoscere e saper usare un<br />

solo linguaggio <strong>di</strong> programmazione). Il FORTRAN si rivela la scelta migliore per risolvere algoritmi numerici<br />

complicati (un esempio tra tanti: risolvere problemi accoppiati <strong>di</strong> flusso e trasporto in mezzi porosi dove<br />

le incognite del problema sono dell’or<strong>di</strong>ne delle migliaia e migliaia). MATLAB® è esso stesso un programma<br />

complesso (originariamente scritto in FORTRAN e successivamente riscritto in linguaggio C) che va bene<br />

per risolvere programmi d’elaborazione numerica, per lavorare con matrici (MATLAB® infatti sta per MATrix<br />

LABoratory “laboratorio matriciale”) e per la grafica.<br />

MATLAB® è un prodotto della The MathWorkse vedremo in particolare la versione<br />

MATLAB® 7.10.0.499 (R2010a).<br />

Un prodotto simile a MATLAB® ma open source è GNU Octave (si vada sul sito http://www.octave.<br />

org).<br />

Nel seguito vedremo come si lavora in MATLAB® tenendo presente che quasi tutti i coman<strong>di</strong> che daremo<br />

valgono alla stessa maniera anche per Octave (eccezion fatta per l’interfaccia grafico).<br />

13.2 Avvio <strong>di</strong> MATLAB®<br />

Tralasciamo la parte relativa alla procedura <strong>di</strong> installazione <strong>di</strong> MATLAB® (che <strong>di</strong>pende dal computer e dal<br />

sistema operativo in uso) e <strong>di</strong>amo per scontato che il programma sia presente sul proprio computer.<br />

In ambiente Linux, per avviare MATLAB® basta <strong>di</strong>gitare il comando matlab da una finestra <strong>di</strong> terminale.<br />

Una volta avviato MATLAB® comparirà il prompt dei coman<strong>di</strong> in una finestra come quella mostrata in<br />

Figura 13.1. Per uscire dall’ambiente si <strong>di</strong>gita exit dalla finestra dei coman<strong>di</strong> oppure dal menu File o ancora<br />

dall’icona <strong>di</strong> chiusura (x in alto a destra della finestra).<br />

Per imparare a usare MATLAB® , inizialmente si prende familiarità con la finestra dei coman<strong>di</strong> eseguendo<br />

calcoli come se fosse una calcolatrice. Ve<strong>di</strong>amo che il risultato viene assegnato ad una variabile detta ans e<br />

che nella Workspace si trovano informazioni su <strong>di</strong> essa (si veda Figura 13.2).<br />

13.2.1 Matrici e vettori in MATLAB®<br />

I vettori si possono scrivere come vettori riga o vettori colonna.<br />

Per esempio:<br />

>>x=[1 2]<br />

>> x=[1 2]<br />

x =<br />

1 2<br />

>> y=[10 20]’<br />

y =<br />

10<br />

20<br />

Un vettore riga x viene scritto usando le parentesi quadre e scrivendo le componenti del vettore una dopo<br />

l’altra. Un vettore colonna può essere creato facendo la trasposta <strong>di</strong> un vettore riga (me<strong>di</strong>ante il simbolo ’ ),<br />

oppure mettendo un punto e virgola dopo ciascuna componente:<br />

202


13.2. Avvio <strong>di</strong> MATLAB®<br />

Figura 13.1: L’ambiente MATLAB consiste <strong>di</strong> una serie <strong>di</strong> finestre, alcune delle quali vengono aperte <strong>di</strong> default:<br />

la Command Window (la finestra dei coman<strong>di</strong>), la Current Folder (la <strong>di</strong>rectory corrente in cui si sta<br />

lavorando), la Workspace (lo spazio <strong>di</strong> lavoro) e la Command History (la finestra con la storia dei coman<strong>di</strong><br />

dati).<br />

Figura 13.2: Primi calcoli in MATLAB® : osservare cosa succede nella Command Window nella Workspace e<br />

nella Command History.<br />

203


13. PRIMI PASSI IN MATLAB®<br />

>> y=[10;20]<br />

y =<br />

10<br />

20<br />

In MATLAB® i vettori altro non sono che un caso particolare <strong>di</strong> matrice a n righe e 1 colonna (vettore<br />

colonna) o a 1 riga e n colonne (vettore riga). Quin<strong>di</strong> per scrivere una matrice si scrivono i valori della matrice<br />

riga per riga andando a capo con il punto e virgola:<br />

>> A=[1 2 3 4;<br />

5 6 7 8;<br />

9 10 11 12;<br />

13 14 15 16]<br />

A =<br />

1 2 3 4<br />

5 6 7 8<br />

9 10 11 12<br />

13 14 15 16<br />

Per matrici (e quin<strong>di</strong> per i vettori) si possono fare le operazioni <strong>di</strong> somma e prodotto in maniera molto<br />

semplice. Date due matrici A e B si ha<br />

G C=A+B: matrice somma<br />

G C=A-B: matrice <strong>di</strong>fferenza<br />

G C=A*B: matrice prodotto (deve essere la matrice A <strong>di</strong> <strong>di</strong>mensione n × m e la matrice B <strong>di</strong> <strong>di</strong>mensione<br />

m × r altrimenti si ha un messaggio <strong>di</strong> errore).<br />

G C=A’: matrice trasposta<br />

G C=A.*B : matrice i cui elementi sono C (i , j ) = A(i , j ) ∗ B(i , j )<br />

Osserviamo che, per in<strong>di</strong>care un valore della matrice A basta specificare l’in<strong>di</strong>ce <strong>di</strong> riga e <strong>di</strong> colonna: per<br />

esempio<br />

>> A(2,2)<br />

ans =<br />

6<br />

Per in<strong>di</strong>care gli elementi <strong>di</strong> tutta la colonna i si usa A(:,i), mentre A(i,:) in<strong>di</strong>ca gli elementi della riga i.<br />

>> A(:,2)<br />

ans =<br />

2<br />

6<br />

10<br />

14<br />

>> A(2,:)<br />

ans =<br />

5 6 7 8<br />

L’operatore due punti può dunque essere usato per estrarre un’intera riga o colonna da una matrice o<br />

un’intera sottomatrice. Se vogliamo estrarre le ultime due righe e colonne della matrice A, si <strong>di</strong>gita il comando<br />

204


13.3. Coman<strong>di</strong> utili<br />

>> M=A(3:4,3:4)<br />

M =<br />

11 12<br />

15 16<br />

In questo modo abbiamo creato la matrice M che ha come elementi quelli della sottomatrice <strong>di</strong> A con le ultime<br />

due righe e colonne.<br />

Per scrivere una matrice vuota A, invece, si usa l’istruzione A=[ ].<br />

Se si vuole risolvere un sistema lineare Ax = b in MATLAB® si può semplicemente usare una function<br />

propria <strong>di</strong> MATLAB® “nascosta” nell’operatore \ (backslash): basta <strong>di</strong>gitare il comando x= A \b, con b<br />

vettore colonna, per avere in x il vettore incognito. Ad esempio (si confronti con l’esercizio 7.6.2):<br />

>> A=[0.2 1 0.2; 1 6.5 1.75; 0 2 2.25]<br />

A =<br />

0.2000 1.0000 0.2000<br />

1.0000 6.5000 1.7500<br />

0 2.0000 2.2500<br />

>> b=[2.8 ; 19.25; 10.75]<br />

b =<br />

2.8000<br />

19.2500<br />

10.7500<br />

>> x=A\b<br />

x =<br />

1<br />

2<br />

3<br />

13.3 Coman<strong>di</strong> utili<br />

Per lavorare meglio sia nella finestra dei coman<strong>di</strong> sia, successivamente, per scrivere ed eseguire dei veri e<br />

propri programmi, risultano utili le seguenti funzioni:<br />

G who – fornisce l’elenco <strong>di</strong> tutte le variabili presenti nella finestra dei coman<strong>di</strong> (lo si può vedere anche<br />

nella Workspace;<br />

G whos – fornisce l’elenco <strong>di</strong> tutte le variabili insieme allo spazio in memoria da esse occupato;<br />

G help – può essere usato da solo o insieme al nome <strong>di</strong> una function <strong>di</strong> MATLAB® o creata dall’utente, e<br />

mostra tutte le informazioni utili per capire come usare MATLAB® o quella function;<br />

G clear – usata da sola cancella tutte le variabili presenti nella finestra dei coman<strong>di</strong>, seguita da un elenco<br />

<strong>di</strong> variabili (messe una <strong>di</strong> seguito all’altra senza virgole) cancella tutte quelle variabili;<br />

G il punto e virgola “;” messo dopo un’istruzione non fa vedere il risultato dell’istruzione nella finestra<br />

dei coman<strong>di</strong>;<br />

G il simbolo % è il simbolo per scrivere commenti:<br />

ciò che viene scritto dopo % rappresenta un<br />

commento;<br />

G <strong>di</strong>ary – permette <strong>di</strong> salvare, su un file che viene chiamato <strong>di</strong>ary, il contenuto <strong>di</strong> ciò che viene scritto<br />

nella finestra dei coman<strong>di</strong>. Il file <strong>di</strong>ary si trova nella <strong>di</strong>rectory corrente in cui si sta lavorando;<br />

G <strong>di</strong>ary off – chiude il file aperto me<strong>di</strong>ante l’istruzione <strong>di</strong>ary;<br />

205


13. PRIMI PASSI IN MATLAB®<br />

G <strong>di</strong>ary file<strong>di</strong>ary – comando analogo a <strong>di</strong>ary, ma il file non si chiamerà <strong>di</strong>ary bensì file<strong>di</strong>ary;<br />

G save filesave – salva tutte le variabili presenti nel Workspace, nel file filesave.mat;<br />

G load ’filesave’ – ripristina lo stato del Workspace, per esempio dopo aver chiuso la sessione <strong>di</strong><br />

MATLAB® , caricando tutte le variabili che erano state salvate in filesave.mat.<br />

C‘e una notevole <strong>di</strong>fferenza <strong>di</strong> significato tra i files generati dall’istruzione <strong>di</strong>ary e quelli generati me<strong>di</strong>ante<br />

save. Ciò che salviamo con il comando <strong>di</strong>ary è paragonabile a ciò che può essere scritto alla lavagna<br />

e <strong>di</strong> cui pren<strong>di</strong>amo appunti: scriviamo un file <strong>di</strong> testo che possiamo elaborare o da cui possiamo trarre dei<br />

risultati per i nostri problemi. Al contrario, quello che viene salvato me<strong>di</strong>ante il comando save è costituito<br />

da una o più variabili, che possono essere riutilizzate nuovamente in MATLAB® nella finestra dei coman<strong>di</strong>, in<br />

sessioni successive a quella in cui sono state create, senza dover rieseguire tutti i coman<strong>di</strong> che hanno portato<br />

alla creazione delle variabili stesse.<br />

Il comando save è utile anche per salvare singole matrici o una lista <strong>di</strong> matrici nella <strong>di</strong>rectory corrente. Ci<br />

soffermiamo sulla possibilità <strong>di</strong> salvare i dati in formato ASCII, in modo da poter utilizzare i dati che salviamo<br />

non solo in MATLAB® ma anche in programmi scritti con altri linguaggi <strong>di</strong> programmazione. Supponiamo<br />

<strong>di</strong> avere una matrice A e <strong>di</strong> volerla salvare nel file matriceA.dat. Scriveremo il comando<br />

save matriceA.dat A -ascii<br />

Quando vogliamo caricare in MATLAB® la matrice dal file useremo il comando<br />

load(’matriceA.dat’)<br />

e in questo modo avremo la matrice nella variabile matriceA (il nome del file senza l’estensione dopo il<br />

punto).<br />

13.4 MATLAB® per scrivere ed eseguire programmi<br />

A <strong>di</strong>fferenza del FORTRAN, MATLAB® non ha subroutines e functions ma solo functions che possono<br />

avere uno o più variabili <strong>di</strong> ingresso e una o più variabili in uscita.<br />

I files in cui vengono scritti i programmi si chiamano M-files dal fatto che hanno l’estensione .m:<br />

prova.m, fun.m, . . . I files vanno scritti con l’e<strong>di</strong>tor <strong>di</strong> testo <strong>di</strong> MATLAB® o con un altro e<strong>di</strong>tor <strong>di</strong> testo in<br />

formato ASCII (quello che facciamo per il FORTRAN).<br />

Quello che in FORTRAN corrisponde al programma principale, in MATLAB® prende il nome <strong>di</strong> script,<br />

per il fatto che presenta una lista <strong>di</strong> coman<strong>di</strong> da eseguire in ambiente MATLAB® , tra cui la chiamata alle<br />

functions proprie <strong>di</strong> MATLAB® o definite dall’utente (sempre tramite M-files). Inoltre non bisogna dare nessuna<br />

istruzione <strong>di</strong> inizio e fine programma (cioè non esiste l’equivalente delle istruzioni program e stop,<br />

end con cui apriamo e chiu<strong>di</strong>amo un programma principale in FORTRAN). È importante vedere subito una<br />

importante <strong>di</strong>fferenza tra FORTRAN e MATLAB® : mentre in FORTRAN, siamo abituati a scrivere un programma<br />

in un unico file, includendo in esso anche le subroutines e le functions che ci servono, poichè poi<br />

dobbiamo compilare per avere il programma eseguibile, in MATLAB® le functions e gli scripts vengono<br />

sempre scritti su files <strong>di</strong>stinti.<br />

Per eseguire uno script salvato in nomefile.m non c’è bisogno <strong>di</strong> dover compilare il programma (come<br />

invece si deve fare per il FORTRAN): basta lanciare il programma nella finestra dei coman<strong>di</strong> me<strong>di</strong>ante il<br />

nome del file (senza l’estensione .m) o me<strong>di</strong>ante il comando run(’nomefile.m’) o run(’nomefile’).<br />

Una function invece può essere eseguita tramite uno script oppure <strong>di</strong>rettamente nella finestra dei<br />

coman<strong>di</strong>, specificando le variabili <strong>di</strong> ingresso e <strong>di</strong> uscita, come vedremo con qualche esempio tra breve.<br />

Per quanto riguarda il nome da dare alle variabili, MATLAB® è sensibile alle lettere minuscole e<br />

maiuscole: una variabile chiamata A è <strong>di</strong>versa da a, una variabile XOLD è <strong>di</strong>versa da xold.<br />

È importante osservare, inoltre, che nello scrivere M-files le variabili utilizzate non vanno <strong>di</strong>chiarate,<br />

come invece va fatto in FORTRAN.<br />

13.4.1 Strutture<br />

Per capire le <strong>di</strong>fferenze <strong>di</strong> programmazione tra FORTRAN e MATLAB® , partiamo dagli operatori logici.<br />

Ve<strong>di</strong>amo nel seguito come si scrivono i vari cicli in FORTRAN e in MATLAB® :<br />

206


13.4. MATLAB® per scrivere ed eseguire programmi<br />

Operatore MATLAB® Operatore FORTRAN Significato<br />

< .LT minore<br />

> .GT. maggiore<br />

= .GE. maggiore o uguale<br />

== .EQ. uguale<br />

∼= .NE. non uguale<br />

&& .AND. congiunzione<br />

|| .OR. <strong>di</strong>sgiunzione<br />

∼ .NOT. negazione<br />

Tabella 13.1: Operatori relazionali e logici<br />

in FORTRAN<br />

i f ( espr . logica ) then<br />

{ istruzione 1a }<br />

{ istruzione 2a }<br />

{ . . . . }<br />

else<br />

{ istruzione 1b }<br />

{ istruzione 2b }<br />

{ . . . . }<br />

end i f<br />

in MATLAB®<br />

i f ( espr . logica )<br />

{ istruzione 1a }<br />

{ istruzione 2a }<br />

{ . . . . }<br />

else<br />

{ istruzione 1b }<br />

{ istruzione 2b }<br />

{ . . . . }<br />

end<br />

in FORTRAN<br />

i f ( espr . logica1 ) then<br />

{ istruzione 1a }<br />

{ istruzione 2a }<br />

{ . . . . }<br />

else i f ( espr . logica2 ) then<br />

{ istruzione 1b }<br />

{ istruzione 2b }<br />

{ . . . . }<br />

. . . .<br />

else<br />

{ istruzione 1z }<br />

{ istruzione 2z }<br />

{ . . . . }<br />

end i f<br />

in MATLAB®<br />

i f ( espr . logica1 )<br />

{ istruzione 1a }<br />

{ istruzione 2a }<br />

{ . . . . }<br />

e l s e i f ( espr . logica2 )<br />

{ istruzione 1b }<br />

{ istruzione 2b }<br />

{ . . . . }<br />

. . . .<br />

else<br />

{ istruzione 1z }<br />

{ istruzione 2z }<br />

{ . . . . }<br />

end<br />

Osserviamo che in MATLAB® non ci sono i then e che elseif va scritto tutto attaccato.<br />

207


13. PRIMI PASSI IN MATLAB®<br />

in FORTRAN<br />

do while ( espressione logica )<br />

{ istruzione 1 }<br />

{ istruzione 2 }<br />

{ . . . }<br />

{ istruzione n }<br />

end do<br />

in MATLAB<br />

while ( espressione logica )<br />

{ istruzione 1 }<br />

{ istruzione 2 }<br />

{ . . . }<br />

{ istruzione n }<br />

end<br />

Nel ciclo while si elimina il do.<br />

in FORTRAN<br />

do ind= v a l i n i z , v a l f i n , incr<br />

{ i s t r u z i o n i }<br />

end do<br />

in MATLAB<br />

for ind= v a l i n i z : incr : v a l f i n<br />

{ i s t r u z i o n i }<br />

end<br />

Il ciclo do in FORTRAN <strong>di</strong>venta ciclo for in MATLAB® . L’or<strong>di</strong>ne delle variabili relative al valore iniziale<br />

del ciclo, valore finale e incremento non è più come in FORTRAN e ci sono i due punti al posto della virgola:<br />

osservare bene le <strong>di</strong>fferenze.<br />

C’è un’altra struttura che si trova in MATLAB® e non in FORTRAN 77: è la costruzione switch-case.<br />

switch ( espressione ) % ( s c a l a r e o stringa )<br />

case { valore1 } % eseguita se l ’ espressione e ’ valutata al valore1 )<br />

{ i s t r u z i o n i }<br />

{ . . . }<br />

case { valore2 } % ( eseguita se l ’ espressione e ’ valutata al valore2 )<br />

{ i s t r u z i o n i }<br />

{ . . . }<br />

otherwise<br />

{ i s t r u z i o n i }<br />

{ . . . }<br />

end<br />

Il ciclo con switch confronta i valori dati nell’espressione <strong>di</strong> input (subito dopo switch) con ciascun<br />

valore assegnato a case ed esegue le istruzioni relative al case in cui valore ed espressione coincidono.<br />

Nell’esempio che riportiamo, a seconda del valore assegnato alla variabile scelta cambiano i valori da<br />

assegnare alle variabili a e b:<br />

s c e l t a =’test1’ ;<br />

switch s c e l t a<br />

case {’test1’}<br />

x0= 0 . 1 ;<br />

x1= 0 . 2 ;<br />

case {’test2’}<br />

x0= 0 . 0 ;<br />

x1= 1 . 0 ;<br />

otherwise<br />

<strong>di</strong>sp (’nessun␣caso␣test␣scelto’)<br />

end<br />

Osserviamo che scelta è una variabile <strong>di</strong> stringa <strong>di</strong> caratteri, il nome del caso test scritto tra apici; per<br />

visualizzare un messaggio sulla Command Window, abbiamo usato la function <strong>di</strong> MATLAB® chiamata <strong>di</strong>sp.<br />

208


13.5. Dati <strong>di</strong> input<br />

13.5 Dati <strong>di</strong> input<br />

Quando si lavora nella finestra dei coman<strong>di</strong>, per assegnare il valore alle variabili basta scrivere il nome<br />

della variabile seguito dal simbolo <strong>di</strong> uguale e dal valore (o dai valori) da assegnare (a seconda che si tratti <strong>di</strong><br />

una variabile scalare, matrice, vettore...):<br />

>> a=10.5;<br />

>> A=[1 2 3; 4 5 6; 7 8 9];<br />

Nell’eseguire uno script, alla stessa maniera, si può assegnare il valore alle variabili <strong>di</strong>rettamente all’interno<br />

dello script. Tuttavia, se si vuole dare maggiore generalità al programma e si vogliono dare in input i valori<br />

delle variabili, conviene usare la function input. Ve<strong>di</strong>amo con un esempio:<br />

a=input(’␣scrivi␣il␣valore␣della␣variabile␣a␣’)<br />

Il messaggio contenuto tra apici viene visualizzato sulla finestra dei coman<strong>di</strong> e il prompt aspetterà che l’utente<br />

scriva il valore da assegnare ad a. La function input si può dunque paragonare alle istruzioni <strong>di</strong> write<br />

e read in FORTRAN per assegnare il valore alle variabili.<br />

Questa procedura può essere utilizzata sia per assegnare il valore a variabili scalari, sia per matrici e vettori.<br />

Tuttavia, se i dati <strong>di</strong> input sono molto “pesanti” (ad esempio matrici <strong>di</strong> <strong>di</strong>mensioni molto elevate), conviene<br />

usare in maniera opportuna la funzione <strong>di</strong> input unitamente al comando load - scrivendo una volta per tutte<br />

la matrice <strong>di</strong> input in un file da caricare ogni volta che si vuole eseguire il programma con quella matrice.<br />

Per esempio, abbiamo scritto nel file A.dat i valori della matrice e vogliamo dare in input questa matrice al<br />

nostro programma. Invece <strong>di</strong> scrivere<br />

A= input(’␣matrice␣A␣’);<br />

nello script scriveremo<br />

A= input(’␣file␣<strong>di</strong>␣input␣con␣la␣matrice␣A␣’, ’s’);<br />

A= load(A);<br />

Osserviamo che abbiamo usato input inserendo, oltre alla stringa tra apici ’file <strong>di</strong> input con la<br />

matrice A’, anche ’s’: questa opzione serve perchè noi scriveremo il nome del file su cui si trova memorizzata<br />

la matrice e questo file viene letto come una stringa <strong>di</strong> caratteri per cui inizialmente alla variabile A<br />

viene associato il file con la matrice (in questo caso A.dat). Con il comando successivo, viene caricato il file<br />

e memorizzato <strong>di</strong> nuovo sulla variabile A, che quin<strong>di</strong> <strong>di</strong>venta la nostra matrice.<br />

Si osservi la <strong>di</strong>fferenza che c’è nel lasciare o meno spazi bianchi prima dell’apice che chiude la frase che<br />

viene visualizzata sulla Command Window tramite input.<br />

È utile sapere anche che, se un’istruzione è troppo lunga e si vuole andare a capo, si utilizzano tre puntini<br />

... sulla riga che si vuole interrompere e si prosegue a scrivere sulla riga successiva.<br />

13.5.1 Programma sul metodo delle bisezioni<br />

Consideriamo l’algoritmo del metodo delle bisezioni come descritto a pag. 38 per calcolare gli zeri <strong>di</strong><br />

un’opportuna funzione f .<br />

Ad esempio vogliamo risolvere il problema f (x) = 0 con f (x) = ( x 2 )2 − sin(x)<br />

nell’intervallo [1,3].<br />

Dobbiamo scrivere il programma principale, in un file che chiamiamo bisez.m, e la function legata alla<br />

funzione f (x), in un file che chiamiamo fun.m.<br />

Scriviamo il programma principale:<br />

% programma per i l calcolo d e g l i z e r i <strong>di</strong> una funzione me<strong>di</strong>ante<br />

% i l metodo <strong>di</strong> bisezione<br />

a=input (’primo␣estremo␣dell’’intervallo␣a␣’ ) ;<br />

b=input (’secondo␣estremo␣dell’’intervallo␣b␣’ ) ;<br />

aux=fun ( a ) * fun (b ) ;<br />

i f aux>=0<br />

<strong>di</strong>sp (’estremi␣dello␣stesso␣segno’)<br />

break<br />

end<br />

itmax =100;<br />

209


13. PRIMI PASSI IN MATLAB®<br />

t o l l =1.e−10;<br />

i t e r =0;<br />

c =(a+b ) * 0 . 5 ;<br />

scarto=abs (b−a ) * 0 . 5 ;<br />

while i t e r t o l l<br />

i t e r = i t e r +1;<br />

aux=fun ( a ) * fun ( c ) ;<br />

i f aux>0<br />

a=c ;<br />

else<br />

b=c ;<br />

end<br />

c =(a+b ) * 0 . 5 ;<br />

scarto=abs (b−a ) * 0 . 5 ;<br />

end<br />

i f fun ( c)==0 | | scarto < t o l l<br />

s p r i n t f (’%s␣%15.8e’ , ’soluzione␣approssimata␣c=␣’ , c )<br />

else<br />

s p r i n t f (’%s’ , ’raggiunto␣numero␣max␣<strong>di</strong>␣iterazioni␣’)<br />

end<br />

Per poter essere eseguito, dobbiamo scrivere in un file chiamato fun.m la function fun. Si ha:<br />

function y=fun ( x )<br />

% funzione per lo schema d e l l e b i s e z i o n i<br />

% input x<br />

% output y =(x /2)^2 −sin ( x )<br />

y=( x/2).^2 − sin ( x ) ;<br />

Nel programma principale abbiamo semplicemente tradotto l’algoritmo del metodo delle bisezioni. Abbiamo<br />

considerato dei coman<strong>di</strong> che non abbiamo ancora visto in MATLAB® , per la stampa dei risultati (me<strong>di</strong>ante<br />

sprintf) e abbiamo usato il comando break per interrompere l’esecuzione del programma se una<br />

con<strong>di</strong>zione non è verificata.<br />

Le righe <strong>di</strong> commento scritte dopo l’istruzione function y=fun(x) vengono visualizzate sulla<br />

Command Window se, una volta salvata la function, <strong>di</strong>gitiamo l’istruzione help fun<br />

13.6 Dati <strong>di</strong> output<br />

L’ambiente MATLAB® permette <strong>di</strong> visualizzare tutte le variabili presenti al termine dell’esecuzione <strong>di</strong> un<br />

programma o <strong>di</strong> una funzione. Tuttavia, alcune volte vogliamo visualizzare subito dei risultati sulla Command<br />

Window o su un file separato rispetto all’ambiente <strong>di</strong> lavoro. Abbiamo già visto, nell’esempio precedente<br />

il comando sprintf: esso serve per stampare un messaggio sulla Command Window utilizzando un<br />

certo tipo <strong>di</strong> formato.<br />

Nell’esempio avevamo usato<br />

sprintf(’%s␣%15.8e’, ’soluzione␣approssimata␣c=␣’, c)<br />

All’interno delle parentesi tonde si possono riconoscere due parti: nella prima parte si scrive, tra apici e uno <strong>di</strong><br />

seguito all’altro, il formato da utilizzare per la stampa delle variabili che sono scritte subito dopo. Nel nostro<br />

caso, le variabili da stampare sono la stringa <strong>di</strong> caratteri soluzione approssimata c= e il valore della<br />

variabile c. Per la stringa <strong>di</strong> caratteri si usa il formato delle stringhe che è dato da %s mentre per la variabile c,<br />

volendo scriverla me<strong>di</strong>ante un formato esponenziale con 8 cifre nella mantissa, usiamo il formato %15.8e.<br />

Rispetto al FORTRAN, il formato per una variabile è preceduto dal simbolo % ma per il resto non ci sono<br />

grosse <strong>di</strong>fferenze. Per la variabili intere o reali possiamo decidere quante cifre utilizzare per rappresentare la<br />

variabile (%15.8e nell’esempio). Riassumiamo nella tabella seguente i principali tipi <strong>di</strong> formato e i simboli<br />

che servono per andare a capo o creare nuove linee: Se si vogliono scrivere i risultati su un file, occorre aprire<br />

il file e associarlo ad una variabile me<strong>di</strong>ante la function fopen. Ad esempio<br />

fid= fopen(’risultati.txt’,’w’)<br />

210


13.7. Grafici<br />

formato<br />

Significato<br />

%s stringhe <strong>di</strong> caratteri<br />

%d formato intero<br />

%f formato fisso<br />

%e formato esponenziale (del tipo 3.5e + 00)<br />

%E formato esponenziale (del tipo 3.5E + 00)<br />

\ n nuova linea<br />

\ r per andare a capo<br />

Tabella 13.2: Il formato<br />

Figura 13.3: Finestra con il grafico<br />

Con questa istruzione aprimamo il file <strong>di</strong> risultati dal nome risultati.txt (’w’ in<strong>di</strong>ca che il file è <strong>di</strong><br />

scrittura) associandolo alla variabile fid. Per scrivere sul file, al posto della function sprintf si userà la<br />

function fprintf che <strong>di</strong>fferisce dalla prima per il fatto che bisogna in<strong>di</strong>care la variabile associata al file <strong>di</strong><br />

scrittura dati. Il comando sprintf <strong>di</strong> prima <strong>di</strong>venta ora:<br />

fprintf(fid , ’%s␣%15.8e’, ’soluzione␣approssimata␣c=␣’, c)<br />

Per chiudere il file si usa l’istruzione fclose(fid). Quin<strong>di</strong> fopen e fclose sono equivalenti alle<br />

istruzioni open e close che abbiamo visto in FORTRAN.<br />

13.7 Grafici<br />

Supponiamo <strong>di</strong> voler fare il grafico <strong>di</strong> una serie <strong>di</strong> dati (x i , y i ), i = 1,...,n. Sulla Command Window (o<br />

all’interno <strong>di</strong> uno script) basta <strong>di</strong>gitare il comando<br />

plot(x,y)<br />

Si aprirà una nuova finestra con il grafico (ve<strong>di</strong> Figura 13.3).<br />

Potremo poi mo<strong>di</strong>ficare il colore, il tipo <strong>di</strong> linea, inserire titolo, legenda,...operando <strong>di</strong>rettamente sul menu<br />

della finestra del grafico, o inserendo i coman<strong>di</strong> opportuni tramite la Command Window 1 .<br />

Si possono sovrascrivere grafici l’uno sull’altro utilizzando il comando hold on. Oppure si possono<br />

affiancare grafici me<strong>di</strong>ante il comando subplot. Lasciamo gli approfon<strong>di</strong>menti all’help on line.<br />

1 Ci sarebbe tanto da <strong>di</strong>re a riguardo ma lasciamo che il lettore curioso approfon<strong>di</strong>sca l’argomento utilizzando l’help on line <strong>di</strong><br />

MATLAB® . In Octave, invece, le mo<strong>di</strong>fiche ai grafici non possono essere fatte usando la finestra del grafico.<br />

211


13. PRIMI PASSI IN MATLAB®<br />

Per fare il grafico <strong>di</strong> una funzione, si possono seguire <strong>di</strong>verse strade.<br />

Se si ha a <strong>di</strong>sposizione la function (propria <strong>di</strong> MATLAB® o scritta su un file .m), si può costruire il vettore<br />

con il valore della funzione in un numero determinato <strong>di</strong> punti equi<strong>di</strong>stanti sull’intervallo in cui si desidera<br />

visualizzarla. A tal proposito è utile la function linspace che permette <strong>di</strong> <strong>di</strong>scretizzare un intervallo chiuso<br />

[a,b] in un prefissato numero <strong>di</strong> punti. Useremo allora le seguenti istruzioni:<br />

x=linspace ( 0 , 2 ) ;% <strong>di</strong>scretizziamo l ’ i n t e r v a l l o [ 0 , 2 ] in 100 parti<br />

% uguali<br />

% x=linspace (50 , 0 , 2 ) d i s c r e t i z z a l ’ i n t e r v a l l o in<br />

%50 parti uguali<br />

y=myfun( x ) ; % valuto la function myfun nel v e t t o r e x<br />

plot ( x , y )<br />

Questo approccio è comodo quando la funzione da visualizzare ha una espressione complicata o quando<br />

stiamo lavorando all’interno <strong>di</strong> uno script. La function myfun deve essere scritta in modo che sia possibile<br />

valutarla <strong>di</strong>rettamente su un vettore (che è quello che facciamo tramite l’istruzione y=myfun(x)). Le<br />

operazioni <strong>di</strong> moltiplicazione, <strong>di</strong>visione ed elevamento a potenza devono essere vettorizzate, facendo precendere<br />

il simbolo <strong>di</strong> moltiplicazione, <strong>di</strong>visione e elevamento a potenza dal simbolo del punto – .*, ./,<br />

.ˆ – permettendo, in tal modo, che le operazioni vengano fatte componente per componente del vettore. Le<br />

operazioni <strong>di</strong> somma e <strong>di</strong>fferenza sono vettorizzate per definizione.<br />

Ad esempio: la function myfun definita tramite le istruzioni<br />

function [ y ]= f ( x )<br />

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

non è vettorizzata. Se invece scriviamo<br />

function [ y ]= f ( x )<br />

y=log ( x ) . * x<br />

allora la function è vettorizzata.<br />

Un’altra via è <strong>di</strong> scrivere la function come una funzione inline nella Command Window e <strong>di</strong> utilizzare la<br />

function ezplot per farne il grafico.<br />

Supponiamo <strong>di</strong> voler fare il grafico della funzione f (x) = e x −10sin(x)−1. Per avere questa funzione nella<br />

Command Window durante la sessione <strong>di</strong> lavoro (quin<strong>di</strong> non come una function scritta su file), scriviamo il<br />

comando<br />

fun = inline(’exp(x)-10*sin(x)-1’)<br />

Sulla Command Window compaiono le seguenti righe:<br />

>> fun=inline(’exp(x)-10*sin(x)-1’)<br />

fun =<br />

Inline function:<br />

fun(x) = exp(x)-10*sin(x)-1<br />

Se vogliamo farne il grafico nell’intervallo [0,2] scriveremo<br />

ezplot(fun, 0, 2)<br />

e viene <strong>di</strong>rettamente creato il grafico della funzione fun. La function ezplot può essere utilizzata anche<br />

con funzioni intrinseche <strong>di</strong> MATLAB® o definite dall’utente in forma vettorizzata (per esempio<br />

ezplot(’sin’,0,2)<br />

crea il grafico della funzione sin(x) nell’intervallo [0,2]).<br />

13.8 Sulle potenzialità <strong>di</strong> MATLAB®<br />

MATLAB® ha un grande numero <strong>di</strong> functions predefinite che permettono <strong>di</strong> eseguire applicazioni in <strong>di</strong>versi<br />

settori propriamente matematici, per approssimare zeri <strong>di</strong> funzioni, per lavorare su matrici sparse, ri-<br />

212


13.9. Applicazioni <strong>di</strong> MATLAB® nel <strong>Calcolo</strong> <strong>Numerico</strong><br />

solvere equazioni <strong>di</strong>fferenziali, lavorare su dati statistici, fare grafici in due e tre <strong>di</strong>mensioni... Basta vedere il<br />

Demo <strong>di</strong> MATLAB® per trovare la function <strong>di</strong> cui si ha bisogno.<br />

È possibile inoltre installare pacchetti specifichi per specifiche aree <strong>di</strong> applicazioni, quali sistemi <strong>di</strong><br />

controllo, biologia computazionale, finanza computazionale, meccatronica...<br />

In questa breve presentazione <strong>di</strong> MATLAB® , tuttavia, cercheremo <strong>di</strong> vedere come utilizzarlo per capire<br />

meglio alcuni dei problemi trattati in <strong>Calcolo</strong> <strong>Numerico</strong>, rielaborando o ripresentando alcuni esempi già visti.<br />

13.9 Applicazioni <strong>di</strong> MATLAB® nel <strong>Calcolo</strong> <strong>Numerico</strong><br />

13.9.1 Sull’instabilità numerica<br />

Ripren<strong>di</strong>amo l’esempio 3.7.1 visto nel Capitolo 3 per cui vogliamo approssimare il valore <strong>degli</strong> integrali<br />

espressi me<strong>di</strong>ante la formula<br />

∫ 1<br />

x n<br />

y n =<br />

0 x + 10 dx<br />

per valori <strong>di</strong> n = 1,2,...,30.<br />

Avevamo visto due formule ricorsive che ci permettevano <strong>di</strong> approssimare y n , una era instabile e l’altra<br />

era stabile.<br />

Proviamo a rivedere gli algoritmi (nell’esempio 3.7.1) e scriviamo un programma MATLAB® da eseguire<br />

per verificare quanto avevamo detto.<br />

% E s e r c i z i o sull ’ i n s t a b i l i t a ’ numerica<br />

% calcolo dell ’ i n t e g r a l e y_n= int_0^1 x^n / ( x+10) dx<br />

%<br />

% y i n s t : v e t t o r e con i v a l o r i dell ’ algoritmo i n s t a b i l e<br />

% y s t : v e t t o r e con i v a l o r i dell ’ algoritmo s t a b i l e<br />

%<br />

% algoritmo i n s t a b i l e<br />

%<br />

y inst (1)= log (11) −log ( 1 0 ) ; %corrisponde al valore i n i z i a l e<br />

for i =1:30<br />

y inst ( i +1)= 1/ i −10* y inst ( i ) ;<br />

end<br />

%<br />

% algoritmo s t a b i l e<br />

% s i r i c hiede che i l valore dell ’ i n t e g r a l e y_n1 s i a approssimato<br />

% con una accuratezza data dal valore <strong>di</strong> input t o l<br />

n1= input (’␣in<strong>di</strong>ce␣n1’ ) ;<br />

t o l =input (’␣tolleranza␣tol’ ) ;<br />

k= −log10 ( t o l ) + n1 ;<br />

k= f i x ( k + 1 ) ; % f i x e ’ una function che e f f e t t u a l ’ arrotondamento<br />

% del numero in modo da avere un valore intero<br />

yst ( k ) = 0 ;<br />

for j =k−1:−1:1<br />

yst ( j ) =1/10*(1/ j − yst ( j + 1 ) ) ;<br />

end<br />

Uno volta eseuito lo script, nella Command Window si hanno i due vettori che possono essere confrontati tra<br />

loro. Osserviamo che l’equivalente programma FORTRAN sarebbe meglio scriverlo non utilizzando i vettori<br />

e facendosi stampare i risultati interme<strong>di</strong> su un file. In questo caso, potendo avere i risultati sulla Command<br />

Window, ci conviene usare dei vettori. Il valore iniziale y 0 si avrà nella prima componente dei vettori che<br />

vengono creati. Perciò si faccia attenzione agli in<strong>di</strong>ci utilizzati (per yst si usa j e j+1: perchè?).<br />

Volendo, si può mo<strong>di</strong>ficare lo script facendo uso della function <strong>di</strong> MATLAB® single che converte il<br />

risultato in singola precisione in modo da confrontare i due algoritmi con i calcoli in singola precisione.<br />

213


13. PRIMI PASSI IN MATLAB®<br />

Figura 13.4: Algoritmo instabile: schermata del confronto tra l’uso o meno della function single<br />

% y i n s t s i n g : v e t t o r e dell ’ algoritmo i n s t a b i l e lavorando<br />

% in singola precisione<br />

% y s t s i n g : v e t t o r e dell ’ algoritmo s t a b i l e lavorando<br />

% in singola precisione<br />

yinstsing (1)= single ( log ( 1 1 ) ) −single ( log ( 1 0 ) ) ;<br />

for i =1:30<br />

yinstsing ( i +1)= single (1/ i ) −single (10* yinstsing ( i ) ) ;<br />

end<br />

n1= input (’␣in<strong>di</strong>ce␣n1’ ) ;<br />

t o l =input (’␣tolleranza␣tol’ ) ;<br />

k= −log10 ( t o l ) + n1 ;<br />

k= f i x ( k + 1 ) ;<br />

ystsing ( k ) = 0 ;<br />

for j =k−1:−1:1<br />

ystsing ( j ) = single (1/10)* single (1/ j − ystsing ( j + 1 ) ) ;<br />

end<br />

Come si può osservare dalle Figure 13.4 e 13.5, i risultati ottenuti dall’algoritmo instabile cambiano a seconda<br />

che si usi o meno la function single mentre abbiamo gli stessi risultati (consideriamo le cifre corrette in<br />

singola precisione, usando il formato format short e) per l’algoritmo stabile.<br />

13.9.2 Sull’interpolazione e approssimazione <strong>di</strong> dati<br />

In MATLAB® esistono già delle function che permettono <strong>di</strong> interpolare e approssimare delle serie <strong>di</strong> dati.<br />

C’è la function polyfit che, dati i vettori contenenti le ascisse e le or<strong>di</strong>nate da interpolare o approssimare,<br />

<strong>di</strong> <strong>di</strong>mensione n, e il grado m del polinomio che si vuole creare, fornisce in output il vettore contenente i<br />

214


13.9. Applicazioni <strong>di</strong> MATLAB® nel <strong>Calcolo</strong> <strong>Numerico</strong><br />

Figura 13.5: Algoritmo stabile: schermata del confronto tra l’uso o meno della function single<br />

coefficienti del polinomio interpolante (o approssimante) in or<strong>di</strong>ne decrescente [a m a m−1 ... a 0 ] da cui il polinomio<br />

è p(x) = a m x m + a m−1 x m−1 +... a 0 : per m = n −1 si ha il polinomio <strong>di</strong> interpolazione, per m < n −1 si<br />

ha il polinomio <strong>di</strong> approssimazione. L’algoritmo si basa sul processo <strong>di</strong> minimizzazione nel senso dei minimi<br />

quadrati.<br />

Esempio:<br />

>> x=[7 8 9 10];<br />

>> y=[3 1 1 9];<br />

>> p=polyfit(x,y,3)<br />

p =<br />

1.0000 -23.0000 174.0000 -431.0000<br />

Significa che il polinomio <strong>di</strong> interpolazione è:<br />

p(x) = x 3 − 23x 2 + 174x − 431<br />

Una volta ricavati i coefficienti, si può fare un grafico del polinomio utilizzando la function polyval.<br />

>> xx=linspace(x(1), x(4));<br />

>> yy=polyval(p,xx);<br />

>> plot(x,y,’o’, xx,yy)<br />

215


13. PRIMI PASSI IN MATLAB®<br />

Con polyval si valuta il polinomio, i cui coefficienti sono dati dal vettore p, nei punti <strong>di</strong> xx. Abbiamo usato<br />

la function plot per rappresentare sullo stesso grafico due curve, quella dei dati x,y (grafico che facciamo<br />

per punti utilizzando dei “cerchietti”) e quella del polinomio.<br />

Scriviamo ora delle function che ci permettano <strong>di</strong> ottenere il polinomio <strong>di</strong> interpolazione sia usando<br />

l’approccio delle funzioni base monomiali che porta alla costruzione della matrice <strong>di</strong> Vandermonde,<br />

sia costruendo i polinomi <strong>di</strong> Lagrange o utilizzando le <strong>di</strong>fferenze <strong>di</strong>vise <strong>di</strong> Newton (si riveda il Capitolo 5<br />

sull’interpolazione).<br />

Usando le funzioni base monomiali, scriviamo la seguente function, interpmonom:<br />

function p=interpmonom( x , y )<br />

% function p=interpmonom ( x , y )<br />

% interpolazione monomiale<br />

% dati i v a l o r i x e y da interpolare s i c o s t r u i s c e i l v e t t o r e p<br />

% dei c o e f f i c i e n t i del polinomio <strong>di</strong> interpolazione<br />

% applicando i l metodo dei c o e f f i c i e n t i indeterminati<br />

%<br />

% se x e y non sono gia ’ v e t t o r i colonna l i ren<strong>di</strong>amo t a l i<br />

% me<strong>di</strong>ante l e due i s t r u z i o n i s u c c e s s i v e<br />

x=x ( : ) ;<br />

y=y ( : ) ;<br />

i f length ( x)~= length ( y )<br />

% length e ’ una function che misura la lunghezza del v e t t o r e<br />

% ( s i confronti la d i f f e r e n z a tra length e s i z e )<br />

error (’MATLAB:interpmonom’ , . . .<br />

’i␣vettori␣x␣e␣y␣non␣hanno␣la␣stessa␣lunghezza’)<br />

else<br />

n=length ( x ) −1;<br />

% V matrice <strong>di</strong> Vandermonde c o s t r u i t a in maniera r i c o r s i v a<br />

V( : , 1 ) = ones (n+1 , 1 ) ;<br />

for i =2:n+1<br />

V ( : , i )= x . * V ( : , i −1);<br />

end<br />

p=V\y ;<br />

% i l v e t t o r e p contiene i c o e f f i c i e n t i del polinomio i n t e r p o l a t o r e<br />

% in or<strong>di</strong>ne c r e s c e n t e − p0 p1 p2 . . .<br />

% se vogliamo usare la function del MATLAB polyval per valutare<br />

% t a l e polinomio in piu ’ punti , dobbiamo s c r i v e r l i in or<strong>di</strong>ne decrescente<br />

for i =1:n+1<br />

aux ( i )=p(n+2− i ) ;<br />

end<br />

p=aux ;<br />

end<br />

Osserviamo che abbiamo usato l’istruzione error per mostrare un messaggio <strong>di</strong> errore e far interrompere<br />

l’esecuzione della function, nel caso in cui i dati <strong>di</strong> input x e y non abbiano la stessa lunghezza. La stringa<br />

’MATLAB:interpmonom’ è una stringa <strong>di</strong> identificazione dell’errore (puù essere anche omessa), mentre la<br />

stringa ’i vettori x e y non hanno la stessa lunghezza’ è quella che viene visualizzata durante l’esecuzione del<br />

co<strong>di</strong>ce.<br />

La matrice V è stata costruita in maniera ricorsiva. Una volta calcolato il vettore p possiamo valutare il<br />

polinomio <strong>di</strong> interpolazione me<strong>di</strong>ante la polyval.<br />

Riprendendo l’esempio <strong>di</strong> prima, con x,y,xx,yy già dati:<br />

>> p=interpmonom(x,y);<br />

>> plot(x,y,’o’, xx,yy)<br />

Per quanto riguarda l’interpolazione <strong>di</strong> Lagrange, si considerino le due functions che chiamamo<br />

lagrange e interplagrange rispettivamente. La prima valuta l’i -simo polinomio <strong>di</strong> Lagrange e l’altra<br />

valuta il polinomio <strong>di</strong> interpolazione <strong>di</strong> Lagrange in un assegnato punto (o nelle componenti <strong>di</strong> un vettore).<br />

216


13.9. Applicazioni <strong>di</strong> MATLAB® nel <strong>Calcolo</strong> <strong>Numerico</strong><br />

function yval=lagrange ( xval , x , i )<br />

% function yval=lagrange ( xval , x , i )<br />

% function che calcola i l polinomio i−simo <strong>di</strong> Lagrange<br />

% valutandolo in xval<br />

% xval puo ’ e s s e r e uno s c a l a r e o un v e t t o r e<br />

% x − v e t t o r e d e l l e a s c i s s e da interpolare<br />

xval=xval ( : ) ;<br />

n=length ( x ) ;<br />

yval =ones ( length ( xval ) , 1 ) ; % s i crea un v e t t o r e <strong>di</strong> t u t t i 1<br />

for j =1:n<br />

i f j ~= i<br />

yval=yval . * ( xval−x ( j ) ) / ( x ( i ) −x ( j ) ) ;<br />

end<br />

end<br />

function yval=interplagrange ( xval , x , y )<br />

% function yval=interplagrange ( xval , x , y )<br />

% dati i v e t t o r i x e y da interpolare<br />

% la function implementa l ’ interpolazione <strong>di</strong> Lagrange valutandola<br />

% in xval<br />

% xval puo ’ e s s e r e uno s c a l are o un v e t t o r e<br />

% questa function chiama la function lagrange ( xval , x , i )<br />

i f length ( x)~= length ( y )<br />

error (’MATLAB:interplagrange’ , . . .<br />

’i␣vettori␣x␣e␣y␣non␣hanno␣la␣stessa␣lunghezza’)<br />

else<br />

xval=xval ( : ) ;<br />

yval=zeros ( length ( xval ) , 1 ) ; % s i crea un v e t t o r e <strong>di</strong> t u t t i zero<br />

n=length ( x ) −1; % n grado del polinomio<br />

for i =1:n+1<br />

yval = yval + lagrange ( xval , x , i ) * y ( i ) ;<br />

end<br />

end<br />

Eseguiamo l’esempio <strong>di</strong> prima per vedere cosa si ottiene:<br />

>> yy=interplagrange(xx,x,y);<br />

>> plot(x,y,’o’, xx,yy)<br />

Ora la function interplagrange sostituisce l’uso delle due function polyfit, polyval o<br />

interpmonom, polyval.<br />

Calcoliamo ora il polinomio <strong>di</strong> interpolazione me<strong>di</strong>ate le <strong>di</strong>fferenze <strong>di</strong>vise <strong>di</strong> Newton. Scriviamo due<br />

functions, la prima che scrive la tabella delle <strong>di</strong>fferenze <strong>di</strong>vise, la seconda che valuta il polinomio <strong>di</strong> interpolazione<br />

implementando l’algoritmo <strong>di</strong> Horner 2 in modo da minimizzare il numero delle operazioni da<br />

eseguire.<br />

function table= d i v d i f ( x , y )<br />

% function table=<strong>di</strong>v<strong>di</strong>f ( x , y )<br />

% x − a s c i s s e dei dati da interpolare<br />

% y − or<strong>di</strong>nate dei dati da interpolare<br />

% table − t a b e l l a d e l l e d i f f e r e n z e d i v i s e<br />

x=x ( : ) ;<br />

y=y ( : ) ;<br />

n=length ( x ) ;<br />

m=length ( x ) ;<br />

2 William Horner (1786-1837) fu un matematico inglese, ricordato essenzialmente per il suo metodo sulle equazioni algebriche.<br />

Spieghiamo l’algoritmo solo per rendere comprensibile la function che scriviamo.<br />

217


13. PRIMI PASSI IN MATLAB®<br />

i f n~=m<br />

error (’MATLAB:<strong>di</strong>fferenze_<strong>di</strong>vise’ ,’errore␣sui␣dati’)<br />

else<br />

table=zeros (n , n ) ; % iniziamo la t a b e l l a come una matrice <strong>di</strong> z e r i<br />

table ( : , 1 ) = y ;<br />

for j =2:n<br />

for k =2: j<br />

table ( j , k)= ( table ( j , k−1) − table ( j −1,k−1) ) / . . .<br />

( x ( j ) − x ( j−k+1) ) ;<br />

end<br />

end<br />

end<br />

La <strong>di</strong>agonale principale della matrice table ha i coefficienti a 0 , a 1 , ... a n del polinomio <strong>di</strong> interpolazione.<br />

Il polinomio è dunque:<br />

p(x) = a 0 + a 1 (x − x 0 ) + a 2 (x − x 0 )(x − x 1 ) + ... + a n (x − x 0 )(x − x 1 )···(x − x n−1 )<br />

Per valutarlo in un punto x eseguiamo i seguenti passaggi, applicando, in tal modo, l’algoritmo <strong>di</strong> Horner:<br />

p = a n<br />

p = p(x − x n−1 ) + a n−1<br />

= a n (x − x n−1 ) + a n−1<br />

p = p(x − x n−2 ) + a n−2<br />

.<br />

= a n (x − x n−1 )(x − x n−2 ) + a n−1 (x − x n−2 ) + a n−2<br />

p = p(x − x 0 ) + a 0<br />

= a n (x − x n−1 )(x − x n−2 )...(x − x 1 )(x − x 0 ) + ... + a 1 (x − x 1 )(x − x 0 ) + a 0<br />

= a 0 + a 1 (x − x 0 )(x − x 1 ) + ... + a n (x − x 0 )(x − x 1 )...(x − x n−2 )(x − x n−1 )<br />

La function da scrivere è dunque:<br />

function yval= i n t e r p d i v d i f ( xval , x , table )<br />

% function yval= i n t e r p d i v d i f ( xval , x , table )<br />

% x − a s c i s s e dei dati da interpolare<br />

% table − t a b e l l a d e l l e d i f f e r e n z e <strong>di</strong>vise ,<br />

% ottenuta dalla function d i v d i f ;<br />

% servono i v a l o r i della <strong>di</strong>agonale principale<br />

% xval − s c a l a r e o v e t t o r e in cui c a l c o l a r e i l polinomio<br />

% i n t e r p o l a t o r e<br />

% yval − valore ( o v a l o r i ) del polinomio i n t e r p o l a t o r e<br />

% valutato in xval<br />

% nel calcolo del polinomio i n t e r p o l a t o r e s i applica<br />

% l ’ algoritmo <strong>di</strong> Horner<br />

xval=xval ( : ) ;<br />

x=x ( : ) ;<br />

n=length ( x ) −1;<br />

yval=table (n+1 ,n+1)* ones ( length ( xval ) , 1 ) ;<br />

for j =n: −1:1<br />

yval=yval . * ( xval−x ( j ) ) + table ( j , j ) ;<br />

end<br />

Le functions appena descritte possono essere usate in maniera del tutto equivalenti per risolvere il problema<br />

dell’interpolazione. Ci sono però dei casi in cui i risultati ottenuti dalla polyfit e dalla interpmonom<br />

non sono corretti in quanto la matrice <strong>di</strong> Vandermonde ad esse legate è malcon<strong>di</strong>zionata.<br />

218


13.9. Applicazioni <strong>di</strong> MATLAB® nel <strong>Calcolo</strong> <strong>Numerico</strong><br />

Abbiamo già descritto gli effetti del malcon<strong>di</strong>zionamento nella Sezione 5.4.1 del Capitolo 5. Quando applichiamo<br />

la function polyfit ai dati <strong>di</strong> quel problema, si ha il seguente messaggio <strong>di</strong> avvertimento (un<br />

warning):<br />

>> poli=polyfit(x,y,5)<br />

Warning: Polynomial is badly con<strong>di</strong>tioned. Add points with <strong>di</strong>stinct X<br />

values, reduce the degree of the polynomial, or try<br />

centering<br />

and scaling as described in HELP POLYFIT.<br />

Questo ci <strong>di</strong>ce che i risultati che avremo non saranno buoni e, effettivamente, se facciamo il grafico dei dati<br />

del problema e del polinomio <strong>di</strong> interpolazione ottenuto con la polyfit, si nota subito che il polinomio è<br />

completamente errato (ve<strong>di</strong> Figura 13.8) Anche nell’applicare la function interpmonom si ha il messaggio <strong>di</strong><br />

Figura 13.6: Uso della function polyfit per l’esempio malcon<strong>di</strong>zionato.<br />

avvertimento<br />

>> pmon=interpmonom(x,y)<br />

Warning: Matrix is close to singular or badly scaled.<br />

Results may be inaccurate. RCOND = 5.537667e-31.<br />

Se aggiungiamo al grafico precendente la curva corrispondente al polinomio ottenuto con la interpmonom<br />

osserviamo come le due curve siano tra loro <strong>di</strong>stinte e non interpolano i dati.<br />

Figura 13.7: Uso della function interpmonom per l’esempio malcon<strong>di</strong>zionato.<br />

Proviamo invece ad applicare l’algoritmo <strong>di</strong> Lagrange o delle <strong>di</strong>fferenze <strong>di</strong>vise <strong>di</strong> Newton e aggiungiamo<br />

le nuove curve sul precedente grafico:<br />

219


13. PRIMI PASSI IN MATLAB®<br />

>> ylagr=interplagrange(xx,x,y);<br />

>> table=<strong>di</strong>v<strong>di</strong>f(x,y);<br />

>> ynewt=interp<strong>di</strong>v<strong>di</strong>f(xx,x,table);<br />

>> plot(xx,ylagr,xx,ynewt)<br />

Figura 13.8: Uso delle functions corrispondenti agli algoritmi <strong>di</strong> Lagrange e delle <strong>di</strong>fferenze <strong>di</strong>vise <strong>di</strong> Newton<br />

nell’esempio malcon<strong>di</strong>zionato. Osserviamo che la Figura 5.6 relativa allo stesso problema è stata ottenuta<br />

eseguendo le stesse functions (per semplicità abbiamo omesso i risultati ottenuti dalla interpmonom) in<br />

ambiente Octave.<br />

Si nota subito che le due curve sono tra loro coincidenti e interpolatorie!<br />

13.9.3 Confronto tra schemi per equazioni <strong>di</strong>fferenziali or<strong>di</strong>narie<br />

Nel Capitolo 10 abbiamo introdotto alcuni meto<strong>di</strong> per la risoluzione <strong>di</strong> equazioni <strong>di</strong>fferenziali or<strong>di</strong>narie,<br />

in particolare i meto<strong>di</strong> <strong>di</strong> Eulero esplicito, <strong>di</strong> Eulero implicito e <strong>di</strong> Crank-Nicolson.<br />

Li abbiamo anche confrontati per capire meglio il concetto <strong>di</strong> stabilità, considerando l’equazione test<br />

y ′ = −y con y(0) = 1 (si veda a proposito la Figura 10.2).<br />

Scriviamo ora un programma MATLAB® che, per questa equazione test,<br />

G ci permetta <strong>di</strong> poter confrontare i tre meto<strong>di</strong> tra loro e con la soluzione esatta<br />

G crei dei grafici simili a quelli <strong>di</strong> Figura 10.2<br />

G salvi i valori numerici dei <strong>di</strong>versi meto<strong>di</strong> e della soluzione esatta in un file<br />

clear<br />

% h = passo <strong>di</strong> d i s c r e t i z z a z i o n e temporale<br />

% Tfin = tempo f i n a l e <strong>di</strong> osservazione<br />

% n = numero <strong>di</strong> v o l t e in cui verra ’ applicato ciascuno dei meto<strong>di</strong><br />

% proposti<br />

% f i d = v a r i a b i l e associata al f i l e <strong>di</strong> r i s u l t a t i<br />

% t = v e t t o r e dei tempi<br />

% ye = v e t t o r e dei v a l o r i a s s o c i a t i al metodo <strong>di</strong> Eulero e s p l i c i t o<br />

% ( <strong>di</strong> lunghezza n+1 perche ’ la prima componente corrisponde<br />

% al valore della soluzione al tempo zero )<br />

% y i = v e t t o r e dei v a l o r i a s s o c i a t i al metodo <strong>di</strong> Eulero implicito<br />

% ycn = v e t t o r e dei v a l o r i a s s o c i a t i al metodo <strong>di</strong> Crank−Nicolson<br />

% yex = v e t t o r e dei v a l o r i a s s o c i a t i alla soluzione e s a t t a<br />

h=input (’passo␣h␣’ ) ;<br />

Tfin=input (’tempo␣finale␣<strong>di</strong>␣osservazione␣’ ) ;<br />

n=Tfin /h ;<br />

f i d =fopen (’ode_a_confronto.txt’ ,’w’ ) ;<br />

t ( 1 ) = 0 ;<br />

220


13.9. Applicazioni <strong>di</strong> MATLAB® nel <strong>Calcolo</strong> <strong>Numerico</strong><br />

y ( 1 ) = 1 ;<br />

ye (1)= y ( 1 ) ;<br />

y i (1)= y ( 1 ) ;<br />

ycn (1)= y ( 1 ) ;<br />

yex (1)= y ( 1 ) ;<br />

for i =1:n<br />

ye ( i +1)= ye ( i ) − h* ye ( i ) ;<br />

y i ( i +1)= y i ( i )/(1+h) ;<br />

ycn ( i +1)= (2−h)/(2+h) * ycn ( i ) ;<br />

t ( i +1)= t ( i )+h ;<br />

yex ( i +1)=exp(− t ( i + 1 ) ) ;<br />

end<br />

plot ( t , yex , ’k’ , ’linewidth’ ,2 )<br />

hold on %comando per s o v r a s c r i v e r e i g r a f i c i l ’ uno s u l l ’ a l t r o<br />

plot ( t , ye ,’b’ , ’linewidth’ , 2 )<br />

plot ( t , yi ,’r’ ,’linewidth’ , 2 )<br />

plot ( t , ycn , ’g’ ,’linewidth’ , 2 )<br />

legend (’soluzione␣esatta’ , ’Eulero␣esplicito’ , ’Eulero␣implicito’ , ’Crank-Nicolson’ , )<br />

% la legenda , lo spessore d e l l e linee , o i l colore possono e s s e r e<br />

% messi s i a <strong>di</strong>rettamente dalla f i n e s t r a della figura<br />

% s i a dal programma stessocome in questo caso ( solo in Octave s i<br />

% deve operare <strong>di</strong>rettamente dal programma per poter cambiare<br />

% l e proprieta ’ della figura ) .<br />

hold o f f<br />

for i =1:n+1<br />

f p r i n t f ( fid , ’\n%5.2f␣%12.6e␣%12.6e␣%12.6e␣%12.6e’ , t ( i ) , yex ( i ) , . . .<br />

ye ( i ) , y i ( i ) , ycn ( i ) ) ;<br />

end<br />

f c l o s e ( f i d ) ;<br />

221


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

14<br />

TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Io <strong>di</strong>co <strong>di</strong> aver capito un’equazione<br />

quando sono in grado <strong>di</strong> pre<strong>di</strong>re le<br />

proprietà delle sue soluzioni senza<br />

effettivamente risolverla.<br />

Paul Adrien Maurice Dirac<br />

14.1 Il foglio elettronico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223<br />

14.2 Inserire funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223<br />

14.3 Formule ricorsive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228<br />

14.4 Fare grafici nel foglio elettronico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231<br />

14.4.1 Grafici multicolonna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236<br />

14.5 Inserire dati da files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238<br />

14.1 Il foglio elettronico<br />

Il foglio elettronico può essere usato nell’ambito del <strong>Calcolo</strong> <strong>Numerico</strong> per implementare ed eseguire<br />

semplici algoritmi ricorsivi. Inoltre può essere utilizzato per importare dati e per fare grafici. Nel seguito,<br />

daremo alcune in<strong>di</strong>cazioni su come usare il foglio elettronico, in particolare la versione in lingua inglese <strong>di</strong><br />

OpenOffice 2.4 (in questa versione i numeri decimali vanno scritti facendo uso del punto . – ad esempio<br />

2.1023 – a <strong>di</strong>fferenza della versione in lingua italiana dove i numeri decimali, <strong>di</strong> default, vanno scritti facendo<br />

uso della virgola – ad esempio 2,1023. 1 Tenendo conto <strong>di</strong> questa <strong>di</strong>fferenza saremo in grado <strong>di</strong> usare<br />

correttamente il foglio elettronico.<br />

14.2 Inserire funzioni<br />

Un foglio elettronico si presenta come una tabella <strong>di</strong> cellette, ognuna delle quale viene in<strong>di</strong>viduata dal<br />

numero che contrad<strong>di</strong>stingue la corrispondente riga e dalla lettera che in<strong>di</strong>ca la corrispondente colonna. Ad<br />

esempio, la cella C7 si trova sulla colonna C e sulla riga 7.<br />

1 Lasciando la versione italiana <strong>di</strong> OpenOffice, si può scegliere <strong>di</strong> scrivere i numeri decimali usando il punto . anzichè la virgola ,<br />

andando, me<strong>di</strong>ante il Menu, su Strumenti −− > Opzioni −− > Impostazioni della Lingua −− > Lingue e scegliere come Lingua Locale<br />

(nella seconda riga a partire dall’alto) quella Italiana (Svizzera) o un’altra lingua che permette <strong>di</strong> ottenere come separatore delle cifre<br />

decimali il punto.<br />

223


14. TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Figura 14.1: Si vuole lavorare sulla cella C7. La lettera C e il numero 7 che in<strong>di</strong>viduano la colonna C e la<br />

riga 7 sono evidenziate rispetto alle altre colonne e righe. La cella C7 ha il bordo più scuro rispetto alle altre<br />

celle. Sono state cerchiate in rosso le due righe chiamate Name Box (Casella del Nome) e Input Line (Riga <strong>di</strong><br />

<strong>di</strong>gitazione).<br />

Quando, con il mouse, ci spostiamo su una cella e clicchiamo il tasto sinistro del mouse, allora il contorno<br />

della cella <strong>di</strong>venta <strong>di</strong> colore nero grassetto: vuol <strong>di</strong>re che possiamo ”lavorare” su quella cella (si veda la Figura14.1).<br />

Inoltre, sopra la tabella delle celle, sulla sinistra, viene visualizzato nella Name Box (nella Casella del<br />

Nome) il nome della cella su cui vogliamo lavorare.<br />

Se in una cella scriviamo un numero o applichiamo una formula numerica che avrà come risultato un<br />

numero, la cella può essere considerata come una variabile e sarà chiamata con la coppia lettera-numero che<br />

la in<strong>di</strong>vidua (per esempio la cella C7).<br />

Per scrivere un numero o applicare una formula numerica, una strada da seguire è la seguente:<br />

G Una volta che siamo sulla cella (per esempio la cella C7 evidenziata rispetto alle altre) scriviamo =<br />

e poi il numero che vogliamo scrivere, ad esempio 0.1 (oppure 0,1 se la versione <strong>di</strong> Office è quella<br />

italiana). Ve<strong>di</strong>amo che quello che scriviamo sulla cella compare anche nella riga <strong>di</strong> Input Line (o riga<br />

per immettere i coman<strong>di</strong>, Riga <strong>di</strong> <strong>di</strong>gitazione) che si trova sopra la tabella delle celle. Nel momento in<br />

cui scriviamo =, accanto a quella riga compare un simbolo a forma <strong>di</strong> x dal colore rosso (al posto del<br />

simbolo <strong>di</strong> sommatoria che c’era prima) e il simbolo <strong>di</strong> accettazione in verde (vedasi le immagini in<br />

Figura 14.2 e 14.3 e le si confronti con la Figura14.1).<br />

G Se invece <strong>di</strong> un numero vogliamo applicare una formula numerica, possiamo o scrivere <strong>di</strong>rettamente il<br />

valore della funzione (per esempio cos(0.1) + 0.3 ) oppure possiamo avvalerci dell’aiuto delle funzioni<br />

predefinite che possiamo utilizzare nel foglio elettronico. Dal menu del foglio elettronico, cliccando<br />

su Insert (Inserisci) troviamo le due voci Function. . . (Funzione) e Function list (Lista <strong>di</strong> funzioni). Di<br />

qui possiamo vedere quali sono le funzioni che possiamo utilizzare. Ricor<strong>di</strong>amo che nella versione<br />

italiana, la funzione valore assoluto si chiama ASS (ABS in quella inglese), la funzione seno si chiama<br />

SEN (SIN in quella inglese). Nel momento in cui iniziamo a <strong>di</strong>gitare il nome <strong>di</strong> una funzione, molto<br />

probabilmente ci verrà già data in<strong>di</strong>cazione sulla funzione che inizia in quel modo, se l’abbiamo già<br />

utilizzata precedentemente. Inoltre, nel Name Box, dove prima era in<strong>di</strong>viduata la cella su cui stavamo<br />

lavorando, vengono visualizzate le funzioni più recenti che abbiamo utilizzato (si vedano le Figure 14.4<br />

e 14.5).<br />

224


14.2. Inserire funzioni<br />

Figura 14.2: Scriviamo = nella cella C7 per inserire un numero o per valutare una funzione in un numero.<br />

Figura 14.3: Inseriamo il valore 0.1 nella cella C7.<br />

225


14. TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Figura 14.4:<br />

(Funzione).<br />

Inseriamo il valore cos(0.1) nella cella C7 partendo dal menu Insert (Inserisci) e Function<br />

226


14.2. Inserire funzioni<br />

Figura 14.5: Inseriamo il valore cos(0.1) nella cella C7. Nella figura in alto si vede l’ultimo passaggio <strong>di</strong> cosa<br />

accade dopo aver inserito la funzione da menu. Nella figura in basso si vede cosa succede quando si scrive<br />

<strong>di</strong>rettamente la formula.<br />

227


14. TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Figura 14.6: Inseriamo in C2 il valore cos(B2).<br />

14.3 Formule ricorsive<br />

Supponiamo ora <strong>di</strong> voler implementare l’algoritmo dello schema <strong>di</strong> punto fisso, applicato alla funzione<br />

g (x) = cos(x).<br />

Nella colonna A scriveremo le iterazioni k che facciamo nell’implementare lo schema. Per implementare<br />

la formula x k = g (x k−1 ) useremo le colonne B e C: in B metteremo i valori delle approssimazioni x k , in C<br />

scriveremo il valore g (x k ).<br />

Nella riga 1 delle colonne A, B e C, per ricordare ciò che stiamo facendo, scriviamo semplicemente k, xk e<br />

g(xk), rispettivamente.<br />

Al primo passo, nella cella A2 <strong>di</strong>amo il valore 0 per in<strong>di</strong>care l’iterazione k = 0, a B2 assegniamo il valore iniziale<br />

per x 0 , per esempio 0.0 e in C2 assegniamo il valore g (x 0 ), cioè cos(B2), che ci servirà al passo successivo.<br />

Osserviamo che abbiamo usato la cella B2 come una variabile avendo dato a C2 il valore cos(B2). Possiamo<br />

scrivere a mano cos(B2) oppure, inserendo la funzione cos() e cliccando con il mouse sulla variabile-cella<br />

in cui valutare la funzione (i cui contorni <strong>di</strong>venteranno <strong>di</strong> colore rosso), automaticamente viene inserito il<br />

nome della cella all’interno delle parentesi (in questo caso la cella B2). Dopo aver schiacciato il tasto <strong>di</strong> invio<br />

comparirà il valore numerico della funzione calcolata (si veda la Figura 14.6).<br />

Al passo successivo, il passo k deve essere uguale a 1: applichiamo alla cella A3 la formula A2+1 in modo<br />

da ottenere 1 (vedremo perchè conviene applicare questa semplice formula). La cella B3 ha come significato<br />

x 1 = g (x 0 )= cos(B2)=C2, il valore che si trova nella cella C2. Nella cella C3 andremo a valutare cos(B3), in<br />

modo da utilizzarlo nella cella B4 al passo successivo.<br />

Siamo ora in grado <strong>di</strong> scrivere queste formule in maniera ricorsiva effettuando una sola operazione <strong>di</strong><br />

copia-incolla o <strong>di</strong> trascinamento. . .<br />

Difatti, ora sulla riga 4 noi dobbiamo:<br />

G in A4, incrementare il valore dell’iterazione che viene effettuata (la cella A4 deve essere uguale ad A3<br />

+1);<br />

G in B4, aggiornare la variabile x k mettendo nella cella B4 il valore che si trova nella cella C3;<br />

G in C4, aggiornare la variabile g (x k ) calcolando cos(B4).<br />

228


14.3. Formule ricorsive<br />

Figura 14.7: Operazione <strong>di</strong> copia-incolla per applicare le formule ricorsive dalla riga 3 alla riga 4. Nella figura<br />

in alto, abbiamo ”annerito” le tre cellette della riga 3. Nella figura in basso, dopo aver fatto Copy delle tre<br />

cellette della riga 3, ”anneriamo” le tre cellette della riga 4 su cui incolleremo le formule ricorsive.<br />

229


14. TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Figura 14.8: Risultato dell’operazione <strong>di</strong> copia e incolla dalle cellette della riga 3 alle cellette della riga 4.<br />

Questa operazione andrà ripetuta fino a quando non ci accorgiamo <strong>di</strong> essere arrivati a convergenza - vedremo<br />

poi come.<br />

Per aggiornare la riga 4 basta semplicemente ”annerire” con il mouse le cellette A3-B3-C3 (dove ci sono<br />

delle formule che si riferiscono alla riga precedente), spostandoci con il mouse e cliccando contemporaneamente<br />

con il tasto sinistro del mouse stesso. Clicchiamo quin<strong>di</strong> con il tasto destro del mouse e si aprirà una<br />

finestra <strong>di</strong> coman<strong>di</strong>: in particolare, clicchiamo alla voce Copy (Copia) e poi con il mouse ”anneriamo” (con la<br />

stessa tecnica descritta prima) le tre cellette successive.<br />

Clicchiamo <strong>di</strong> nuovo il tasto destro del mouse e facciamo Paste (Incolla). Vedremo che le cellette ora sono<br />

aggiornate e con le stesse formule che avremmo scritto a mano celletta per celletta (in A4 troviamo la formula<br />

A3+1, in B4 troviamo C3, in C4 troviamo cos(B4) ). Si vedano le Figure 14.7 e 14.8. Se anzichè ”annerire” solo<br />

le cellette della riga successiva, ”annerrissimo” le cellette <strong>di</strong> molte più righe, l’algoritmo verrà applicato in<br />

successione (talmente rapida che ci sembra istantanea) per molti più passi (tanti quante sono le righe su cui<br />

abbiamo applicato la formula ricorsiva me<strong>di</strong>ante l’operazione <strong>di</strong> copia e incolla). Si veda la Figura 14.9.<br />

L’operazione <strong>di</strong> copia e incolla si può fare anche in un’altra maniera me<strong>di</strong>ante l’operazione <strong>di</strong> trascinamento<br />

del mouse. Una volta che abbiamo ”annerito” le cellette in cui si trovano le formule ricorsive da applicare<br />

sulle righe successive, osserviamo che l’angolo in basso a destra della cornice nera che si è venuta a<br />

creare ha un bor<strong>di</strong>no più spesso. Ci avviciniamo con il tasto sinistro del mouse su quel bor<strong>di</strong>no e poi trasciniamo<br />

il mouse verso il basso. Ve<strong>di</strong>amo che, via via che an<strong>di</strong>amo verso il basso, i bor<strong>di</strong> delle cellette su<br />

cui vogliamo applicare le formule ricorsive <strong>di</strong>ventano <strong>di</strong> colore rosso. Una volta che lasciamo il tasto sinistro<br />

del mouse, le formule vengono applicate e troviamo i valori numerici nelle cellette. Notiamo che nella<br />

versione 2.3 <strong>di</strong> OpenOffice, una volta che lasciamo il tasto sinistro del mouse, per completare l’operazione <strong>di</strong><br />

trascinamento dobbiamo cliccare su Formule nella finestra che automaticamente viene aperta. Dopo aver<br />

completato questa operazione, si conclude correttamente l’operazione <strong>di</strong> trascinamento. Osserviamo che ci<br />

sono al più due cifre decimali nella rappresentazione dei numeri. Per visualizzare meglio i numeri, conviene<br />

cambiare formato: ”anneriamo” le cellette delle colonne B e C, clicchiamo il tasto destro del mouse e, sulla<br />

finestra che si apre, an<strong>di</strong>amo su Format Cells (Formatta Celle). Si apre una nuova finestra da cui clicchiamo<br />

su Numbers (Numeri) e scegliamo la categoria del formato scientifico. Qui possiamo definire manualmente<br />

230


14.4. Fare grafici nel foglio elettronico<br />

Figura 14.9: Risultato dell’operazione <strong>di</strong> trascinamento (o <strong>di</strong> copia e incolla) su più righe.<br />

il numero <strong>di</strong> zeri che vogliamo nella mantissa (vedasi Figura 14.10). 2 Se vogliamo ora aggiungere delle iterazioni<br />

all’algoritmo, me<strong>di</strong>ante un’operazione <strong>di</strong> copia e incolla o <strong>di</strong> trascinamento, oltre alle formule anche il<br />

formato viene incollato/trascinato nelle celle successive. Per capire quando arrestare l’algoritmo, utilizziamo<br />

il test <strong>di</strong> arresto sugli scarti. Sulla colonna D andremo a scrivere il valore assoluto della <strong>di</strong>fferenza tra due<br />

approssimazioni successive e applicheremo tale formula in maniera ricorsiva. Faremo quin<strong>di</strong> ABS(B3-B2)<br />

e trascineremo questa formula nelle celle successive con il formato che ci sembrerà più opportuno (si veda<br />

la Figura 14.11). In base alla tolleranza prefissata, quando lo scarto <strong>di</strong>verrà minore della tolleranza, allora<br />

arresteremo l’algoritmo (e quin<strong>di</strong> ci fermeremo nell’operazione <strong>di</strong> copia e incolla o <strong>di</strong> trascinamento delle<br />

formule da una cella alla successiva).<br />

14.4 Fare grafici nel foglio elettronico<br />

Una volta terminata l’implementazione del metodo <strong>di</strong> punto fisso, possiamo pensare <strong>di</strong> fare un grafico<br />

semilogaritmico <strong>degli</strong> scarti in funzione delle iterazioni.<br />

Dobbiamo quin<strong>di</strong> vedere come fare nel foglio elettronico un grafico in cui sull’asse delle ascisse mettiamo<br />

i valori delle iterazioni e sull’asse delle or<strong>di</strong>nate inseriamo i valori assoluti <strong>degli</strong> scarti. Inoltre, dobbiamo<br />

rendere il grafico semilogaritmico per stu<strong>di</strong>are il profilo <strong>di</strong> convergenza del metodo.<br />

Incominciamo ”annerendo” solo la colonna che contiene le iterazioni dal valore 1 fino alla fine delle<br />

iterazioni che abbiamo effettuato: questa operazione viene fatta tenendo premuto il tasto sinistro del mouse.<br />

2 Osserviamo che il formato scelto può andare “stretto” nella cella/celle selezionate: in tal caso, al posto del numero saranno visualizzati<br />

i simboli ###. Per avere una corretta visualizzazione dei numeri, si dovrà allargare la colonna corrispondente in cui si trovano le<br />

celle per le quali non si vede il formato corretto. Cliccando con il tasto sinistro del mouse sulla cella che porta la lettera della colonna che<br />

desideriamo allargare, vedremo che tutte le celle della colonna selezionata si ”anneriscono”. Ci si sposta poi, con il mouse, verso il bordo<br />

destro della cella (per esempio ci troviamo sulla cella della colonna C al contorno con la cella della colonna D) e vedremo comparire una<br />

doppia freccia, grazie alla quale si potrà allargare tutta l’ampiezza della colonna verso destra. Allargheremo la colonna fino a quando<br />

tutte le celle saranno visualizzate correttamente nel loro formato.<br />

231


14. TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Figura 14.10: Finestra per mo<strong>di</strong>ficare il formato numerico dei risultati. Viene scelto un formato scientifico<br />

definito dall’utente.<br />

Figura 14.11: Schema del punto fisso, in cui è stata aggiunta, nella colonna D, il valore assoluto dello scarto<br />

tra due approssimazioni successive. Si noti che abbiamo scelto un formato numerico <strong>di</strong>verso per gli scarti<br />

rispetto a quello usato per xk e cos(xk).<br />

232


14.4. Fare grafici nel foglio elettronico<br />

Figura 14.12: Selezione delle colonne per fare il grafico.<br />

Dobbiamo poi passare alla colonna <strong>degli</strong> scarti, dal valore ottenuto all’iterazione 1 fino al valore ottenuto<br />

all’ultima iterazione. Per non perdere ”traccia” della colonna delle iterazioni, prima <strong>di</strong> iniziare a premere con<br />

il tasto sinistro del mouse sulla colonna <strong>degli</strong> scarti, dobbiamo schiacciare anche il tasto Ctrl della tastiera del<br />

computer. Solo dopo an<strong>di</strong>amo ad annerire la colonna <strong>degli</strong> scarti. In questo modo lasciamo ”nera” anche la<br />

colonna delle iterazioni (si veda la Figura 14.12).<br />

A questo punto, an<strong>di</strong>amo sul Menu principale del foglio elettronico alla voce Insert (Inserisci) e <strong>di</strong> qui su<br />

Chart (Diagramma).<br />

Si apre una finestra che ci permette la scelta del grafico. Noi sceglieremo il grafico XY (Scatter) (nella<br />

versione italiana XY (Dispersione) ) con solo linee - Lines Only (vedasi Figura 14.13). Procedendo (con Next<br />

- Avanti), si vede che l’intervallo dei punti su cui fare il grafico è stato già scelto e compare nella riga relativa<br />

al Data Range (Area dati). Per la serie dei dati, Data Series, si vede quali sono i valori delle ascisse (X-values)<br />

e quali le or<strong>di</strong>nate (Y-values). Si vede anche la scritta Column D che in<strong>di</strong>ca il fatto che abbiamo preso per le<br />

or<strong>di</strong>nate i valori presi dalla colonna D (vedremo che poi uscirà il nome Column D nella legenda della figura e<br />

vedremo come dare un nome più significativo) (si veda la Figura 14.14). Andando ancora avanti, nella Chart<br />

Elements (Elementi del <strong>di</strong>agramma), si può decidere cosa scrivere come titolo, sottotitolo, etichette sugli assi<br />

x e y. Nella Figura 14.15 abbiamo dato titolo, sottotitolo. . . A questo punto si clicca su Finish (Fine) e sul foglio<br />

elettronico compare il nostro grafico (che non è ancora semilogaritmico), mostrato nella Figura 14.16.<br />

Per fare mo<strong>di</strong>fiche al grafico, bisogna cliccare una volta con il tasto sinistro del mouse posizionato sul<br />

grafico, in modo da vedere in alto a sinistra un’icona con il simbolo dell’àncora. Ci si posiziona con il mouse<br />

all’interno del grafico e si clicca una volta con il tasto destro. Compare una finestra e qui si clicca la voce E<strong>di</strong>t<br />

(E<strong>di</strong>ta). Ora è possibile cambiare il tipo <strong>di</strong> assi o le linee del grafico, i colori, la legenda. . . .<br />

Ad esempio, andando con il mouse sull’asse delle Y e cliccando due volte con il tasto sinistro del mouse,<br />

si apre una finestra da cui poter cambiare le linee, i colori, i caratteri, ma soprattutto la scala del grafico.<br />

Da Scale (Scala) è infatti possibile scegliere la scala logaritmica come si vede nella Figura 14.17. Una<br />

volta cliccato su OK, si torna al grafico che non è più quello <strong>di</strong> prima ma è in scala semilogaritmica (si veda<br />

233


14. TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Figura 14.13: Finestra per la scelta del grafico<br />

Figura 14.14: Finestra del Data Series<br />

Figura 14.15: Titolo, sottotitolo, etichette.<br />

234


14.4. Fare grafici nel foglio elettronico<br />

Figura 14.16: Grafico<br />

Figura 14.17: Scelta della scala<br />

la Figura 14.18). Possiamo fare altre mo<strong>di</strong>fiche (per esempio cliccando sulla curva del grafico (Data Series<br />

Column D), possiamo cambiare lo spessore della curva). Inoltre, possiamo cambiare i caratteri usati per il<br />

titolo, i colori dello sfondo. E così via.<br />

Quello che ci interessa ora è come cambiare la legenda.<br />

Clicchiamo due volte con il tasto sinistro del mouse sul grafico. Poi clicchiamo con il tasto destro: si apre<br />

una finestra con varie opzioni <strong>di</strong> scelta tra cui Data Ranges. Clicchiamo su Data Ranges e si aprirà una finestra,<br />

quella che ve<strong>di</strong>amo nella Figura 14.19. Per cambiare la scritta Column D, dobbiamo inserire nella casella<br />

Range for Name (Area per Nome) il nome <strong>di</strong> una cella del foglio elettronico in cui abbiamo scritto un nome <strong>di</strong><br />

legenda che riteniamo più appropriato (per esempio, nella cella E1 abbiamo scritto punto fisso). Cliccando<br />

sull’icona che si trova a destra della finestra del Range for Name, possiamo poi <strong>di</strong>rettamente cliccare sulla<br />

cella E1 in modo da inserire automaticamente il nome della cella sulla casella Range for Name (il risultato <strong>di</strong><br />

questa operazione è mostrata nella Figura 14.20. Ve<strong>di</strong>amo che non compare più il nome Column D ma punto<br />

fisso sia su questa finestra sia, dopo aver dato l’OK, sul grafico (vedasi la Figura 14.21).<br />

235


14. TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Figura 14.18: Grafico semilogaritmico<br />

Figura 14.19: Finestra del Data Ranges<br />

14.4.1 Grafici multicolonna<br />

Osserviamo che la procedura eseguita per fare il grafico semilogaritmico appena descritto può essere ripetuta<br />

in maniera analoga per fare grafici multicolonna (per esempio, sull’asse delle x riportiamo le iterate,<br />

mentre sull’asse delle or<strong>di</strong>nate riportiamo i valori assoluti <strong>degli</strong> scarti relativi ai meto<strong>di</strong> <strong>di</strong> Newton-Raphson,<br />

Regula Falsi, tangente fissa, secante fissa. . . ): una volta che abbiamo inserito i dati relativi alle ascisse e alle<br />

or<strong>di</strong>nate della prima serie <strong>di</strong> dati (per esempio quelli del metodo <strong>di</strong> Newton-Raphson), e mentre stiamo ancora<br />

lavorando sulla finestra che ci permette <strong>di</strong> costruire il grafico, dopo la scelta del tipo <strong>di</strong> grafico (Chart Type)<br />

e Data Range, al passo del Data Series possiamo aggiungere (Add) altre serie <strong>di</strong> dati (per esempio iterazioni e<br />

scarti del metodo della Regula Falsi) per fare un grafico multicolonna. Si vedano le Figure 14.22 e 14.23.<br />

236


14.4. Fare grafici nel foglio elettronico<br />

Figura 14.20: Finestra del Data Ranges dopo aver operato la mo<strong>di</strong>fica<br />

Figura 14.21: Grafico finale semilogaritmico<br />

237


14. TABELLE E GRAFICI CON IL FOGLIO ELETTRONICO<br />

Figura 14.22: Dopo aver schiacciato sul tasto Add (Aggiungi), per aggiungere altri dati nel grafico, bisogna<br />

selezionare i nuovi dati.<br />

Figura 14.23: Dopo aver selezionato le cellette opportune dei valori delle ascisse da aggiungere al grafico, i<br />

valori vengono visualizzati sulla finestra. Analogamente si procede per l’asse y.<br />

14.5 Inserire dati da files<br />

Spesso il foglio elettronico viene utilizzato per fare grafici importando dati numerici da files esterni –<br />

per esempio files <strong>di</strong> tipo testo generati dall’esecuzione <strong>di</strong> programmi scritti in FORTRAN o altri linguaggi <strong>di</strong><br />

programmazione.<br />

Per inserire correttamente i dati su più colonne, si può seguire questo percorso: dal Menu principale del<br />

foglio elettronico si va su Insert (Inserisci) −− > Sheet from file (Foglio da file). A questo punto si apre una<br />

finestra da cui è possibile selezionare il percorso in cui si trova il file da aprire. Una volta che importiamo<br />

il file, si apre un’altra finestra (la finestra <strong>di</strong> Text import (importa testo)) in cui dobbiamo selezionare alcuni<br />

parametri che ci permetteranno <strong>di</strong> importare i dati inserendoli su più colonne (se i dati sono scritti su più<br />

colonne, che è la cosa che ci importa per poter fare i successivi grafici).<br />

Le opzioni che dobbiamo selezionare sono, oltre a Tab, che già troviamo in<strong>di</strong>cato, anche Merge delimiters<br />

e Space (si veda la Figura 14.24). Una volta dato l’OK, si apre un’altra finestra (Insert Test) in cui <strong>di</strong>gitiamo <strong>di</strong><br />

nuovo OK. Troviamo i dati del file messi in colonna come erano nel file <strong>di</strong> partenza. Il formato numerico non è<br />

molto carino (solo due cifre decimali, anche se andando a vedere celletta per celletta possiamo osservare che<br />

i valori sono memorizzati così come erano nel file originario), ma selezionando le celle possiamo cambiare<br />

238


14.5. Inserire dati da files<br />

Figura 14.24: Importare dati da un file esterno.<br />

il formato in modo da visualizzarlo correttamente. A questo punto, abbiamo i nostri dati in tabella sul foglio<br />

elettronico e possiamo fare i grafici o altre operazioni tramite il foglio elettronico.<br />

239


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 2011), 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 2011), The MacTutor History of Mathematics<br />

archive, University of St Andrews Scotland, http://www-gap-system.org/~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 2011), The Babbage Engine, Computer History Museum, Mountain<br />

View, CA, http://www.computerhistory.org/babbage.<br />

241

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!