Esaminiamo cinque situazioni
che inducono i programmatori a compiere errori loro malgrado.
1) Una prima possibilità
di errore interviene quando
si hanno valori dello stesso ordine di grandezza, cioè tutti molto piccoli
oppure molto grandi, i quali subiscono
somme e sottrazioni successive. In questi casi
può succedere che le cifre più significative si elmininino a vicenda mentre
il risultato si restringe sulle cifre di destra.
Per chiarire il meccanismo prendiamo la seguente espressione algebrica:
E = (A + B + C) * D
e supponiamo che i numeri siano:
CASO I°
A = + 324,18962
B = + 534,71093
C = – 858,90056
Il termine (A + B + C) è –0,00001.
Assumiamo che D sia pari a 955.417.300.231 ed il valore finale è:
E = –9554173,00231
L'esempio mostra che successive somme e sottrazioni fanno sì che il
risultato dipenda in maniera esclusiva dall'ultimo decimale. Le cifre di
destra assumono una importanza fondamentale ed un arrotondamento produce un
risultato del tutto inattendibile. Infatti supponiamo che i valori esatti
abbiano sei cifre decimali e non cinque come nel caso precedente cioè siano:
CASO 2°
A = + 324,189625
B = + 534,710937
C = –
858,900561
Si ottiene il risultato parziale +0,000002
ed il risultato finale è:
E = +19108346,00462
E' evidente che il valore di E ricavato nel
primo calcolo seppure ottenuto con ben cinque cifre decimali è
completamente sbagliato. In pratica è fondamentale che il
programmatore eviti somme e sottrazioni alternate, e,
se non può evitarle, ne consideri adeguatamente le
conseguenze.
2)
Un'altro tipo di errore algoritmico interviene a causa
dei decimali illimitati.
Qualsiasi
numero ha una precisione che si può ampliare ma che comunque ha un limite
fisico a causa del fatto che è contenuto in un campo di memoria il quale è
finito. Il numero decimale
periodico o aperiodico non produce un risultato esatto. Ad esempio in qualsiasi
macchina si provi a calcolare:
(1/3) * 3
non si avrà mai l'unità come dovrebbe essere:
(1/3) * 3
=1
bensì il valore:
(1/3) * 3 = 0,999999
Semplicemente perché la macchina calcola 1/3
pari a 0,333333 e
poi compie la moltiplicazione.
3)
Un punto critico nasce dai troncamenti dei decimali che producono arrotondamenti
accettabili se il calcolo è limitato, cioè compie un solo passo. Quando invece il calcolo è esteso,
cioè compie più passi, questi comportano
successive ripercussioni le quali
producono risultati talora del tutto errati. Oltre al caso delle somme e
sottrazioni successive sopra visto facciamo il caso delle divisioni. Prendiamo come esempio
i due algoritmi:
(A/D + B/D + C/D)
(A + B + C) / D
i quali da un punto di vista matematico sono identici, mentre
per la programmazione il secondo è senza dubbio il migliore.
Le tre divisioni producono approssimazioni che sommate alterano il
risultato più di quanto possa fare l'unico arrotondamento del secondo
algoritmo.
4)
In talune situazioni l'imprecisione sembrerebbe dettata dalle
condizioni stesse di calcolo come a proposito della
serie armonica:
S(N) = 1 + 1/2 + 1/3 + .. + 1/N
L'algoritmo che segue pedissequamente la formula perde i valori più
piccoli:
INIZIO - SERIE ARMONICA 1° ALGORITMO
Leggi N
Serie = 0
K = K + 1
RIPETI FINCHE' K = N
Elemento = 1/K
Serie = Serie + Elemento
K = K + 1
FINE-RIPETI
...
FINE
Il seguente algoritmo invece comincia la somma dai valori più piccoli e risulta più
accurato:
INIZIO - SERIE ARMONICA 2° ALGORITMO
Leggi N
Serie = 0
K = N
RIPETI FINCHE' K <= 1
Elemento = 1/K
Serie = Serie + Elemento
K = K – 1
FINE-RIPETI
...
FINE
Per avere una misura del fenomeno, diamo il risultato S
ottenuto con diversi valori di N. L'ultima colonna riporta le differenze dei
risultati tra i due algoritmi
N |
S (Algoritmo 1°) |
S (Algoritmo 2°) |
Differenza |
100 |
5,1873775174 |
5,1873775176 |
0,0000000002 |
200
|
5,8780309475 |
5,8780309480 |
0,0000000005 |
300 |
6,2826638794 |
6,2826638802 |
0,0000000008 |
400 |
6,5699296899 |
6,5699296910 |
0,0000000011 |
L'ultima colonna mostra che le differenze non sono
grandi in valore assoluto, tuttavia presentano una incidenza
non trascurabile e soprattutto non
lineare. L'approssimazione cresce via via che l'algoritmo
gestisce cifre più piccole, infatti proprio questo è il limite
della iterazione nel primo algoritmo che volevo mostrare.
5)
Succede che un programma venga sviluppato anche se non
si possiedono tutti i parametri per la sua stesura
perché taluni mancano, oppure perché ci sono ma
provengono da statistiche affette da fluttuazioni.
Si pone allora il problema di giudicare la bontà dell'algoritmo,
nel senso di valutare come una piccola variazione rispetto a quello
che in teoria è del tutto preciso, pregiudichi o meno
l'attendibilità del programma. Per lo scopo si esamina la risposta r che muta
al variare d dei parametri dell'algoritmo. Il
rapporto:
c = r/ d
chiamato numero di condizionamento esprime l'instabilità
dell'algoritmo. Come esempio consideriamo il seguente sistema di equazioni lineari: