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