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