2 Dia per pagina

Transcript

2 Dia per pagina
Somma di numeri floating point
Algoritmi di moltiplicazione e divisione per
numeri interi
Standard IEEE754
"
Standard IEEE754: Singola precisione (32 bit)
si riescono a rappresentare numeri 2.010 • 2-38 ÷ 2.010 • 238
"
Standard IEEE754: Doppia precisione (64 bit)
si riescono a rappresentare numeri 2.010 • 2-308 ÷ 2.010 • 2308
Standard IEEE754
Lo standard IEEE754 sceglie di:
"
"
rendere d0 = 1 implicito, mettendo un circuito che somma
automaticamente 1 alla cifra espressa dalla mantissa.
usare la notazione polarizzata per rappresentare l’esponente:
essa consente di ordinare e confrontare gli esponenti in modo
facile
- Singola precisione: polarizzazione pari a 127 = 011111112
- Doppia precisione: polarizzazione pari a 1023 = 011111111112
riservare l’esponente 00...0 per rappresentare lo zero
" riservare l’esponente 11...1 per casi particolari
(fuori dall’insieme dei valori rappresentabili)
"
Standard IEEE754
Per leggere un numero in notazione polarizzata si usa la regola:
(-1)S•(1+m)•2(e - polazizzazione)
Esempio: Quale numero decimale rappresenta la seguente sequenza di bit,
letta secondo lo standard IEEE754?
esponente: 100011012 = 128+8+4+1=14110
mantissa: 1+0.100112 = 1+0.59375 = 1.5937510
Quindi il numero è: 1.5937510 • 2(141 - 127) = 1.5937510 • 214
Standard IEEE754
Per scrivere un numero in notazione polarizzata bisogna ricordarsi di:
" non rappresentare la parte intera della mantissa
(il bit 1 prima della virgola)
" aggiungere all’esponente la polarizzazione
Esempio: scrivere - 10. 62510 in notazione floating point, usando lo
standard IEEE754
- 10. 62510 = - (10 + 0.5 +0.125) = - (10 + 1/2 + 1/8) =
= - 1010. 1012 = - 1. 010101 • 23 =
= (-1)1 • (1 + 0.010101) • 2(3+127)
= (-1)1 • (1 + 0.010101) • 2(130)
Somma di numeri razionali in virgola mobile
Algoritmo che esegue la somma
di due numeri razionali :
Esempio: eseguire 510 + 3.62510
assumendo una precisione di 4 bit
510 = 1012 = 1.01 • 22
3.62510 = 11.1012• 20 = 1.1101• 21
= 0.11101• 22
Allora: 1.01000 +
0.11101 =
---------------10.00101 • 22
Normalizzazione: 1.000101 • 23
Arrotondamento: 1.0001 • 23
Somma di numeri razionali in virgola mobile
Esercizio: eseguire la somma di
+
Somma di numeri razionali in virgola mobile
Somma di numeri razionali in virgola mobile
La limitatezza della precisione dell’aritmetica dei calcolatori porta ad avere dei
problemi con le proprietà delle operazioni aritmetiche.
Ad esempio, la somma in virgola mobile non è associativa, cioè, in generale, non è
vero che x+(y+z) = (x+y)+z
I problemi nascono quando si vogliono sommare due numeri molto grandi di segno
opposto, con altro un numero molto piccolo
x = 1.510 • 1038
y = - 1.510 • 1038
z = 1.010
con x,y,z espressi in singola precisione
x+(y+z) = -1.5 • 1038 + (1.5 • 1038 + 1.0)
= -1.5 • 1038 + 1.5 • 1038 = 0.010
(x+y)+z = ( -1.5 • 1038 + 1.5 • 1038 ) + 1.0
= 0.0 + 1.0 = 1.010
Moltiplicazioni e divisioni tra numeri interi
Abbiamo visto che le ALU sono in grado di eseguire operazioni di
somma
sottrazione
salto
confronto
operazioni logiche: AND e OR
Ma ci sono altre due operazioni fondamentali che devono essere
implementate: MOLTIPLICAZIONE e DIVISIONE di numeri interi
Vediamo come vengono realizzate...
Moltiplicazione tra numeri interi
Come funziona l’algoritmo “carta e penna” per la moltiplicazione ?
105 *
204 =
---------
420
000
210
---------21420
Moltiplicando
Moltiplicatore
Prodotto
I passi dell’algoritmo sono i seguenti :
considerare le cifre del moltiplicatore una alla volta, da destra a sinistra
" moltiplicare il moltiplicando per la singola cifra del moltiplicatore
" scalare il prodotto intermedio di una cifra alla volta verso sx
rispetto ai precedenti prodotti intermedi ottenuti
" il prodotto si ottiene dalla somma di tutti i prodotti intermedi
"
Moltiplicazione tra numeri interi
Cosa succede in base 2 ?
1011 *
101 =
---------
1011
0000
1011
---------110111
Moltiplicando 1110
Moltiplicatore 510
Prodotto 5510
Osservazioni:
" il numero delle cifre del prodotto è molto più grande rispetto alle
cifre del moltiplicatore e del moltiplicando.
Ignorando i bit di segno si ha:
moltiplicatore (n bit) moltiplicando (m bit) ==> prodotto (n+m bit)
" Poichè si vogliono rappresentare sia gli operandi che il risultato
delle operazioni su 32 bit bisogna fare attenzione ai casi di
OVERFLOW !
Moltiplicazione tra numeri interi
Cosa succede in base 2 ?
1011 *
101 =
---------
1011
0000
1011
---------110111
Moltiplicando 1110
Moltiplicatore 510
Prodotto 5510
Osservazioni: (continua)
" Poichè ci sono solo le cifre 0 e 1 ogni passo della moltiplicazione
viene semplificato
- si mette una copia del moltiplicando nella posizione opportuna
se la cifra “corrente” del moltiplicatore è 1
- si mette 0 in posizione opportuna se la cifra corrente del
moltiplicatore è 0
Moltiplicazione tra numeri interi (primo algoritmo)
Si basa su:
" shift a destra del moltiplicatore per
considerare, una alla volta, tutte le
sue cifre (dalla meno significativa
alla più significativa)
" shift a sinistra del moltiplicando per
rappresentare correttamente i
prodotti parziali
Moltiplicando Moltiplicatore Prodotto
1011
1011
10110
10110
101100
101100
1011000
1011000
10110000
0101
0101
0010
0010
0001
0001
0000
0000
0000
0000
1011
1011
1011
1011
110111
110111
110111
110111
Moltiplicazione tra numeri interi (primo algoritmo)
Il circuito che implementa l’algoritmo della pagina precedente ? :
Moltiplicazione tra numeri interi (secondo algoritmo)
Il primo algoritmo di moltiplicazione usa un registro a 64bit per il moltiplicando e,
conseguentemente, una ALU a 64bit per la somma
Infatti, Il moltiplicando viene scalato a sinistra di una cifra ad ogni passo,
in modo da non influenzare i bit meno significativi del prodotto
Il secondo algoritmo, invece, per arrivare allo stesso obiettivo, prevede
di scalare il prodotto a destra
In tal modo il moltiplicando può restare fisso e quindi sono necessari
solo 32bit sia per corrispondente registro che per la ALU
Risultato: il circuito diventa più semplice e la moltiplicazione più veloce
Vediamo in dettaglio il secondo algoritmo:
Moltiplicazione tra numeri interi (secondo algoritmo)
Si basa su:
" shift a destra del moltiplicatore per
considerare, una alla volta, tutte le
sue cifre (dalla meno significativa
alla più significativa)
" shift a destra del prodotto per
non influenzare le cifre meno
significative dei prodotti parziali
" ad ogni passo vengono sommati
solo i 32bit più significativi del
prodotto
Moltiplicando Moltiplicatore Prodotto
0101
1011
00000000
0101
1011
10110000
1011
0010
01011000
1011
0010
01011000
1011
0001
00101100
1011
0001
11011100
1011
0000
01101110
1011
0000
01101110
1011
0000
00110111
Moltiplicazione tra numeri interi (secondo algoritmo)
Il circuito che implementa il secondo algoritmo per la moltiplicazione è:
Moltiplicazione tra numeri interi (terzo algoritmo)
Il secondo algoritmo spreca inizialmente i 32bit bassi del prodotto, che sono
esattamente lo spazio necessario per memorizzare il moltiplicatore
Man mano che lo spazio sprecato del prodotto diminuisce (per via dello shift a
destra) diminuiscono anche le cifre significative del moltiplicatore
Il terzo algoritmo prevede quindi la memorizzazione del moltiplicatore
nella parte bassa del prodotto
Con questa soluzione:
"
"
si elimina un registro (quello che prima memorizzava il moltiplicatore)
il test sulla cifra del moltiplicatore da considerare ad ogni passo
diventa il test sul bit meno significativo del prodotto
Vediamo nei dettagli il terzo (e ultimo!!!) algoritmo per la moltiplicazione...
Moltiplicazione tra numeri interi (terzo algoritmo)
Si basa su:
" memorizzazione del moltiplicatore
nella parte bassa del prodotto
" shift a destra del prodotto per
non influenzare le cifre meno
significative dei prodotti parziali
" ad ogni passo vengono sommati
solo i 32bit più significativi del
prodotto
Moltiplicando
1011
1011
1011
1011
1011
1011
1011
1011
1011
Prodotto
00000101
10110101
01011010
01011010
00101101
11011101
01101110
01101110
00110111
Moltiplicazione tra numeri interi (terzo algoritmo)
Il circuito che implementa il terzo algoritmo per la moltiplicazione è:
Moltiplicazione tra numeri interi
Fino ad ora NON abbiamo considerato il SEGNO di moltiplicando e
moltiplicatore
Il modo più semplice di gestire il segno è il seguente:
convertire moltiplicando e moltiplicatore in numeri positivi
" eseguire il la moltiplicazione
" stabilire il segno del prodotto secondo la regola dei segni,
ricordando i segni originali
"
ATTENZIONE: gli algoritmi possono effettuare solo 31 iterazioni, lasciando i
segni fuori dal calcolo
Divisione tra numeri interi
Come funziona l’algoritmo di divisione “carta e penna” ?
Dividendo Divisore
100
: 6
=
10
06
40
36
4 Resto
Quoziente
016
Si ha: Dividendo = Quoziente * Divisore + Resto
da cui: Resto = Dividendo - Quoziente * Divisore
I passi dell’algoritmo sono i seguenti:
" considerare le cifre del dividendo, partendo dalla cifra più significativa
" vedere quante volte il divisore sta nel gruppo di cifre del dividendo
" scrivere la cifra corrispondente nel quoziente
" sottrarre il multiplo del divisore dal dividendo
" alla fine il resto è minore del divisore
ATTENZIONE: la divisione per ZERO causa errore
Divisione tra numeri interi
Cosa succede in base 2 ?
Dividendo Divisore Quoziente
1101001 : 101 = 0010101
11
110
101
11
110
101
10
101
101
0 Resto
Osservazioni:
" Quante volte il divisore sta nella porzione di dividendo considerata?
Ci sono solo due alternative: 0 volte oppure 1 volta
Questo semplifica l’algoritmo di divisione
" Consideriamo per ora solo numeri positivi
Divisione tra numeri interi (primo algoritmo)
Supponiamo di dover dividere 11012 : 01012 ( cioè 1310 : 510 )
Il primo algoritmo di divisione procede come segue:
" quoziente memorizzato su un registro a 32 bit e inizializzato a zero
quoziente = 0000
" divisore memorizzato sulla parte alta di un registro a 64 bit
divisore = 01010000
" resto memorizzato su reg. a 64 bit, inizializzato col valore del dividendo
resto = 00001101 = dividendo
il calcolatore non capisce “al volo” quando il divisore è più piccolo della
porzione di dividendo considerata. Ad ogni passo fa la sottrazione
(dividendo - divisore) e controlla il segno del risultato
" ad ogni passo si esegue lo shift a destra di una posizione del divisore
"
resto = 00001101
resto = 00001101 resto = 00001101
divisore = 01010000
divisore = 00101000 divisore = 00010100
10111101
11100101
11111001
se il segno è positivo ==> shift a sinistra del quoziente e inserimento di 1
se il segno è negativo ==> shift a sinistra del quoziente e inserimento di 0
+ ripristino del valore precedente di resto
Divisione tra numeri interi (primo algoritmo)
Resto
00001011
01010000
10111101
00001011
00101000
11100101
00001011
00010100
11111001
00001011
00001010
00000011
00000101
11111110
00000011
Divisore
Quoziente
01010000
0000
00101000
0000
00010100
0000
00001010
0000
00000101
0001
00000010
0010
Divisione tra numeri interi (primo algoritmo)
Il circuito che implementa il primo algoritmo è il seguente:
Divisione tra numeri interi (altri algoritmi)
"
"
"
Analogamente al caso della moltiplicazione, sono stati studiati dei
raffinamenti per l’algoritmo della divisione
L’obiettivo è sempre quello di semplificare e rendere più veloce il
circuito che implementa la divisione
Vediamo solo le modifiche ai circuiti, e non gli algoritmi in dettaglio
(li trovate comunque sul libro di testo)
Divisione tra numeri interi (secondo algoritmo)
Circuito relativo al secondo algoritmo:
Divisione tra numeri interi (terzo algoritmo)
Circuito relativo al terzo algoritmo:
Divisione tra numeri interi
Fino ad ora non abbiamo considerato il SEGNO di dividendo e divisore
Analogamente al caso della moltiplicazione, il modo più semplice di
gestire il segno è il seguente:
"
convertire dividendo e divisore in numeri positivi
"
eseguire la divisione lasciando i bit di segno fuori dal calcolo
"
"
stabilire il segno del quoziente mediante la regola dei segni,
ricordando i segni originali (quoziente negativo se i segni di dividendo
e divisore sono discordi, positivo altrimenti)
stabilire il segno del resto mediante la seguente regola:
dividendo e resto devono avere lo stesso segno, indipendentemente
dal segno del divisore e del quoziente