FPU 8087: i tipi di dati

Introduzione
I giudizi ricevuti alla pubblicazione della prima puntata, mi hanno un po' disorientato.
Certo l'8087 fa parte dell'archeologia dei microprocessori, ma le sue funzioni sono tuttora presenti nei nostri PC.
Ho deciso quindi di fare un' unica lezione conclusiva sui tipi di dati, il modo cioe' in cui vengono scritti i numeri.
Lo standard seguito dal coprocessore e' l'IEEE 754 (attualmente in fase di revisione / ampliamento).
I tipi di dati sono gli stessi che utilizziamo nella programmazione in un qualsiasi linguaggio anche se cambiano nome passando da un linguaggio all'altro (Real, Float, Double ... Integer, int, Longint, .. ecc.).
Sono spiegati in modo accessibile, alcuni concetti come l'uno implicito, la denormalizzazione oppure i NAN, di cui tanti parlano ...... molti meno conoscono.
Per chi vuole approfondire l'argomento FPU, allego la mia dispensa da cui ho tratto gli articoli, che e' poi la traduzione del manuale Intel con un po' di commenti per chiarirne il senso.
TIPI di DATI
I tipi di dati gestiti dalla FPU sono: Interi a 16, 32 e 64 bit, Reali a 32, 64 e 80 bit e i numeri BCD a 18 cifre + segno.
Sui numeri interi c'e' poco da dire: si tratta di normali interi con segno nei quali, quindi, il bit piu' significativo rappresenta il segno (0= +, 1= -).
Sui numeri BCD, va detto che ognuno di questi numeri occupa 80 bit. Siccome ogni cifra occupa 4 bit, in questo spazio entrerebbe un numero grande 80/4=20 cifre decimali. La scelta pero' e' quella di memorizzare il segno che occupa 1 bit e di sprecare 7 bit del byte piu' significativo raggiungendo quindi un totale di "solo" 18 cifre + segno.
Sui reali c'e' un po' piu' da parlare.
Un reale decimale scritto in forma esponenziale e' un numero del tipo -1234,5678 x 10+8.
Chiameremo Significant o Mantissa la parte -1234,5678 ed Exponent o Esponente la parte +8 cioe' l'esponente di 10.
In binario il discorso in partenza e' molto simile. L'equivalente potrebbe essere -1010,1101 x 2+1000.
Un numero al suo interno si suddivide nelle parti: Significant, Exponent e, separatamente, Segno del Significant.
Vi sono pero' delle regole da applicare.
Innanzitutto per evitare ambiguita', si mette la virgola sempre in una stessa posizione.
Si vuole cioe' evitare che due numeri come +10,11x2+1001 e +101,1x2+1000, siccome differiscono nelle due mantisse e nei due esponenti sembrino diversi (i numeri sono uguali, abbiamo solo spostato la virgola ed aggiustato l'esponente).
La regola seguita, prevede che la virgola stia sempre dopo il primo 1 della mantissa (nell'esempio precedente il numero andrebbe percio' scritto +1,011 x 2+1010), ma non basta!
1 Implicito
Siccome in binario le cifre valgono solo 0 oppure 1, e siccome tutte le mantisse hanno un 1 prima della virgola (vi sono alcune eccezioni che pero' vengono gestite diversamente), chi ce lo fa fare di scrivere questo 1 prima della virgola ?
Insomma, per farla breve, nella mantissa del numero precedente viene solo scritto + ,011 risparmiandoci un bit. Questo bit risparmiato in realta' e' utile perche' ci permette, a parita' di tutto, di avere una cifra significativa in piu'.
L'1 prima della virgola che non viene fisicamente scritto nei registri, ma di cui nei calcoli si tiene conto, prende il nome di Uno Implicito.
Per quanto riguarda l'esponente c'e' un'altra piccola complicazione: anziche' essere un normale intero con segno, e' polarizzato. Vale a dire al normale numero intero con segno viene sommata una costante 0111.. ..111 pari alla dimensione dell'esponente.
Facciamo un esempio, senno' le idee restano troppo confuse. Immaginiamo di avere 7 bit per la mantissa, 4 per l'esponente ed 1 per il segno della mantissa:

Il numero binario + 1,010110101011 x 2+0100, si scriverebbe:
1) segno della mantissa 0 (la regola e' la solita 0 = +, 1 = -).
2) la costante di polarizzazione dell'esponente si ottiene facendo seguire un unico 0 da tanti 1 quanti posti rimangono: 0111.
3) l'esponente: +0100 in formato complemento a due e' sempre 0100. A questo punto sommiamogli la costante di polarizzazione ed otteniamo : 0100+0111=1011.
4) Per la mantissa abbiamo a disposizione 7 bit. Togliendo l'1 prima della virgola la mantissa e' ,010110101011. Teniamoci adesso le prime 7 cifre cioe': 0101101.
5) In conclusione il numero verrebbe scritto cosi':

Come abbiamo gia' detto, i formati reali gestiti sono 3:
1- Short Real: 32 bit totali (1 bit segno mantissa, 8 bit di esponente e 23 bit restanti + 1 implicito, di mantissa).
2- Long Real: 64 bit totali (1 bit segno mantissa, 12 bit di esponente e 51 bit restanti + 1 implicito, di mantissa).
3-Temporary Real: 80 bit totali (1 bit segno mantissa, 16 bit di esponente e 64 bit restanti di mantissa: fa eccezione in quanto non utilizza l'1 implicito).
Questo modo di scrivere i numeri reali e' oggetto dello standard IEEE 754 che e' stato adottato da tutti i produttori di computer a partire dagli anni '80. Il formato Short Real corrisponde a quello delle variabili float in linguaggio C/C++, Real del Pascal, ecc. . Il Long Real al Double C/C++.
Il Temporary Real e' poco usato nei programmi ma e' il formato in cui vengono riportate nei registri interni a 80 bit tutte le variabili prima di fare i calcoli (che pero' hanno un'accuratezza legata alla dimensione del dato iniziale).
NAN
La rappresentazione dei numeri reali prevede anche la possibilita' di memorizzare numeri particolari come + e -infinito, NAN, numeri denormalizzati, + e - zero.
Innanzitutto bisogna fare qualche precisazione per ognuno di questi numeri "particolari".
Con + e meno infinito non si intende propriamente la stessa cosa che in matematica. + infinito e' semplicemente un numero che supera il limite massimo per la dimensione del reale in uso, analogo il discorso per - infinito.
La sigla NAN sta per Not A Number e corrisponde ad entita' non numeriche che vengono generate nel corso dei calcoli. All'interno dei NAN distinguiamo Indefinite: una codifica che rappresenta alcune forme indeterminate ( infinito - infinito, zero per infinito o il viceversa) ed anche risultati derivanti da situazioni come "operazione su registro marcato vuoto", registro destinatario non vuoto (in genere a causa di stack overflow), estrazione di radice quadrata di un numero negativo, ecc. .
Denormalizzazione
I Numeri Denormalizzati sono numeri che non rispettano la normale condizione dell'uno implicito e della posizione della virgola. Sono numeri molto piccoli che vengono accettati in questa forma, con un ridotto numero di cifre significative onde evitare un peggiore arrotondamento a 0.

Questa scelta di utilizzare alcune combinazioni di mantissa ed esponente per rappresentare i suddetti "numeri particolari" riduce seppur di poco l'intervallo che significant ed exponent possono assumere. Ad esempio un exponent di 8 bit coprira' l'intervallo +126 :-126 anziche' + 127 : -128.
Vediamo adesso piu' concretamente un esempio che illustra come opera la denormalizzazione. Supponiamo che il risultato di un'operazione fra short real sia:

Come detto, i calcoli internamente vengono condotti con la massima precisione di 80 bit maggiore dei 32 bit del risultato. Calcolato questo viene rilevato che l'esponente -131 e' fuori dall'intervallo consentito da quel formato.
Anziche' arrotondarlo brutalmente a 0, si opera una serie di shift a destra con incrementi dell'esponente, fino a che l'esponente e' rientrato nei limiti consentiti. La prima volta che si fa lo shift a destra come bit entrante vi sara' un 1 (l'uno implicito). Le altre volte uno 0. Ecco la serie di operazioni che verrebbe svolta:
Chi e' interessato ad approfondire l'argomento si puo' scaricare la dispensa completa.
Tanti saluti
P.S.
I consigli e le correzioni sono benvenuti, ma, per cortesia, non vi mettete a giocare al tiro al piccione ! Troppo facile !
L'argomento non e' dei piu' semplici, la dispensa l'ho testata varie volte, ma mi potrebbe, comunque, essere scappata qualche c...... (imprecisione)! Abbiate pieta'!