Originariamente pubblicato in data 06/08/1999
A
C
C
O
M
A
Z
Z
I
Quattro conti con SANE
Quattro conti con SANE
I calcoli in virgola mobile (e cioè i calcoli con la virgola) nascondono molti più insidie di quanto si possa immaginare, quando è un computer a occuparsene. Quando il sistema operativo è Mac OS, però...
Il compito più semplice per un calcolatore dovrebbe essere, se il nome del nostro amico elettronico facesse fede, la risoluzione di complessi calcoli matematici. Sorprendentemente, non tutti i calcolatori sono calcolatrici accettabili: ma i computer Apple sono a prova di bomba. Vediamo perché.
Utilizzare un calcolatore come una costosissima calcolatrice è sempre possibile, ma spesso sconsigliabile. Le idiosincrasie del calcolatore, che stiamo per esaminare in dettaglio, producono risultati alquanto curiosi quando meno ce lo aspettiamo.Prendete ad esempio il programma del listato qui sotto. Lho appena compilato ed eseguito sia con un calcolatore Ms Dos usando il nuovissimo e meraviglioso (per gli standard vigenti nello sceiccato dellEmesdosistan, beninteso) Turbo Pascal 5.5 della Borland, sia su Macintosh con il vecchio, anzi obsoleto, Turbo Pascal Mac 1.1. Nel primo caso ho ottenuto un risultato (errato) di 1,0000000015, mentre nel secondo caso il Mac mi ha restituito un impeccabile risultato di uno.
Listato 1. Apparentemente, sommando diecimila volte un decimillesimo dovremmo ottenere una unità: ma non tutti i computer acconsentono graziosamente.
Program Diecimila;
var
r: real;
i: integer;
begin
r := 0;
for i := 1 to 10000 do
r := r + 0.0001;
WriteLn (r);
ReadLn
end.
Purtroppo per noi, tra le meravigliose astrazioni della matematica ed il modo il cui i calcolatori elettronici implementano questi concetti corre una considerevole distanza. Concettualmente, il problema è semplice: mentre i numeri matematici sono infiniti, perché esistono infiniti numeri reali come il pi greco, i numeri rappresentabili su un calcolatore sono un insieme finito, perché il calcolatore è una macchina finita che dispone di una quantità finita di memoria. Pertanto dovremo spesso accontentarci di una approssimazione in luogo di un risultato matematico esatto.
Nella pratica, quello che succede nel caso del listato uno, è tanto banale quanto indisponente. Ogni calcolatore memorizza internamente i numeri in codifica binaria, cioé utilizzando solo le cifre zero ed uno; questo dipende dal fatto che internamente al calcolatore esistono dei circuiti elettrici che fanno passare la corrente o non la fanno passare, e questo viene associato alle cifre zero ed uno... Roba vecchia, mi interromperanno i miei lettori, aria fritta e rifritta.
Già, ma le conseguenze non sono affatto banali. Noi siamo soliti lavorare con numeri decimali. I numeri decimali sono numeri che utilizzano la base dieci, cioé numeri scritti con dieci cifre differenti. Tra le varie conseguenze di questa convenzione abbiamo il fatto che ci è sempre possibile rappresentare esattamente in notazione decimale (cioé usando la virgola decimale) ogni frazione ottenuta dividendo un numero per due, per cinque, e per i multipli di questi numeri. I due numeri che condividono questa simpatica caratteristica, il due ed il cinque, godono della proprietà poiché sono i divisori della base dieci (cinque per due fa dieci). Per esempio, queste divisioni sono esatte:
1: 5 = 0,2
1 : 2 = 0,5
1:10 = 0,1
1 :625 = 0.0016
Però una divisione che abbia come divisore un numero diverso da 2, 5, e i multipli di questi può darci dei problemi, e produrre quei famigerati numeri periodici che abbiamo incontrato tanto tempo fa alle scuole medie. Per esempio:
1:3 = 0,33333...
1:7 = 0.14285...
Ora, poiché il calcolatore utilizza internamente la base due, cioè i numeri binari, esso può rappresentare esattamente in virgola mobile solo quelle frazioni che hanno al denominatore il due e le sue potenze; cioè i numeri come un mezzo o un quarto, ma non un decimo. Se noi scriviamo il valore di 1/10 in binario otteniamo un numero periodico: e anche quando il calcolatore, come avviene nel programma del listato 1, somma per diecimila volte quella che abbiamo scoperto essere una approssimazione del valore di un decimillesimo ottiene una approssimazione del risultato corretto.
Se a questo punto state cominciando a guardare preoccupati il vostro personal, pensando a quante volte vi siete fidati ciecamente dei suoi risultati matematici, tirate pure un sospiro di sollievo: il pericolo di incappare in gravi errori, se il calcolatore è un Apple, è risibile. Il tutto grazie a Sane, il protagonista di questa puntata.
Il nome Sane è una sigla. Anzi, dovremmo dire un acronimo. Sane significa Standard Apple Numerics Environment, e cioè ambiente standardizzato da Apple per i computi numerici. Si tratta di una raccolta di sofisticati sottoprogrammi matematici creati dai maghi di casa Apple per rendere assai limitati i guai conseguenti dalle limitazioni dei calcolatori elettronici. Sane è basato su uno standard internazionale oggi molto diffuso, lo standard IEEE 754.
Glossarietto
La sigla IEEE, che si pronuncia in inglese i triple e, indica lassociazione degli ingegneri elettronici.
Lo standard IEEE 754 è anche alla base dei processori matematici Intel 8087, 80287 e 80387 e dei processori matematici Motorola 68881 e 68882; tuttavia limplementazione Apple è di gran lunga più fedele, più precisa e più affidabile di quella Intel e persino di quella Motorola.
Un coprocessore matematico è un processore, e cioè un componente elettronico di grande complessità creato per eseguire in fretta e bene calcoli matematici anche complessi. I coprocessori Intel sono talvolta usati nei Pc Ibm e compatibili, dove sono disponibili come optional. I coprocessori Motorola sono montati di serie su tutti i Macintosh II.
Il Turbo Pascal 5.5 per MsDos implementa una parte dello standard IEEE 754, e la attiva su esplicita richiesta dellutente: se questo viene fatto, il programma del listato 1 restituisce un risultato corretto.
Apple ha creato Sane in quattro versioni, di modo che esso sia disponibile per ogni calcolatore Apple. La versione in uso sui calcolatori dotati di coprocessore matematico (tutti quelli degli anni novanta) fa uso dei coprocessori matematici Motorola, ma rielabora i risultati ottenuti tramite essi per migliorare la precisione dei risultati. Sane è contenuto nelle memorie permanenti Rom di questi calcolatori, e pertanto tutte le applicazioni che girano su questi calcolatori ne fanno uso. È per questo motivo che il programma del listato 1 non dà errori su Macintosh.
Vediamo in cifre quali sono le caratteristiche di Sane. Sane fornisce ai programmatori tre alternative per i numeri in virgola mobile, chiamate single, double ed extended (in italiano si tradurrebbero con precisione singola, doppia ed estesa). Internamente, Sane usa sempre il tipo extended, e si suggerisce che i programmatori facciano lo stesso: i formati single e double sono forniti per i casi in cui sia necessario risparmiare memoria e non sia richiesta una grande precisione nei calcoli matematici.
Sane fornisce anche il tipo comp, per numeri interi.
Tabella 1. Caratteristiche dei tipi di dato definiti in Sane.
Single Double Extended Comp
Occupazione di memoria (byte) 4 8 10 8
Precisione in cifre binarie 24 53 64 63
Precisione in cifre decimali (circa) 7/8 15/16 19/20 18/19
Massimo numero positivo 3,4x1038 1,7x10308 1,1x104932 9,2x1018
Minimo numero positivo 1,5x10-45 5x10-324 1,9x10-4951 1
Trattamento dellinfinito Si Si Si No
Trattamento dei non-numeri Si Si Si Si
Sane si profila, dunque, già a prima vista come un sistema capace di una grande precisione nella memorizzazione delle cifre. Il tipo extended può essere utilizzato per numeri sia grandissimi che piccolissimi (ad esempio, se volessimo esprimere la velocità della luce in Angstrom percorsi ogni anno-luce il tipo extended sarebbe assai abbondantemente in grado di memorizzare il risultato). Il tipo comp, dal canto suo, può essere usato per esprimere il debito pubblico dell'Italia espresso in pesos argentini.
Ma le capacità del modulo matematico di casa Apple non si fermano qui. La questione matematica non deve nè può essere ridotta ad un aumento della precisione: questa soluzione è semplicistica, perché non tiene in considerazione il semplice fatto che gli errori si propagano: un errore commesso nellultima cifra decimale di un numero diviene molto più significativo se il numero viene, per qualche motivo, moltiplicato per una quantità molto grande.
Un problema tipico del calcolo numerico, la disciplina dellinformatica che si occupa di queste questioni, è che spesso per un calcolatore possono esistere due numeri, x ed y, tali che:
x <> y
x - y = 0
Ciò accade quando i due numeri differiscono solo per qualche decimale, come potrebberlo essere i numeri 1,023456789 e 1,023456788. Quando si esegue la sottrazione tutte le cifre più significative si cancellano, e restano solo le cifre meno significative, che come abbiamo detto possono essere errate, e spesso il calcolatore giunge ad equiparare questo numero piccolissimo allo zero. Perché dovrebbe farlo? Il sottoprogramma che esegue la sottrazione viene spesso confezionato in modo da azzerare le quantità molto piccole per evitare il problema opposto, e cioè un risultato di zero che viene valutato (di poco) diverso da zero. Visto che per i programmi il test di equaglianza allo zero è spesso vitale, si preferisce commettere il primo errore al secondo.
Sane evita questo tipo di errori. Sane comprende una libreria completa di funzioni matematiche, algebriche, trigonometriche e finanziarie: tutte queste funzioni sono state accuratamente disegnate in modo da computare il risultato con precisione totale, sino allultima cifra binaria decimale. La conversione da dedimale a binario e viceversa, che dava tanti problemi nel nostro programma esemplificativo del listato 1, avviene in modo accurato.
I suoi arrotondamenti sono accurati ed astuti: avvengono in modo tale da minimizzare gli errori da arrotondamento. Per i casi particolari, il programmatore che fa uso di Sane può anche specificare in che direzione va eseguito larrotondamento. Un semplice esempio: nella aritmetica astratta, per ogni numero x ed y, avremo sempre che (x : y) x y = x. Sui calcolatori questo tipicamente non è vero, perchè larrotondamento provoca una approssimazione che inficia il risultato finale. Con Sane, la relazione matematica è sempre rispettata quando x ed y sono numeri interi, ed è quasi sempre rispettata persino quando utilizziamo la limitata rappresentazione single; un mio personale esperimento eseguito su Un Altro Calcolatore ha trovato quella macchina in errore in più di un quarto dei casi.
Sane esegue un underflow graduale. Per underflow intendiamo la sostituzione di un numero molto piccolo con lo zero, una attitudine dei calcolatori che, come abbiamo stigmatizzato poco sopra, provoca conseguenze alquanto spiacevoli. A causa del modo in cui i calcolatori memorizzano i numeri reali, attorno allo zero si trova tipicamente un intorno relativamente grande in cui non ci sono numeri rappresentabili. Sane utilizza il formato denormalizzato dei numeri reali, che permette di avere svariati valori rappresentabili dentro il buco.
Non è un numero!
Sane, inoltre, permette di utilizzare valori numerici che per la matematica sono assai significativi, ma nel calcolo eseguito da calcolatore tradizionalmente sono impossibili da ottenere: si tratta dellinfinito sia positivo che negativo, e di due differenti zeri, lo 0+ e lo 0-. La distinzione tra lo zero provenendo dai numeri negativi e provenendo da quelli positivi diviene fondamentale quando si lavora con funzioni matematiche che sono discontinue.
Quando si richiede a Sane di calcolare il risultato di una operazione con valori particolari (come ad esempio una somma tra linfinito positivo e linfinito negativo, oppure la divisione di zero su zero) Sane restituisce un valore particolare, chiamato un NaN. NaN significa Not A Number, e cioè Non Un Numero.Esistono molti differenti NaN, indicati nella tabella 2.
Lidea importante qui è che i NaN si propagano: se il computer utilizza Sane per risolvere lequazione (x + y) / z, e la somma di x ed y non può venire calcolata per il motivo succitato, Sane permette di tentare la divisione del NaN ottenuto per il numero z, e restituisce come risultato lo stesso NaN. Questo permette al programmatore di controllare il risultato solo al termine di una complessa serie di calcoli, senza doversi continuamente interrompere per verificare se si sia prodotto qualche spiacevole errore. Opzionalmente, il programmatore può richiedere che i NaN provochino linterruzione del programma, ed invochino una procedura di gestione delllerrore da lui creata. In questi caso i NaN vengono chiamati NaN segnalanti.
I codici NaN che abbiamo elencati nella tabella 2 normalmente non vengono visualizzati sullo schermo: anche se sono prodotti da Sane, la applicazione, se è ben fatta, li filtra e presenta allutente messaggi derrore più significativi. Excel, ad esempio, si comporta così. Tuttavia, la tabella potrebbe risultare utile a chi si trovi di fronte ad un programma che segue anche calcoli tramite Sane, ma non si preoccupi della interfaccia utente. Evento spiacevole, e che non ci è stato dato di rilevare mai, data lalta sofisticazione raggiunta dalle applicazioni sviluppate per i computer Apple, ma che tuttavia potrebbe verificarsi. La tabella sarà utile anche ai programmatori, sia quelli alle prime armi che utilizzino qualche linguaggio che non da completa visibilità della macchina e del suo toolbox (e quindi anche di Sane), sia a maggior ragione a quanti chiamano direttamente il toolbox, come accade ai nostri lettori che seguano un corso di programmazione Macintosh.
Tabella 2: i non-numeri definiti in Sane
Codice Sigla Uso
1 NaNSqrt Radice quadrata non esistente nel campo reale.
Ad esempio, -1
2 NaNAdd Somma matematicamente non definita
Ad esempio, + -
4 NaNDiv Divisione matematicamente indefinita.
Ad esempio 0/0
8 NaNMul Moltiplicazione matematicamente indefinita.
Ad esempio, 0 x
9 NaNRem Modulo matematicamente indefinito.
Ad esempio, 65 mod 0
17 NaNAscBin Conversione di una stringa in numero impossibile.
Ad esempio, interpretare ciao come numero.
20 NaNComp Risultato della conversione del NaN comp al
formato extended.
21 NaNZero È fallito il tentativo di creare un NaN usando Sane
33 NaNTrig Argomento invalido di funzione trigonometrica.
Ad esempio, cos ().
34 NaNInvTrig Argomento invalido a funzione trigonometrica
inversa
36 NaNLog Logaritmo inesistente. Ad esempio log (-20)
37 NaNPower Argomenti inaccettabili alla funzione di elevamento
a potenza. Ad esempio -3-3.4 oppure 1 elevato ad
38 NaNFinan Argomenti inaccettabili alle funzioni finanziarie.
Ad esempio linteresse composto per (-5) anni.