Cerca

modulo attività

modulo tecnica

Il computer non è in grado di trattare i numeri reali ma solo una loro approssimazione.

Lo fa ognuno di noi quando deve usare il "pi.greco": mica pensiamo di usare tutte le cifre decimali? 

Il numero delle cifre decimali di "pi.greco" è infinito e questo significa che se lo si vuole usare completo non si ha abbastanza carta né abbastanza tempo per eseguire i calcoli per cui lo approssimiamo alla lunghezza che ci fa comodo.

Il computer deve, perlomeno, fare lo stesso visto che ha una memoria di dimensioni limitate da assegnare a ciascun numero.

In aggiunta il computer fa altre approssimazioni in quanto al suo interno usa numeri in base 2 e non in base dieci.

La formalizzazione di tutti problemi connessi con la rappresentazione di numeri in un computer è fissata nello standard "IEEE 754".

numMacch2L'applicazione di Scratch "numeri macchina" è stata creata per sondare questi limiti senza pretesa di approfondirli.

Alla sua apertura con "bandierina verde" sono disponibili numerosi tasti per creare rapidamente numeri molto grandi o molto piccoli a partire dal numero "1".

L'atteggiamento più produttivo è provare con numeri diversi e osservare cosa accade.

Già moltiplicando per 1e-30, cioè dividendo per 1030, si vede che il numero "1" è diventato 9,999999999999999e-31: c'è una sua approssimazione! (nota 1)

Se, invece, si divide per 10 un po' di volte, si vede che già alla sesta volta sono state aggiunte altre cifre sigificative il numero non è più identico all'originale, cioé risulta corrotto.

La corruzione del numero sembra minima ma se si fa il test con l'istruzione "se (x=1), allora... altrimenti..." si vede che il risultato e "falso".numMacch1

Premere [tasto 1] per verificare.

In questo test il numero 1 viene diviso 8 volte per 10 e poi moltiplicato altrettante volte per 10: dovremmo avere lo stesso numero ed infatti sul visore si vede ancora il numero "1" ma le cose non stanno propriamente in questo modo: per un computer può accadere che  il valore di "x=1" non sia uguale a "1".

... in che senso?

Il computer confronta un numero esatto, intero, il numero "1", con il valore di "x" contenuto in una memoria del computer.

Se questo valore è stato oggetto di operazioni numeriche successive il risultato dopo ciascun calcolo viene approssimato alla cifra binaria più vicina che il computer è in grado di assegnargli.

Il risultato è che qualche cifra decimale trascurabilissima sia leggermente diversa da quanto ci si aspetterebbe da un computer "serio".

Il computer è serissimo solo che non può fare più di quanto i suoi limiti possano permettergli di fare.

Il computer è stato costruito per manipolare numeri binari di lunghezza limitata che necessitano di approssimazioni per la sua memorizzazione.

 

Prove

con [tasto N]

- inserire una stringa "abc", moltiplicare per "1" e si vede che il valore è"0";

- inserire "0.0000005" (ATTENZIONE! usare il punto decimale e non la virgola) e si vede l'intera cifra (nota 2); se si moltiplica per 1 si vede "0" solo perché il visore non mostra più di 6 cifre decimali. Se si moltiplica per mille si rivede il valore corretto della cifra inserita, ma, guarda caso, solo in modo approssimato "4,999999999999999e-10". (nota 1)

- con un qualunque valore andare a vedere cosa accade quando l'esponente approssima 308 o -308 così si rileva che si vanno perdendo cifre significative fino a smarrire del tutto ogni parentela col numero iniziale. Il computer è andato in overflow o in underflow

- se si parte dal numero "1" e lo si divide per 10 molte volte si vede che solo a partire da un esponente pari a -312 le cifre significative cominciano a "deteriorarsi" progressivamente a cominciare da quella più a destra. Il numero perde di significato solo dopo 9,88*10-324 dove solo il "9" ha senso mentre le altre cifre arrivano da chissà dove. (nota 3)

- se si parte dal numero "1" e lo si moltiplica molte volte per 10 si vede che oltre 1*10308 diventa "infinity"

- inserire un numero di venti cifre intere "12345678901234567890" (nota 2) e moltiplicare per "1". Risultato : "1234568790123456800". Si vede che le due cifre più a destra sono già scomparse e sostituite con uno "0" e la terzultima è stata approssimata alla più vicina passando da "7" a "8". Scratch ha correttamente scritto 16 cifre significative ed ha arrotondato la meno significativa (nota 1)

- inserire un numero di 30 cifre intere (nota 2), moltiplicare per "1". Risultato: "1,23456789012345e-29; si vede che ci sono 16 cifre significative (nota 1). Dividere per 1030 e vedere che le cifre significative sono 17

 

Altre prove

[tasto 2]: test per verifica che ripetere per 10 volte la somma x:= x+0,1 non da' "1"

[tasto 3]: test per verifica che ripetere per 8 volte la somma x:= x+0,125  da' "1"

[tasto 4]: test per verifica che ripetere per 64 volte la somma x:= x+0,015625  da' "1" 

Perchè questa disparità di trattamento?

0,125 e 0,015625 sono numeri macchina perchè sottomultipli di 2,

0,1 è un numero che viene approssimato dalla macchina 

 

Mai inserire nel programma di Scratch condizioni del tipo "se un (valore) è uguale ad un numero" se non si è sicuri che tali valori possano essere identici in tutte le sue cifre, anche quelle non visibili (per tutte si intende sia l'espnente che l'intera mantissa).

 

Ecco alcuni articoli che sviluppano approfonditamente il problema:

"Aritmetica di macchina e analisi dell'errore" (uniba) di Cinzia Elia e Felice Iavernaro,

"Numeri di macchina" (diapositive) di Luca Zanni e Marco Prato,

"Rappresentazione di nmeri in macchian. Condizionamento e stabilità" (polito) di Stefano Berrone.

 

note

nota 1: sono 16 cifre significative.

nota 2: ogni valore inserito viene trattato inizialmente come una stringa, solo dopo un'operazione Scratch "capisce" se deve trattarlo come un numero o come una stringa.

nota 3: il numero, scritto diversamente, è: 0,988*10-323. Sembra sia possibile scendere a numeri con esponente minore di -308 come previsto dalo standard IEEE 754. Ma se c'erano 16 cifre a disposizione per la mantissa e ne sono state corrotte 15 si è dovuti passare da esponente -308 ad esponente -308-15= -323 prima di vedere scomparire l'ultima cifra superstite del numero originale. Notare che subito dopo anche Scratch si "rifiuta" di continuare a dividere per 10 ponendo il valore a 0 anche se "appaiono" delle cifre non nulle ma che sappiamo casuali.