La rappresentazione dei numeri reali

 

I numeri reali comprendono i numeri:

 

 

 

Nei sistemi posizionali, fissato il valore B della base e l'insieme dei simboli o cifre, di solito appartenenti all'insieme {0,1,2,..,B-1}, un numero reale R è rappresentato da:

 
± dn-1 dn-2 .. d1 d0 . d-1 d-2 .. d-m
 

 

Il valore di un numero X espresso in questa notazione è dato dalla formula:

 

X = Bn-1 * dn-1 + ….. + B2 * d2 + B1 * d1 + d0 *B0 +

B-1 * d-1 + B-2 * d-2 + B-3 * d-3 + ... B-m * d-m + ...

 

 

che si può riscrivere come:

 

      n-1               m
X = S dk * Bk + S d-k * B-k
     k=0               k=1

 

dove:

Esempi

 
 
Stringa Base Calcolo valore Valore in base 10
12.3 10 1*101+ 2*100+3*10-1=10+ 2 +0.3 12.3
12.3 4 1*41+ 2*40+3*4-1 = 4+ 2 +0.75  6.75
12.3 8 1*81+ 2*80+3*8-1= 8 + 2 + 0.375 10.375
12.3 16 1*161+ 2*160+3*16-1=16 + 2 +0.1875 18.1875
 





Conversioni di rappresentazione da base B a base 10
 

Ogni numero è espresso, in una base data, da una ben precisa sequenza di cifre.
 

Data una rappresentazione sotto forma di sequenza di cifre (e una base), il numero corrispondente si ricava applicando la formula già vista:

   

X =      Bn-1 * dn-1 + ….. + B2 * d2 + B1 * d1 + d0 *B0 +

            B-1 * d-1 + B-2 * d-2 + B-3 * d-3 + ... B-m * d-m + ...

 

che si può riscrivere come:

 

      n-1               m
X = S dk * Bk + S d-k * B-k
     k=0               k=1

 

Conseguenza
 

La conversione avviene in due fasi:

    conversione della parte intera

    conversione della parte frazionaria

e successiva somma dei due contributi.



Un esercizio di programmazione
Conversione efficiente da rappresentazione binaria a base 10
 

Un algoritmo efficiente per sommare i contributi dei singoli bit come ad esempio, (1001.11) 2
che corrisponde al  valore :

(23 + 20+ 2-1 + 2-2)2 = (9.75) 10

consiste nel calcolare separatamente parte intera e parte frazionaria:

 
Esempio:
(1001)2 = (23 + 20) = ((((1)*2 + 0)*2+0)*2+1)
= (9) 10
[valutazione ® ]
(.1101)2 = (2-4 + 2-2 + 2-1) = (((((1)/2+0)/2+1)/2+1)/2)
= (.8125) 10
[valutazione ¬ ]
 



Conversioni di rappresentazione da base 10 a base B
Dato un numero in base 10, come si ricava la sua rappresentazione sotto forma di sequenza di cifre in una base B assegnata?
 

Osservando che comunque nella notazione posizionale di un reale si distinguono una parte intera ed una frazionaria, per quanto attiene la parte intera potremmo applicare l’algoritmo già visto delle divisioni successive mentre per la parte frazionaria ( |F| < 1), poiché abbiamo esponenti negativi infatti:

F = B-1 * d-1 + B-2 * d-2 + B-3 * d-3 + ... B-m * d-m + ...

per isolare le cifre occorre adottare l'algoritmo delle moltiplicazioni successive.

 
Algoritmo delle moltiplicazioni successive

 Detta F la parte frazionaria di un numero reale V, fissato il valore B della base, essa soddisfa la seguente uguaglianza:

F = B-1 * d-1 + B-2 * d-2 + B-3 * d-3 + ... B-m * d-m + ...

Che può essere anche scritta:

                                F = B-1 * (d-1 + B-2 * d-2 + B-3 * d-3 + ... B-m * d-m + ...)

 
F = B-1 * (d-1 + B-1 * (d-2 + B-1 * (d-3 + ... B-1* (d-m + ...)))))
 
F = B-1 * (d-1 + K)

 

Nel caso in cui B=2 si ha: F= 2-1 *(d-1+K )

 

Pertanto moltiplicando il numero frazionario F per B si ha che la parte intera della moltiplicazione rappresenta il coefficiente di posto -1 ovvero d-1, mentre la parte frazionaria risultante è pari al numero K:
 

K = (d-1 + B-2 * d-2 + B-3 * d-3 + ... B-m * d-m + ...)

al quale può quindi essere applicato di nuovo lo stesso procedimento che fornisce via via le cifre binarie successive.

Il procedimento termina quando si ottiene il valore K=0 oppure lo si può interrompere quando si è raggiunto un numero di cifre adeguato a rappresentare F con la precisione desiderata.

 



Osservazioni sull’algoritmo

 

 

Conseguenza
La conversione avviene in due fasi:

       conversione della parte intera (divisioni successive)

       conversione della parte frazionaria (moltiplicazioni successive)

e successiva sintesi della stringa finale per composizione delle due sottostringhe.



1) Esempio di conversione da base 10 a base 5
V = (29.66)10 ® (….)5
 

Conversione della parte intera
      29 : 5 = 5 con resto 4
    5 : 5 = 1 con resto 0
    1 : 5 = 0 con resto 1 ® (29)10 = (104)5

Conversione della parte frazionaria
    .66 * 5 = 3.3 parte intera = 3, parte frazionaria restante = ,3
    .3 * 5 = 1.5 parte intera = 1, parte frazionaria restante = ,5
    .5 * 5 = 2.5 parte intera = 2, parte frazionaria restante = ,5
    .5 * 5 = 2.5 parte intera = 2, parte frazionaria restante = ,5

® la rappresentazione di .66 in base 5 è periodica

(.66)10 = (.31222222...)5
V= (29.66) 10 ® (104,31222222...) 5

 

 



2) Esempio di conversione da base 10 a base 2
V = (5.875)10 ® (….)2

Conversione della parte intera
    5 : 2 = 2 con resto 1
    2 : 2 = 1 con resto 0
    1 : 2 = 0 con resto 1 ® (5) 10 = (101) 2

Conversione della parte frazionaria
    .875 * 2 = 1.75 parte intera = 1, parte frazionaria restante = .75
    .75 * 2 = 1.5 parte intera = 1, parte frazionaria restante = .5
    .5 * 2 = 1.0 parte intera = 1, parte frazionaria restante = .0

    ® (.875) 10 = (.111) 2
    V = (5.875)10 ® (101.111)2

 

 



3) Esempio di conversione da base 10 a base 2
V = (0.5)10 ® (….)2
 

Conversione della parte intera
    (0) 10 = (0) 2

Conversione della parte frazionaria
    .5 * 2 = 1.0 parte intera = 1, parte frazionaria restante = .0

    ® (.5) 10 = (.1) 2
    V = (0.5)10 ® (0.1)2

 



4) Esempio di conversione da base 10 a base 2
V = (0.3)10 ® (….)2

Conversione della parte intera
    (0) 10 = (0) 2

Conversione della parte frazionaria
    .3 * 2 = 0.6 parte intera = 0, parte frazionaria restante = .6
    .6 * 2 = 1.2 parte intera = 1, parte frazionaria restante = .2
    .2 * 2 = 0.4 parte intera = 0, parte frazionaria restante = .4
    .4 * 2 = 0.8 parte intera = 0, parte frazionaria restante = .8
    .8 * 2 = 1.6 parte intera = 1, parte frazionaria restante = .6 …periodico

    ® (.3) 10 = (.01001) 2
    V = (0.3)10 ® (0.1001)2

 

 



La rappresentazione dei reali all’interno del calcolatore
 

In genere la rappresentazione finita dei numeri reali è impossibile quando il numero ha infinite cifre nella parte frazionaria:

· numeri irrazionali

(non rappresentabili finitamente in forma esplicita in nessuna base:

Ö 2, p )
 

· numeri razionali periodici nella base di rappresentazione utilizzata.

 

Osservazione

Un razionale può risultare periodico o meno a seconda della base usata per rappresentarlo

1/3 = (0.333333333333...)10 = (0.1) 3
8/7 = (1.142857142857...) 10 = (1.1) 7  

in particolare:
se è periodico quando rappresentato in base B, è periodico anche quando rappresentato in qualunque base B’ che sia un fattore di B (B = k B’),

 

quindi se X ha rappresentazione periodica in base 10, la avrà periodica anche in base 2 o in base 5 (ma non necessariamente viceversa)

 

il viceversa, invece, vale solo se B è una potenza di B’ (B = B’m)

 

quindi se è periodico quando rappresentato in base 2, lo sarà anche in base 4, 8, 16,...

 

 

Numeri reali in un elaboratore

 

E' possibile rappresentare finitamente un numero reale all’interno del calcolatore?

Il vincolo

In un elaboratore, la rappresentazione dei numeri reali deve necessariamente essere finita.
 
 

 

 



Rappresentazione in virgola fissa

 

La rappresentazione in virgola fissa è così detta in quanto, stabilito il numero K di bit per memorizzare il numero reale (valori possibili di k sono: 16,32,64) si usa un bit per rappresentare il segno del numero ed i rimanenti K-1 bit vengono suddivisi in due parti una per la memorizzazione della parte intera e una per la parte frazionaria, separate dalla virgola che assume idealmente una posizione fissa.
 

0  1 2 3 4 …… 15 16 17 …… 31
 
0 1 2 15 16 31
­                  ­                         ­                  ­
segno       parte intera               punto    parte frazionaria

 

Numeri reali in virgola fissa in una ipotetica macchina
 
BIT VALORI AMMESSI S 
segno
PI
parte intera
PF parte frazionaria
32 

(4 byte)

da .1*2-16               a » 215  

cioè 1.5*10-6 ¼    3.2768*104 

1 bit 15 bit  

 

16 bit
 

 
 



Rappresentazione in virgola mobile

La rappresentazione in virgola mobile (floating point), detta anche a mantissa e caratteristica, si basa sulla rappresentazione esponenziale dei numeri, detta anche notazione scientifica.

Secondo tale notazione un numero reale V può essere espresso nella seguente forma:

V = ± m * Besp
 m mantissa (reale)     esp esponente (intero)
  Poiché esistono infinite coppie (m, esp) in grado di rappresentare, lo stesso valore reale V, ad esempio, se V=61.4357, B=10 si può avere:
 
Scomposizione mantissa esponente
614,357 * 10-1 614.357 -1
61,4357 * 100 61.4357 0
6,14357 * 101 6.14357 1
0,614357 * 102 0.614357 2
  occorre fare una scelta, in modo che la rappresentazione di un dato valore sia unica.

 

 



Rappresentazione normalizzata

 

Ipotesi: mantissa normalizzata

     compresa fra 0 (incluso) e 1 (escluso)

      avente (se diversa da 0) la prima cifra diversa da zero

  Conseguenza: 1/B £ m < 1

   

Infatti ricordando che m è un numero frazionario si ha:

  m = B-1 * d-1 + B-2 * d-2 + B-3 * d-3 + ... B-m * d-m + ...

pertanto affinché in qualunque base la prima cifra della mantissa sia significativa ovvero diversa da zero deve esserci B-1 * d-1 (il più piccolo di ¹ 0 vale 1)

e quindi e deve essere 1/B £ m.

 

Nell’esempio precedente: la scomposizione prescelta è :

0,614357 * 102        m=0.614357             esp =2
 
Osservazione
La rappresentazione normalizzata è una scelta "efficiente" perché sfrutta tutte le n cifre disponibili per la mantissa senza sprecarle per zeri iniziali che non portano vera informazione (come accadrebbe invece con esp>2, es: per V=0,0614357 * 103 m=0.0614357 esp =3)

 

 

Conversioni di rappresentazione da base 10 a base 2 in notazione esponenziale normalizzata
Dato un numero reale in base 10, come si ricava la sua rappresentazione esponenziale normalizzata in una base B assegnata?

 

Si possono seguire due strade:

 

I Metodo

Convertire il numero da base 10 a base B e poi operare la normalizzazione.

 

1) Esempio di conversione da base 10 a base 5
V = (29.66)10 ® (….)5
 

Conversione della parte intera
29 : 5 = 5 con resto 4
5 : 5 = 1 con resto 0
1 : 5 = 0 con resto 1 ® (29)10 = (104)5

Conversione della parte frazionaria
.66 * 5 = 3.3 parte intera = 3, parte frazionaria restante = ,3
.3 * 5 = 1.5 parte intera = 1, parte frazionaria restante = ,5
.5 * 5 = 2.5 parte intera = 2, parte frazionaria restante = ,5
.5 * 5 = 2.5 parte intera = 2, parte frazionaria restante = ,5
® la rappresentazione di .46 in base 5 è periodica

    (.66)10 = (.31222222...)5
    V= (29.66) 10 ® (104,31222222...) 5
Normalizzazione della mantissa 104,31222222...5= 0.10431222222..*53

B=5    m= 0. 0.10431222222      esp= 3

 

2) Esempio di conversione da base 10 a base 2
V = (5.875)10 ® (….)2

Conversione della parte intera
5 : 2 = 2 con resto 1
2 : 2 = 1 con resto 0
1 : 2 = 0 con resto 1
® (5) 10 = (101) 2

Conversione della parte frazionaria
.875 * 2 = 1.75 parte intera = 1, parte frazionaria restante = .75
.75 * 2 = 1.5 parte intera = 1, parte frazionaria restante = .5
.5 * 2 = 1.0 parte intera = 1, parte frazionaria restante = .0
® (.875) 10 = (.111) 2

V = (5.875)10 ® (101.111)2
Normalizzazione della mantissa 101.111= 0.101111 * 23
      B=2        m= 0. 101111          esp= 3

 
II Metodo
Algoritmo per trovare la rappresentazione normalizzata di un numero V in base B:
 

 

Ad esempio, per trovare la rappresentazione normalizzata in base 10 del numero reale V = (5.875)10 possiamo:

Come si vede il valore della mantissa soddisfa la condizione
1/B£ m <1 infatti (1\B=1\10=0.1) 0.1£ 0.5875 <1

 

Troviamo ora la rappresentazione normalizzata di 5.875 con base B=2:
 

 

Come si vede il valore della mantissa soddisfa la condizione

1/B£ m <1 infatti (1\B=1\2=0.5) 0.1£ 0.734375<1

pertanto si ha: 5.875= 0.734375*23

Effettuando la trasformazione in binario della mantissa (0.734375) si ottiene:

Conversione della parte frazionaria
.734375 * 2 = 1.46875 parte intera = 1, parte frazionaria restante = .46875
.46875* 2 = 0.9375 parte intera = 0, parte frazionaria restante = .9375
.9375* 2 = 1.875 parte intera = 1, parte frazionaria restante = .875
.875 * 2 = 1.75 parte intera = 1, parte frazionaria restante = .75
.75 * 2 = 1.5 parte intera = 1, parte frazionaria restante = .5
.5 * 2 = 1.0 parte intera = 1, parte frazionaria restante = .0
® (0.734375) 10 = (.101111) 2

 

Come si può notare anche con questo metodo risulta m= 0.10111 ed esp=3
pertanto risulta che la seguente rappresentazione binaria normalizzata

5.875 = 0.101111 * 23

 

 

Scelte operative

Decidere la rappresentazione dei numeri reali in un elaboratore, che opera in base B=2, significa stabilire: La rappresentazione di V, fissato il numero K di bit, ad esempio k=16, può essere effettuata suddividendo la locazione di memoria in tre parti:  
0 1 2 8 9 10 31
­                  ­                                           ­
segno       caratteristica                      mantissa
 
 

Nota: poiché per B=2, la mantissa m è sempre compresa fra 1/2 (incluso) e 1 (escluso)
quindi, l’MSB vale sempre 1:

m = ,1xxxxxxx.... e perciò si può evitare di rappresentarlo, perché non porta informazione.

 Esempio: codifica di 5.87510
Float
(32 bit - Mantissa su n=24 bit - Esponente su 8 bit, con eccesso 126 =   27-2)

1) V = 5.87510 = 101.1112
Rappresentazione normalizzata: V = .101111 * 23
Rappresentazione dell'esponente (3+126=129) :  10000001

Rappresentazione in memoria

segno esponente mantissa normalizzata (23 bit, MSB escluso)
 
0 1 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Contenuto in memoria

01000000 10111100 00000000 00000000 contenuto binario dei byte

byte 1 byte 2 byte 3 byte 4

40 BC 00 00 contenuto esadecimale dei byte

   

 

Precisione della rappresentazione
Per precisione di una rappresentazione in virgola mobile si intende il numero di cifre frazionarie che si riescono a rappresentare senza troncamenti.

A tale proposito si osservi che, se si vuole rappresentare in binario con la stessa precisione una mantissa normalizzata (in base 10) occorre prevedere un numero di cifre binarie pari circa al triplo delle cifre presenti nella rappresentazione decimale.
 

Infatti poiché il numero di cifre necessarie per rappresentare in base 2 un valore V è proporzionale a
log2 di V
risulta che il rapporto tra la rappresentazione in base 2 e in base 10 vale:

log2 V
                 3.322
log10 V
Infatti poiché log2 V = log2 10 * log10 V allora tale rapporto risulta pari a = log2 10 = 3.322

Quindi se siamo interessati a rappresentare numeri fino alla k-esima cifra decimale (ovvero ad accettare un errore di rappresentazione relativo < 10-K), dovremo prevedere di usare 3.322*K cifre binarie frazionarie.

Riassumendo si ha che le cifre per la memorizzazione della mantissa servono per la precisione, mentre le cifre per la memorizzazione della caratteristica determinano l'ampiezza dell'intervallo.

Pertanto quando nei calcoli scientifici è richiesta maggior precisione (cioè è necessario memorizzare più cifre decimali) per rappresentare la mantissa si usano altre due o quattro parole contigue, in tal caso si parla di doppia o quadrupla precisione ed è possibile memorizzare fino a 19 o più cifre decimali.

 

 

 

 

Errori dovuti alla rappresentazione approssimata dei numeri reali
A causa del fatto che non tutti i numeri reali sono rappresentabili, nell'aritmetica reale non valgono la proprietà associativa e commutativa della somma e del prodotto o la proprietà distributiva del prodotto pertanto operazioni matematicamente equivalenti possono dare in pratica risultati diversi in quanto l’ordine delle operazioni può avere influenza sul risultato finale.

Si noti che mentre il limite posto ai numeri interi non comporta errori di rappresentazione ma solo l'impossibilità di risolvere problemi con numeri molto grandi o piccoli, la limitatezza del numero delle cifre significative di un numero reale può condurre ad errori.
 

Infatti esiste una disciplina apposita per il calcolo numerico che studia le modalità di esecuzione delle operazioni con il calcolatore, valutando l'entità degli errori numerici introdotti durante l'esecuzione delle istruzioni.
 

La limitatezza del numero delle cifre significative di un numero reale può condurre ad errori di quattro tipi: di troncamento, arrotondamento, incolonnamento e cancellazione.
 

Errore di troncamento e arrotondamento
Si commette un errore di troncamento o arrotondamento perché è impossibile rappresentare le infinite cifre dei numeri periodici e irrazionali con soli n bit o perché il risultato di un’operazione eccede gli n bit disponibili.

 

Errore di incolonnamento
Si commette un errore di incolonnamento perché per eseguire somme e sottrazioni tra numeri reali questi vanno incolonnati allo stesso esponente.

 

Errore di cancellazione
Si commette un errore di cancellazione come conseguenza della operazione di sottrazione tra numeri simili i quali sono però stati rappresentati compiendo un errore di troncamento /arrotondamento.

 

 

Errore di troncamento

È impossibile rappresentare esattamente in base 2, con n bit, tutti i possibili valori reali.
I soli valori rappresentati esattamente sono quelli esattamente esprimibili come
m * Besp

Sommando due valori, il risultato può non essere più rappresentabile negli n bit disponibili per la mantissa.

 

Esempio (ipotizzando, per semplicità una mantissa di un solo byte)
Operazione (fra reali): 158.0 + 133.0

 

Addendi:
158 = 100111102 = .100111102 * 28 (rappresentato esattamente sugli 8 bit disponibili)
133 = 1000010122 = .100001012 * 28 (rappresentato esattamente sugli 8 bit disponibili)

 

Somma:
158 = ,100111102 * 28 +
133 = ,100001012 * 28 =
      
        1,001000112 * 28 = 291
Ma il risultato, di 9 bit, eccede gli 8 bit disponibili per la mantissa, se fossero interi, avremmo overflow e perderemmo il valore del numero, qui invece, trattandosi di reali, si perde qualcosa in precisione (causa perdita LSB ) ma il risultato resta utilizzabile .

Dunque, basta rinormalizzare (verso destra) il risultato e troncarlo (o arrotondarlo) a n bit

1,001000112 * 28 = ,100100012 * 29

Notare che questa rappresentazione a causa dell’errore di troncamento denota 290, anziché 291.
Infatti  0,100100012 * 29 = 100100010 = 256+32+2 = 290
 

Errore di incolonnamento

L’errore di incolonnamento si manifesta quando si incolonnano - per sommarli o sottrarli - due numeri di esponente abbastanza diverso.
 

Esempio (ipotizzando, per semplicità una mantissa di un solo byte)

Operazione (fra reali): 96,5 + 1,75

Addendi:

96,5 = 1100000,12 = ,110000012 * 27 (rappresentato esattamente sugli 8 bit disponibili)

1,75 = 1,11000002 = ,111000002 * 21 (rappresentato esattamente sugli 8 bit disponibili)

 

Per sommare gli addendi, occorre incolonnarli cioè portarli allo stesso esponente: quale? Matematicamente, un esponente vale l’altro ma praticamente, è indispensabile portarli entrambi all’esponente maggiore (in questo caso 7), perché è la scelta che comporta l’errore minore.

Quindi, 1,75 viene trasformato e incolonnato allo stesso esponente di 96,5, ciò comporta la perdita di alcune delle cifre meno significative ovvero un errore di incolonnamento

 

96,5 = ,110000012 * 27 +
1,75 = ,000000112 * 27 = (si perdono cifre)
          ,110001002 * 27 = 98 (anziché 98,25)

Perciò l’operazione realmente effettuata non è stata 96,5 + 1,75, ma 96,5 + 1,5.

L’errore di 0,25 nel risultato non è stato causato da una rappresentazione approssimata dei due addendi ma dalla necessità di incolonnarli per poter procedere all’operazione.

(Se incolonnassi 96,5 (= ,110000012 * 27 ) a 1,75 adeguando l'esponente a 21
poiché 96,5 = ,110000012 * 27 = 110000,012 * 21 perderei così tutte le cifre a sinistra della virgola commettendo un errore molto maggiore!)

 
 

Errore di cancellazione

L’errore di cancellazione si manifesta nel sottrarre due numeri di esponente simile.

Esempio (ipotizzando, per semplicità una mantissa di un solo byte)

Operandi:

15,8 = 1111,(1100)2 = ,111111002 * 24 (rappresentato con errore, valore vero 15.75)
15,5 = 1111,10002 = ,111110002 * 24 (rappresentato esattamente)

Sottrazione:

15,8 = ,111111002 * 24 -
15,5 = ,111110002 * 24 =
          ,000001002 * 24 = .100????? * 2-1

 Il risultato non è normalizzato! Occorre una rinormalizzazione verso sinistra (NB: nel caso del troncamento era verso destra). Le 5 cifre introdotte da destra non sono ottenute dal calcolo e quindi non costituiscono informazione. L’elaboratore introduce di fatto degli zeri, che però non sono significativi, pertanto il risultato è affetto da un errore che ha virtualmente "cancellato", reso inutilizzabili, quelle cifre.

In effetti il risultato apparente, .10000000 * 2-1 = .25 non è corretto, infatti avrebbe dovuto essere 15,8-15,5 = 0,3 = ,10011001 * 2-1.

L’errore di cancellazione è l’effetto finale degli errori e delle approssimazioni precedenti: se si fosse potuto rappresentare 15,8 con infinite cifre, nessuna cifra del risultato sarebbe stata cancellata, e il risultato finale sarebbe stato corretto.

Questo tipo di errore è una delle cause più frequenti della imprecisione nei calcoli con il computer.

 

Errore di arrotondamento

Quando nella rappresentazione di un numero reale anziché troncare la parte frazionaria la si approssima viene commesso un errore di arrotondamento.

Ad esempio (ipotizzando, per semplicità una mantissa di un 4 cifre decimali) il risultato dell’operazione esempio 2/3 che, senza errori, è 0.6666666666... con troncamento delle cifre frazionarie è rappresentato da 0.6666 (con un errore di troncamento pari a 0.0000666666....) mentre con arrotondamento è rappresentato da 0.6667 (con errore di arrotondamento pari a-0.0000333333....)
 

Il C++ arrotonda.

 

Conseguenze degli errori

A causa degli errori di troncamento, arrotondamento, incolonnamento e cancellazione, possono venire meno la proprietà associativa della somma (e della sottrazione).

 

Esempio: (X + Y) - Z ¹ X + (Y - Z)

X = 0,75 = ,11000000 * 20 (rappresentato esattamente)
Y = 65,6 = ,10000011 * 27 (rappresentato con errore di troncamento)
Z = 64,0 = ,10000000 * 27 (rappresentato esattamente)
(X + Y) - Z = 2.35

Primo caso: (X + Y) - Z

Prima operazione: A = X + Y
.11000000 * 20 +.10000011 * 27 =
.00000001 * 27 + .10000011 * 27 =
.10000100 * 27 (err. incolonnamento).

Seconda operazione: R = A - Z
.10000100 * 27 -
.10000000 * 27 =
.00000100 * 27 = (da rinormalizzare)
.100????? * 22 = .10000000 * 22 (errore cancellazione)
.10000000 * 22 =10.000000 = 21  =2,0  

 

Secondo caso: X + (Y - Z) Prima operazione: A = Y - Z
.10000011 * 27 -
.10000000 * 27 =
.00000011 * 27 = (da rinormalizzare)
.11?????? * 21 = (errore cancellazione)
.11000000 * 21  

Seconda operazione: R = X + A
.11000000 * 20 +.11000000 * 21 =
.01100000 * 21 + .11000000 * 21 =
1.00100000 * 21 (da rinormalizzare)
.10010000 * 22
.10010000 * 22 =10.010000 = 21 +2-2 =2,25

La proprietà associativa non è verificata, infatti i risultati sono diversi e coincidono solo sulle prime tre cifre (le uniche significative, in effetti!)

 

Osservazioni sugli errori nei calcoli numerici

I calcoli effettuati con i numeri floating-point possono essere affetti non solo da errori (troncamento/arrotondamento, incolonnamento, cancellazione) sui dati introdotti dal sistema quando le cifre significative sono diverse da quelle ammesse nella rappresentazione, ma anche da errori generati dal particolare algoritmo usato per sviluppare i calcoli.

L’entità degli errori e l’effetto della loro propagazione nei calcoli va tenuta in conto.

Infatti in alcuni algoritmi iterativi la propagazione degli errori durante l’iterazione dei calcoli può portare ad una situazione di instabilità o inaffidabilità dei risultati, mentre altre volte è il problema stesso che essendo mal condizionato può dar luogo ad instabilità e non l’algoritmo che lo risolve.

Ad esempio nel calcolo dell’integrale definito di una funzione per passi, se si sceglie come passo di integrazione  un valore troppo piccolo, nell’intento di aumentare la precisione del risultato, può accadere che il valore della variabile non venga mai incrementato (errore di incolonnamento e successivo troncamento) e il programma entri in loop.

Se n è il valore esatto di un numero (o risultante da un calcolo numerico) ed ñ il valore rappresentato si definisce errore assoluto e = n-ñ ed errore relativo e ¢ = ( n-ñ )/n.

In genere interessa il modulo  sia  dell’errore assoluto |e | sia dell'errore relativo|e’|.

 
 

Osservazione

L'insieme dei numeri reali rappresentabili in virgola mobile comprende lo zero ed un sottoinsieme dei numeri reali compresi negli intervalli [a1,a2] e [-b1,-b2] simmetrici rispetto allo zero.

           b2                                                                             b1        a1                                                                          a2
            ­                                                                               ­         ­                                                                             ­
_______- - - - - - - - - - - - - - - - - - - - - - _ 0 _- - - - - - - - - - - - - - - - - - - - - - ________
                                                                  ­

I valori degli estremi a1,a2,b1,b2 si possono facilmente calcolare assegnando ad m e ad esp i valori minimi e massimi.

 

 

Osservazione
L'insieme dei numeri rappresentabili con questa notazione è un sottoinsieme dei numeri razionali, distribuito in modo non uniforme.

In particolare vi sono valori estremamente vicini fra loro nell'intorno del numero 0 ed estremamente lontani tra loro nell'intorno del massimo numero esprimibile positivo o negativo.

 

Per verificarlo basta calcolare la differenza tra due numeri contigui posti a diversa distanza dall’origine.

Ad esempio (considerando la mantissa di soli 3 bit) i due numeri contigui

0.100* 21 e 0.110*21

distano sull’asse dei reali della quantità: 0.01*21(pari a 0,5)

mentre i numeri

0.100* 23 e 0.110*23

distano sull’asse dei reali della quantità: 0.01*23 (pari a 2)

 

 

Numeri reali nella macchina virtuale C ++

 
 
TIPO BIT VALORI AMMESSI S 

segno

E
esponente
M 

mantissa 

PRECISIONE
floating point 32 

(4 byte)

da .1*2-125 a .11..111*2128» 

2-126¼..... 2128 cioè 

1,2*10-38¼ 3,4*1038

1 bit 8 bit codificato con  
eccesso 126  
(28-1-2) 

 

23 bit 7 cifre
double precision 64 

(8 byte)

da .1*2-1021 
                    .11..11*2 1024» 

2-1022¼ 2 1024cioè 

1.3*10-308¼ 0.7*10308

1 bit 11 bit codificato con  
eccesso 1022  
(211-1-2) 

 

52 bit 15 cifre
long double precision 80 

(10 byte

da 3.4*10-4932 a 1.1*104932 1 bit 15 bit codificato con eccesso 16382 
(215-1-2)
64bit 19 cifre
 

 

Float

 

 

Double

 

Per sapere fisicamente quanto è lunga la rappresentazione in memoria di un unsigned, int, float,... in C++ si usa la funzione sizeof()

 

Nella tabella precedente i valori riportati corrispondono ai simboli a1,a2dell’asse dei reali.
Si noti che la notazione in virgola mobile permette di generare un insieme molto ampio di quello che si sarebbe ottenuto in virgola fissa.