Capitolo 5. - CALCOLO BINARIO

 

 

 

 

            5.1 - Aritmetica binaria finita.

 

 

                La particolare importanza della numerazione binaria per le macchine da calcolo rende opportuno esaminare i dettagli almeno delle operazioni più semplici, specialmente per la rappresentazione dei numeri negativi.

 

                Utilizzeremo solo numeri binari di lunghezza che fissiamo in otto cifre, (pari ad un byte) scrivendo sempre gli zeri non significativi e suddividendo per facilità di lettura in due gruppi di quattro cifre.  Non vi sono comunque difficoltà nell'estensione a sequenze più lunghe o più corte.

 

                Questo ci permetterà da un lato di costruire esempi senza dovere ricor­rere a sequenze binarie molto lunghe, ma dall'altro di stabilire i principi di una aritmetica a rappresentazione finita, estremamente importante per le applicazioni sulla macchina.

 

                L'elemento più importante  è l'impossibilità di estendere le notazioni numeriche su lunghezze grandi a piacere, come è invece implicito nell'aritme­tica ordinaria.

 

                Nell'ipotesi fatta l'intera sequenza di combinazioni ordinate è la precedente (4.3.1), cioè la rappresentazione dei naturali da 0 a 255 (dec); per eseguire la somma si deve fare riferimento ad una speciale tavola pitago­rica, esprimibile con:

 

  (5.1.1)                   addendi   valore     riporto

 

                                    0   0          0              0

                                    0   1          1              0

                                    1   0          1              0

                                    1   1          0              1

 

                Ad esempio, è immediato verificare che:

 

  (5.1.2)                   0010 0110 +       ( 38 decimale)

                                0100 1010 =       ( 74 decimale)

                                ----------------

                                0111 0000         (112 decimale)

 

                Lo spazio limitato comporta un primo problema: se la somma dei due numeri supera il massimo rappresentabile (in questo caso 1111 1111) il risul­tato non è corretto, perché esiste un riporto sulla prima colonna che non è più rappresentabile nello spazio dato:

 

  (5.1.3)                   1010 0110 +       (166 decimale)

                                1100 1010 =       (202 decimale)

                                ----------------

                     (1?)  0111 0000         (112 decimale)

 

                E' evidente che si ha sempre questa situazione se le prime cifre sulla sinistra dei due addendi sono entrambe 1, cioè per valori entrambi maggiori di 127 (decimale) e poiché il massimo valore rappresentabile nello spazio dato è 255 (decimale), il risultato non può essere corretto, perdendosi l'informa­zione data dalla cifra di riporto.[1]

 

                Se il risultato di una operazione non è allocabile (descrivibile) nello spazio fisso e limitato assegnato, si dice che si verifica una situazione di overflow, vale a dire che esso deborda, o  trabocca; la trattazione dell'over­flow è un argomento importante per il calcolo, che esamineremo in dettaglio.

 

 

                Accenniamo brevemente alle altre operazioni aritmetiche.

 

                Sottrazione - non vi sono differenze di principio rispetto a quella decimale, ma la trattazione delle cifre di prestito può dare luogo a qualche difficoltà per la presenza dei due soli simboli 0 ed 1, che obbligano spesso a trascinare il prestito su molte posizioni.

 

                Se indichiamo la differenza con  a - b, non vi sono problemi quando si ha b <= a, ma si verifica di nuovo una situazione simile all'overflow nel caso opposto, a < b, stavolta determinata dalla mancata rappresentazione dei numeri negativi.[2]

 

                Si vedrà comunque tra breve che questo è un 'falso problema', poiché una molto migliore trattazione della somma si avrà come conseguenza della notazio­ne scelta per i numeri negativi, che non esistono nella tabella (4.3.1).

 

 

                Moltiplicazione - nessuna differenza significativa con quella decimale, salvo la necessità di eseguire la somma di più di due termini, che rende complessa la trattazione dei riporti. E' più conveniente un procedimento a più tappe, in cui le cifre del secondo fattore sono considerate una alla volta, iniziando da destra, eseguendo ad ogni stadio la somma di soli due termini.

 

                Poiché il prodotto richiede un numero di cifre significative (contando cioè dal primo 1 sulla sinistra) dell'ordine della somma dei due analoghi numeri per i due fattori, la condizione di overflow, cioè il superamento del numero 255, si ha anche per fattori relativamente piccoli: 15 * 16 è ancora calcolabile, mentre 16 * 16 non lo è più. Per potere rappresentare in ogni caso il prodotto di due numeri binari di otto cifre sarebbe necessaria la disponibilità di sedici cifre in tutto.

 

 

                Divisione - Non ne interessano i dettagli, che hanno una certa comples­sità, ma la natura un po’ diversa da quella consueta; nella forma finita che abbiamo scelto per i numeri, sono rappresentabili i soli naturali tra 0 e 255, quindi non la eventuale parte frazionaria del quoziente.

 

                Per divisione tra i due interi a e b intendiamo quindi l'operazione che determina non il solo quoziente, ma la coppia quoziente q e resto r, secondo la (unica) relazione:

 

  (5.1.4)                   a = q * b + r.

 

                Riprenderemo ampiamente questa operazione.

 

 

 

 

            5.2 - La rappresentazione del segno.

 

 

                La scelta dello spazio di rappresentazione ad otto cifre binarie ci ha condotto alle combinazioni ordinate (4.3.1), che abbiamo interpretato come notazioni per i numeri naturali da 0 a 255.

 

                Una aritmetica capace di trattare anche numeri negativi ha certamente un ambito di applicazioni maggiore, o meglio una senza ne ha uno molto ridotto; è quindi opportuna una convenzione che permetta una tale possibilità.

 

                La più comune è quella di cambiare l'interpretazione della prima cifra sulla sinistra, non considerandola più come massima potenza nella notazione posizionale, ma come rappresentante del segno; generalmente, ciò si fa ponendo 0 per '+' ed 1 per '-'.

 

 

                Abbiamo così ridotto di una potenza del 2 la capacità di rappresentazio­ne; la sequenza dei numeri positivi è:

 

  (5.2.1)                   0000 0000  ( = 0 )

                                0000 0001  ( = 1 )

                                0000 0010  ( = 2 )

                                .................

                                0111 1110  ( = 126 )

                                0111 1111  ( = 127 )

 

                Definito il segno, si deve però ancora dire come debbono essere inter­pretate le altre cifre. Il modo più naturale sembra essere quello di non cambiare altro, ottenendo la notazione della grandezza con segno:

 

  (5.2.2)                   1000 0000  ( = -0  ? )

                                1000 0001  ( = -1 )

                                1000 0010  ( = -2 )

                                .................

                                1111 1110  ( = -126 )

                                1111 1111  ( = -127 )

 

                Questa notazione genera però diversi problemi; il primo è l'esistenza di due forme distinte dello zero, ambiguità che può divenire molto fastidiosa nelle operazioni.

 

                Il secondo è più immediato e grave; se consideriamo uno dei numeri, ad esempio  n = 1000 0001 ,  ed il suo opposto  -n = 1000 0001, la somma naturale dei due numeri non è nulla, comunque vogliamo trattare le due cifre (i segni) sulla sinistra, vale a dire coinvolgendole, oppure no, nella somma per colonne e nei riporti.

 

                La notazione (5.2.2) ci costringerebbe quindi ad una doppia procedura per l'esecuzione della somma, a seconda del coincidere, oppure no, dei segni; ad esempio, il secondo caso dovrebbe essere trasformato nella differenza.

 

                Un secondo metodo è quello detto del complemento ad uno, che estende a tutte le cifre il 'rovesciamento', o complementazione impiegata per il segno; la sequenza che se ne ottiene è:

 

  (5.2.3)                   1111 1111  ( = -0  ? )

                                1111 1110  ( = -1 )

                                1111 1101  ( = -2 )

                                .................

                                1000 0001  ( = -126 )

                                1000 0000  ( = -127 )

 

                La somma di due opposti, n + ( -n )  è ora nulla, ma la scelta fatta comporta ancora una doppia rappresentazione dello zero, e tale somma coincide sempre con lo zero 'negativo'.

 

                La soluzione migliore è quella del complemento a due, che è definibile per ogni base in questi termini: se il numero n è rappresentato in uno spazio finito di p cifre nella base b, si dice suo complemento a b il numero calcola­to come:

 

  (5.2.4)                   n' = b * p - abs ( n )

 

                Nel nostro caso, b = 2  e  p = 8, quindi 28 = 256.

 

 

                Ad esempio:

 

  (5.2.5)                   n = 3 = 0000 0011 (bin)

                                n' = 256  - 3 = 253 = 1111 1101 (bin).

 

                Il complemento a due di ogni numero positivo è automaticamente un valore negativo (per la convenzione sul segno) e coincide con il complemento ad uno aumentato di una unità, cosa che ne rende immediata la determinazione.

 

                La sequenza completa per otto posizioni è:

 

  (5.2.6)                   1111 1111  ( = -1 )

                                1111 1110  ( = -2 )

                                1111 1101  ( = -3 )

                                 .................

                                1000 0001  ( = -127 )

                                1000 0000  ( = -128 )

 

ed elimina il doppio zero, introducendo al suo posto un negativo in più, dovuto alla rappresentazione dello zero, che per il suo segno è convenzional­mente considerato positivo.

 

                Inoltre, come è facile verificare, la somma di due opposti ha sempre come risultato lo zero (unico).

 

                La notazione del complemento a due è quindi la più semplice possibile dal punto di vista operativo; per essa, anzi, la sottrazione a - b si riduce ad una somma, previa la complementazione a due di b.  Essa è in effetti la scelta normale per il calcolo elettronico.

 

                Con la rappresentazione dei numeri negativi come complemento a due abbiamo ovviamente diminuito il massimo intero rappresentabile, che è ora 127; alla impossibilità di eseguire la somma di due interi, se essa supera 127, si accompagna ora il caso di due negativi la cui somma sia inferiore a -128.[3]

 

 

 

 

 

            5.3 - I numeri interi.

 

                Lo spazio di otto bit, di cui uno da dedicare al segno, rappresenta un intervallo di interi troppo ristretto anche per le operazioni aritmetiche più banali; il byte non è quindi una buona scelta per il calcolo.

 

                Si può però procedere ad una aggregazione, considerando una sequenza di due byte come unica unità logica, che viene generalmente indicata con word, o parola; si ha così una sequenza di 16 bit, con la conseguente capacità di rappresentare le combinazioni (scritte ancora per gruppi di quattro bit):

 

  (5.3.1)                   0000 0000 0000 0000 ,  0000 0000 0000 0001 , ....

                                ...., 1111 1111 1111 1110 ,  1111 1111 1111 1111 ,

 

 

per un totale di 216 = 65536. Questo numero è anche pari a 64 * 1024 e corri­sponde al valore indicato con 64K.

 

                Questa è la forma più comune per la rappresentazione dei numeri interi sulle macchine attuali, ed è anche detta degli interi corti, poiché è pure frequente una scelta alternativa di interi lunghi, ottenuta considerando come unità logica una doubleword, o doppia parola, formata con una sequenza di quattro byte consecutivi, con una disponibilità complessiva di 32 bit.

 

                Ci limiteremo comunque a trattare gli interi a 16 bit, poiché con i secondi non cambia alcuna proprietà essenziale, ma viene solo ampliato l'in­tervallo di variazione dei valori possibili.

 

                L'aritmetica degli interi a 16 bit (e di quelli a 32) è sostanzialmente quella già vista supponendo in 8 bit lo spazio di rappresentazione. Se si vogliono considerare solo valori non negativi, o numeri privi di segno, l'in­tera sequenza di valori è quella data in (5.3.1); se invece si desidera trat­tare anche i numeri negativi si adotta normalmente la notazione del complemen­to a due, con la quale il primo bit sulla sinistra rappresenta il segno e si ottiene l'intervallo di variazione, espresso in decimale:

 

  (5.3.2)                   -32768 (= -(215) ... 0 ... 32767 (= 215 - 1).

 

                Per quanto riguarda le operazioni, debbono essere disponibili somma, differenza e moltiplicazione nel senso consueto; per la divisione vale invece la osservazione in (5.1.4), vale a dire per quoziente tra due interi ne inten­deremo solo la parte intera, mentre il calcolo del resto può essere eseguito con una ulteriore apposita operazione.

 

 

 

 

 

            5.4 - Overflow nelle operazioni intere.

 

                Abbiamo già incontrato in (5.1.3) il principale problema posto dalla rappresentazione finita degli interi: poiché esiste un valore massimo, ogni operazione il cui risultato dovrebbe superare tale limite è priva di senso, a meno di non volere esplicitamente considerare il calcolo algebrico delle classi di resti.

 

                Abbiamo indicato col termine overflow il verificarsi di tale caso; esaminiamo ora più a fondo le condizioni che lo determinano, supponendo di operare con gli interi dotati di segno (secondo la convenzione vista) e ricor­dando che somma e sottrazione sono sostanzialmente la stessa operazione.

 

                Negli esempi consideriamo solo interi 'corti' ad otto bit, poiché la sola differenza tra le tre classi di interi sta nei limiti dell'intervallo di rappresentazione, non nelle proprietà strutturali.

 

                Nella esecuzione della somma trattiamo il bit del segno alla stessa stregua degli altri, ossia sommiamo normalmente i primi bit a sinistra dei due termini, tenendo anche conto dell'eventuale riporto; uno dei vantaggi della notazione del complemento a due sta appunto nel permettere questa operazione senza obbligare a trattare il bit del segno come eccezione.

 

                Sommando due interi possono verificarsi tre casi:

 

                (a) nessuno dei due è negativo  - entrambi i bit di segno a 0;

                (b) solo uno dei due è negativo - un segno 0, l'altro 1;

                (c) essi sono entrambi negativi - entrambi i segni ad 1.

 

                Consideriamo, per (a), la somma dei due valori 127 (il massimo) ed 1:

 

  (5.4.1)                   0 1 1 1  1 1 1 1   (127)

                                0 0 0 0  0 0 0 1   (  1)

 

                L'ultima colonna sulla destra genera 0 con riporto di 1 e così pure le successive verso sinistra, fino al bit del segno, per il quale si ha:

 

  (5.4.2)                   1 (riporto) + 0 (primo segno) + 0 (secondo segno)  =  1

 

ed il valore finale è:

 

  (5.4.3)                   1 0 0 0  0 0 0 0   (-128)

 

e la somma di due numeri positivi ne ha generato uno negativo. Si osservi, in particolare, che nel bit del segno è entrato un riporto, ma non ne è uscito nessuno, mentre per due numeri positivi abbastanza piccoli nel bit del segno non entra un riporto, né ne esce alcuno.

 

                Si può verificare facilmente, ad esempio con:

 

  (5.4.4)                   1 0 0 0  0 0 0 1   (-127)

                                1 1 1 1  1 1 1 0   (  -2)

 

che anche il caso (c) genera una anomalia, cioè un risultato positivo come somma di due negativi. Dal punto di vista del bit del segno, è uscito un riporto senza che ve ne sia entrato alcuno; il caso normale è invece quello in cui nel bit del segno entra un riporto e ne esce uno.

 

                Per quanto riguarda il (b), in ogni caso se nel bit del segno entra il riporto, ne esce pure, o in alternativa non ne entra e non ne esce; d'altra parte è ovvio che in questo caso il risultato è sempre nei limiti.

 

                Il riconoscimento della condizione di overflow è quindi semplice: si verifica tale condizione tutte le volte che il riporto nel bit del segno e quello fuori dallo stesso bit non coincidono.

 

                Se non si verifica overflow, il risultato del calcolo è certamente esatto secondo le regole aritmetiche ordinarie; viceversa, esso è privo di senso, o meglio, come già detto nelle note, è corretto nell'aritmetica delle classi di resti in cui il modulo è il massimo intero rappresentabile nello spazio assegnato.

 

 

 

 

 

            5.5 - I numeri non interi.

 

                Per la maggior parte delle applicazioni che richiedono calcoli i numeri interi sono insufficienti; anche nella variante 'estesa' essi sono limitati alla nona potenza del 10, e questo non è sufficiente né per le esigenze scien­tifiche, né per quelle commerciali.

 

                Anche trascurando le necessità di alta precisione, basta che sia presen­te una divisione, o una radice quadrata perché la parte frazionaria, cioè quella alla destra della virgola, o meglio del punto decimale, divenga una informazione essenziale.

 

                E' quindi stato definito un altro modo di utilizzare la memoria, adatto alla rappresentazione di numeri non interi, che in origine sono stati detti, per motivi che chiariremo presto, numeri floating-point, ma per i quali con il tempo ha prevalso la denominazione impropria di numeri reali.

 

                Non sarebbe difficile rappresentare numeri binari non interi in notazio­ne posizionale, estendendo l'applicazione della notazione decimale in analogia a quanto già fatto per gli interi.

 

                La notazione posizionale per un numero non intero è:

 

  (5.5.1)                   an10n + .. + a1101 + a0100 + b-110-1 + b-210-2 + ...

 

 

ove '10' indica, al solito, una base arbitraria ed an,...,a0,b-1,b-2,... appartengono all'insieme dei simboli semplici nella base scelta.

 

                La sola differenza tra le basi sta nel modo di suddividere l'intervallo unitario 0 .. 1 della retta: in decimi, centesimi, ecc. per la base dieci, ma in 'mezzi', 'quarti', 'ottavi', ecc. per la base due.

 

                E' abbastanza semplice provare che ogni punto della retta può essere rappresentato con una somma di potenze negative di qualunque base; ma, come nel caso decimale, la maggior parte di essi non è rappresentabile esattamente con un numero finito di cifre e richiede non una normale somma, ma una somma­toria infinita.

 

                Si riproduce quindi la suddivisione in numeri razionali (ad espressione finita o periodica) ed irrazionali (ad espressione non periodica). L'apparte­nere all'una o all'altra categoria non dipende dalla base, ma non è così per la proprietà di ammettere un'espressione finita.

 

                Consideriamo ad esempio il numero decimale finito

 

  (5.5.2)                   0.2 = 1/5

 

con cui possiamo illustrare la 'traduzione in binario'. Poiché:

 

  (5.5.3)                   1/4 > 1/5 > 1/8,  ed   1/5 = 1/8 + 3/40,

 

la notazione binaria inizia con:

 

  (5.5.4)                   0.001...,   ossia  0 * 1/2 + 0 * 1/4 + 1 * 1/8 + ...

 

osservando ora che  3/40 = 6/80 > 5/80 = 1/16, si prosegue in:

 

  (5.5.6)                   0.0011...

 

e poiché  1/64 > 1/80 > 1/128 si ha ancora:

 

  (5.5.8)                   0.0011001....

 

                I numeri ad espressione finita in qualunque base sono quelli che possono essere scritti come una frazione ridotta ai minimi termini in cui l'intero a numeratore non ha importanza, ma il denominatore deve contenere solo potenze di numeri primi che siano esatti divisori della base.

 

                Per la base dieci, quindi, solo denominatori della forma 2n*5m, con n ed m numeri naturali qualunque, ma per la base due solo potenze pure del 2; in particolare ogni numero ad espressione finita in base due lo è anche in base dieci, ma non è vero il contrario.

 

                L'ultima osservazione è molto importante: poiché i dati forniti alla macchina sono generalmente scritti in decimale e tradotti automaticamente in binario per 'uso interno' in una rappresentazione necessariamente finita, questa operazione comporta quasi sistematicamente un errore dovuto al necessa­rio arrotondamento o troncamento, anche per numeri apparentemente 'innocui', come lo 0.2 dell'esempio appena visto.

 

 

 

 

 

            5.6 - Rappresentazione frazionale binaria.

 

                Supponiamo ancora, per semplicità, di utilizzare uno spazio di 8 bit, cioè un solo byte, ma dedicando stavolta i quattro bit sulla sinistra alla parte intera ed i quattro sulla destra a quella frazionaria. La posizione del punto decimale è quindi implicita e non comporta lo spreco di un bit; ignoria­mo inoltre la presenza del segno, interessandoci ai soli valori positivi.

 

                La parte intera può quindi variare tra 0 e 15, mentre per la frazionaria si hanno tutte le possibili combinazioni di somme delle frazioni decimali:

 

  (5.6.1)                   1/16 = 0.0625,  1/8 = 0.125,  1/4 = 0.25,  1/2 = 0.5 .

 

                Le rappresentazioni possibili sono sempre 256, ma lette stavolta:

 

 

  (5.6.1)                   valore binario     equivalente decimale

                                    0000.0000                        0

                                    0000.0001                        1/16 = 0.0625

                                    0000.0010                        1/8 = 0.125

                                    0000.0011                        1/8 + 1/16 = 0.1875

                                    .........

                                    0010.1010                        2 + 1/2 + 1/8 = 2.625

                                    1111.1111                        .... = 15.9375

 

e costituiscono una ripartizione dell'intervallo di retta 0 .. 16 (estremo superiore escluso) in 256 parti uguali; con la scelta fatta questi sono quindi i soli punti della retta per i quali esiste una rappresentazione esatta.

 

                E' evidente che la 'grossolanità' di questa rappresentazione non verreb­be cambiata di molto adottando uno spazio di rappresentazione di 16, 32 o anche di 64 bit.

 

                Il problema sta nella gestione delle cifre per le parti intera e frazionaria, che provoca lo spreco sistematico di una grande quantità di bit utiliz­zati anche per gli zeri non significativi.

 

                Il limite è dato dall'avere voluto conservare la notazione posizionale pura, troppo rigida per la rappresentazione in uno spazio finito di valori in cui la prima informazione (cifra) significativa può trovarsi molte posizioni prima, o anche molte dopo il punto si separazione.

 

                Non esaminiamo oltre le conseguenze aritmetiche della notazione in (5.6.1) o delle sue possibili estensioni, poiché l'alternativa esponenziale, di cui ci occupiamo tra breve, è molto più conveniente.

 

                In ogni caso, la rappresentazione di macchina dei numeri non interi è necessariamente finita, come del resto già accade per gli interi; sono quindi finiti anche i punti della retta per i quali esiste un numero corrispondente, anche se la loro distribuzione sarà più 'fine' di quanto permettano le forme del tipo della (5.6.1).

 

                Se i punti rappresentati sono finiti, non è corretto qualificare come reali i numeri, perché si tratta solo di un sottoinsieme di razionali, per di più non periodici; la approssimazione dei 'veri' numeri reali, almeno nell'in­tervallo dei valori ottenibili, può considerarsi però abbastanza buona da permettere l'uso non troppo improprio del termine.

 

                Di qui in avanti diremo quindi reali questo tipo di numeri, senza ulte­riori commenti. L'aritmetica dei numeri reali a rappresentazione finita non coincide con quella ordinaria, come già accade per gli interi; rispetto ad essi si hanno anzi maggiori 'irregolarità'.

 

 

 

 

 

            5.7 - La notazione esponenziale, o scientifica.

 

                Accade spesso, specie in applicazioni scientifiche (astronomia, fisica, ingegneria, ecc. ) di dovere considerare nello stesso contesto numeri reali molto 'grandi' e molto 'piccoli', oltre ovviamente a positivi e negativi.

 

                Ad esempio, eseguire la somma o il prodotto dei valori:

 

  (5.7.1)                   a = 3750466720000000.0

                                b = 0.000000000000000265439045,

 

è abbastanza laborioso; per la somma, ad esempio, i due debbono essere ri­scritti allineando al punto decimale, per una lunghezza complessiva assai maggiore di quelle dei due addendi a e b

 

   (5.7.2)                  3750466720000000.000000000000000000000000

                                                              0.000000000000000265439045 .

 

                Il numero di cifre significative di ognuno dei due valori è abbastanza piccolo, ma le esigenze della notazione posizionale costringono a fare ricorso ad una grande quantità di zeri, che appesantiscono la notazione e la tratta­zione; si noti l'analogia con quanto osservato dopo (5.6.1).

 

                Questi problemi possono essere almeno parzialmente risolti passando ad un'altra notazione, detta esponenziale, o scientifica. Per ottenerla basta osservare che un ordinario numero reale come:

 

  (5.7.3)                   x = 23.701

 

può essere scritto anche in altre forme, spostando a sinistra o a destra la posizione del punto decimale e compensando con la moltiplicazione per una opportuna potenza di 10; ad esempio:

 

  (5.7.4)                   x = 23701 * 10-3

                                   = 237.01 * 10-1

                                   = 0.23701 * 102

                                   = 0.00023701 * 105

 

sono scritture diverse per il medesimo valore.

 

                Si dice notazione esponenziale la scrittura di un numero reale come:

 

  (5.7.5)                   m * 10c

 

in cui la mantissa è un numero reale ordinario (eventualmente dotato di segno) e la caratteristica c (o esponente) è il 'fattore di compensazione' che ne determina l'ordine di grandezza.

 

                Ogni numero reale può essere rappresentato in infinite forme esponenzia­li diverse, tante quanti sono i possibili valori della caratteristica; tra di esse ne esiste una privilegiata, che è detta notazione esponenziale normaliz­zata, che è quella in cui il valore assoluto della mantissa è compreso tra zero ed uno, estremo superiore escluso, avendo inoltre la prima cifra signifi­cativa al primo posto dopo il punto.

 

                Nella notazione esponenziale normalizzata la mantissa m è cioè sottopo­sta ai vincoli:

 

  (5.7.6)                   0.1 <= m < 1

 

che, mentre è unica per ogni numero reale non nullo, comporta l'impossibilità di rappresentazione dello zero, il quale risulta l'unica eccezione della regola generale e deve essere trattato a parte con una convenzione apposita (si veda più avanti).

 

                In (5.7.4) la forma normalizzata è la terza, in cui:

 

  (5.7.7)                   m = 0.23701   e   c = 2,

 

mentre la scrittura esponenziale normalizzata del valori (5.7.1) è:

 

  (5.7.8)                   a = 0.375046672 * 1016

                                b = 0.265439045 * 10-15

 

e permette di valutare 'ad occhio' un valore approssimato per il prodotto: infatti 0.37 * 0.26 è 'quasi' 0.1, mentre la somma delle caratteristiche è 1, ossia il prodotto dei due numeri è di poco inferiore ad 1.0. Per la somma rimangono invece i problemi connessi all'allineamento del punto decimale.

 

                Questi esempi bastano per evidenziare il punto di maggiore importanza: con questa notazione è possibile una scrittura uniforme in uno spazio limitato di numeri aventi ordini di grandezza molto diversi tra loro; viene in ogni caso evidenziata l'informazione essenziale, che è la sequenza di cifre signi­ficative, mentre la caratteristica fornisce l'ordine di grandezza, espresso in potenze della base.

 

                Al riguardo dell'uniformità della scrittura si deve ancora osservare che l'informazione data dalla (5.7.8) può essere rappresentata in una forma ancora diversa e per qualche aspetto più conveniente, eliminando dalla notazione tutto ciò che è 'scontato': nell'ordine, la parte '0.' e l'indicazione della base nella caratteristica.

 

                Ne segue che la rappresentazione si può ridurre formalmente ad una coppia di interi indipendenti, per la quale lo zero non è più una eccezione, che in generale si scrive:

 

  (5.7.9)                   ( m, c ),

 

e che per (5.7.8), ad esempio, diviene:

 

  (5.7.10) a = ( 375046672, 16 )

                                b = ( 265439045, -15 )

 

                Si hanno quindi tutte le caratteristiche richieste ad una notazione numerica per essere adattata alle necessità di rappresentazione in uno spazio finito; la notazione esponenziale normalizzata è infatti quella standard di macchina per i numeri non interi.

 

                Poiché la rappresentazione è finita, essa è necessariamente inesatta;  i numeri reali, nella loro forma di macchina, comportano quindi errori di ap­prossimazione sistematici.

 

 

 

 

 

            5.8 - Notazione esponenziale binaria di macchina.

 

 

                La notazione esponenziale è stata definita, per chiarezza, nei consueti termini decimali, ma quanto stabilito resta valido anche in base due: l'espressione (5.5.1) non si riferisce infatti a nessuna base particolare.

 

                Per quanto osservato con (5.7.9), il numero reale può essere considera­to come una coppia di interi; poiché ci è già nota la rappresentazione binaria degli interi, si tratta quindi ormai solo di stabilire:

 

  (5.8.1)   - quanti byte debbono essere utilizzati complessivamente per la rappresentazione di un

                   numero reale in notazione binaria esponenziale normalizzata.

                - quanti di essi debbono rappresentare la mantissa e con quali convenzioni sono utilizzati.

                - quanti, analogamente, per la caratteristica.

 

                Tra le convenzioni rientra naturalmente la trattazione del segno.

 

                Sono stati definiti parecchi 'formati', variabili con la macchina e con il linguaggio, anche se attualmente si ha un generale allineamento sugli standard IEEE (Institute of Electrical and Electronical Engineers, Inc.), che fissano in 4 byte, o 32 bit lo spazio di rappresentazione per i numeri reali ordinari ed in 8 byte, o 64 bit quello per la precisione estesa ('doppia').

 

                I 32 bit del caso 'normale' sono così ripartiti:

 

  (5.8.2)                   smmmmmmm mmmmmmmm mmmmmmmm cccccccc,

 

ossia il primo a sinistra, 's', rappresenta il segno con la consueta conven­zione (0=positivo, 1=negativo), i successivi 23 'm' sono la espressione intera della mantissa, sempre completata con zeri sulla destra e gli 8 'c' dell'ultimo byte a destra sono la rappresentazione della caratteristica.

 

                Per la mantissa si deve osservare che nella espressione binaria essa inizia sempre con la cifra '1', con la sola eccezione del numero zero; tale '1' iniziale può quindi essere ritenuto implicito e non venire incluso nella scrittura;  la mantissa utilizza quindi sempre 24 bit in totale.

 

                La capacità di rappresentazione di 24 bit è di 224, e poiché:

 

  (5.8.3 )                  210 = 1024, cioè circa  1000 = 103,

 

24 cifre binarie equivalgono a circa 3 + 3 + 1.5 cifre decimali.

 

                La capacità di rappresentazione della mantissa nella forma IEEE standard è quindi dell'ordine di 7 cifre decimali per ogni valore fissato della carat­teristica; questa è quindi la massima precisione con cui un singolo numero reale può essere rappresentato. La traduzione decimale/binaria e gli errori di approssimazione cumulati nelle sequenze di calcoli diminuiscono sensibilmente la precisione.

 

                Il passaggio alla doppia precisione, cioè l'impiego complessivo di 64 bit in uno schema simile a (5.8.2), con una eventuale assegnazione maggiore di spazio per la caratteristica sposta i confini del problema, non il problema stesso. Il massimo numero di cifre decimali esatte passa in genere a 13-14.

 

                Per quanto riguarda invece la caratteristica, il suo valore non è in genere rappresentato come un intero 'naturale' di 8 bit nel complemento a due, ma come 'scostamento' rispetto a 128 nello spazio di rappresentazione 0..255, stabilendo per convenzione che la sequenza c = 00000000 di bit nulli sia associata al solo numero reale 'zero' e che c = 1000000 non venga mai utiliz­zata (si tratterebbe di uno 'zero negativo').

 

                In questo modo i valori possibili della caratteristica variano da -127 a +127, che in termini decimali significa una variazione -38 .. +38. I limiti di rappresentazione dei numeri reali positivi ordinari sono infatti:

 

  (5.8.4)                   minimo = 1.1754944 * 10-38  circa

                                massimo = 3.4028235 * 1038  circa

 

e simmetrici per i negativi; per la doppia precisione IEEE si ha invece:

 

  (5.8.5)                   minimo = 2.225073858507201 * 10-308  circa

                                massimo = 1.797693134862316 * 10308  circa

 

 

 

 

            5.9 - Anomalie della rappresentazione binaria.

 

                I numeri rappresentati come in (5.8.2) sono un sottoinsieme finito dei numeri razionali (frazioni) ad espressione finita, che formano invece un insieme infinito.

 

                Dalla finitezza segue immediatamente l'esistenza di un valore minimo non nullo, quello in (5.8.4) o in (5.8.5), che è quindi immediato successore dello zero e corrisponde alla configurazione di bit minima per la caratteri­stica (-127 binario) e per la mantissa (il solo primo bit numerico diverso da zero); ogni tentativo di calcolo di valori positivi al di sotto del minimo (o suo analogo per i negativi) determina la condizione di errore detta underflow.

 

                In quanto alla condizione di overflow, essa non riguarda più la mantis­sa, in cui la perdita di informazione è una condizione 'normale' per la neces­sità delle approssimazioni, ma l'esponente, che non può superare il massimo dato nelle (5.8.4) e (5.8.5).

 

                Un'altra proprietà a prima vista sorprendente è la seguente: se a e b sono due reali positivi entrambi non nulli può accadere che:

 

  (5.9.1)                   a + b = a,

 

relazione aritmeticamente assurda.

 

                Per comprenderne la ragione ci si può limitare alla notazione decimale, considerando i due valori dell'esempio (5.7.1), per i quali supponiamo ora che essi possano essere scritti solo con una espressione di 25 cifre decimali  al massimo, sufficiente per i due numeri singolarmente.

 

                La somma non può però essere più scritta come in (5.7.2), per l'ipotesi sulla lunghezza massima; l'allineamento del punto decimale è sempre necessa­rio, ma si deve pure 'sacrificare' un certo numero di cifre di a o di b, ed ovviamente si tratta delle seconde, meno significative. La somma effettivamen­te eseguibile è quindi:

 

  (5.9.2)                   3750466720000000.000000000

                                                               0.000000000

 

e coincide esattamente con a.

 

                L'anomalia meno evidente riguarda però la distribuzione stessa dei punti sulla retta, che non è più uniforme (in sottointervalli uguali), come accade invece con la notazione in (5.7.1), poco opportuna per il calcolo.

 

                Nella rappresentazione IEEE a 4 byte ogni mantissa utilizza 23 bit effettivamente variabili (non lo 1 iniziale implicito) ; le combinazioni possibili sono esattamente 223, equivalenti ad altrettanti punti equidistanti per ogni valore fissato della caratteristica.

 

                Vale a dire, 223 punti nell'intervallo 1/4 .. 1/2, esattamente come in 1024 .. 2048, oppure  2126 .. 2127, o anche 2-126 .. 2-127 .

 

                Il numero 223 vale circa 8 milioni in decimale; per valori vicini allo zero la capacità di discriminazione è quindi molto alta, ma si dirada col il crescere della caratteristica (se positiva, ma i valori negativi sono simmetrici). Ne segue una strana distribuzione uniforme a scalini, che ai fini della precisione privilegia i calcoli fatti nell'intorno dello zero.

 

                Terminiamo commentando la denominazione di floating point impiegata per i numeri reali nella rappresentazione di macchina: essa deriva dalla notazione scientifica, con cui il punto decimale viene fatto 'fluttuare' verso la destra o verso la sinistra, secondo necessità.

 

                Gli interi, per i quali con la notazione attuale il problema del punto decimale non si pone, sono stati per contrasto detti anche fixed point; questa denominazione è obsoleta, ma di essa esiste ancora traccia in FORTRAN.

 

 

 



[1]   Esso non è nemmeno del tutto 'scorretto': si riconosce infatti facilmente che il valore ottenuto è sempre la somma dei due addendi modulo 256, come definito nell'aritmetica ciclica delle classi di resti, che associa ad ogni intero con il resto della sua divisione (intera) per il modulo.

 

[2]  Per la sottrazione, come pure per la moltiplicazione, il risultato 'anomalo' è però ancora coerente con il calcolo nelle classi di resto modulo 256.

 

[3]  Il lettore interessato può esaminare i vari casi in dettaglio (sono cinque in tutto), osservando che in definitiva si ottiene solo una variante della aritmetica modulo 256, con rappresentanti positivi e negativi; è pure interessante mettere a confronto i casi di overflow con il comportamento dei riporti dentro e fuori delle cifre del segno, trattate nelle  operazioni al pari delle altre.