[MIPS] Somma di due numeri formato IEEE754
Salve, sto facendo degli esercizi di "architettura degli elaboratori" e mi trovo davanti a questo quesito:
Scrivere un programma MIPS per calcolare la somma di A e B, supponendo che siano memorizzati nel formato IEEE 754.
(‐1)S•(1+m)•2(e ‐ polarizzazione)
Sapete dirmi la soluzione? Come faccio a gestire con le istruzioni previste dal MIPS numeri nel formato IEEE754. Immagino debba controllare il "peso" dell'esponente ed eventualmente convertire uno dei due numeri. O sono fuori traccia?
Avete qualche idea?
Grazie!
Scrivere un programma MIPS per calcolare la somma di A e B, supponendo che siano memorizzati nel formato IEEE 754.
(‐1)S•(1+m)•2(e ‐ polarizzazione)
Sapete dirmi la soluzione? Come faccio a gestire con le istruzioni previste dal MIPS numeri nel formato IEEE754. Immagino debba controllare il "peso" dell'esponente ed eventualmente convertire uno dei due numeri. O sono fuori traccia?
Avete qualche idea?
Grazie!
Risposte
Nessuno è in grado di aiutarmi?
L'idea di base è quella di portare i due numeri nello stesso esponente aggiungendo il bit implicito nella notazione in modo da essere in grado di sommarli. Ci sono però diversi dettagli a complicare il tutto come il bit del segno, gli infiniti, gli zeri, NaN e i numeri denormalizzati. Inizia a provare a scrivere una versione che funziona con i numeri positivi "normali" e poi vediamo di aggiungere il resto.
Con numeri normali non c'è molto da scrivere. Se assegno A e B rispettivamente a $s0 e $s1 (e somma in $s2), le istruzioni da scrivere solo soltanto queste:
...che dovrebbero corrispondere al seguente codice in C:
Tra l'altro possa anche evitare di azzerare $s2...
add $s2, $zero, $zero lw $s0, 1000($zero) lw $s1, 2000($zero) addu $s2, $s0, $s1
...che dovrebbero corrispondere al seguente codice in C:
somma = 0; somma = a + b;
Tra l'altro possa anche evitare di azzerare $s2...
Non hai capito quello che intendevo. Parlavo di valori floating point positivi.
"apatriarca":
Non hai capito quello che intendevo. Parlavo di valori floating point positivi.
Nell'esempio che ho scritto sono positivi, infatti eseguo l'istruzione addu, anzichè add che interpreta i numeri come unsigned, cioè senza segno, quindi positivi. O mi sbaglio?
Nel frattempo mi sono bloccato ad un altro esercizio: ovvero la somma di due numeri esadecimali in floatinf point.
Cioè, dati 2 numeri in Hex, convertirli in binario e leggerli come se fossero in FP. Ottenuti i due numeri FP, sommarli.
I due numeri esadecimali sono:
A = C3160000 e B = 42F80000, che tradotti in binario (e interpretati come FP) sono:
A = 1 10000110 00101100000000000000000
B = 0 10000101 11110000000000000000000
Ebbene come faccio la somma dal momento che gli esponenti (10000110 e 10000101) non sono uguali?
L'eventuale procedimento per risolvere il problema è lo stesso che va applicato nel programma MIPS dell'esercizio precedente?
Se gli esponenti non sono uguali riconduci B all' esponente che ha A.
A ha come esponente 135 (cioè 7), B 133 (cioè 5).
Se in r1 ci metti la mantissa di A, in r2 ci metti la mantissa di B shiftata di due posizioni a destra.
(ri è un registro generico)
Poi fai la somma.
Il risultato avrà esponente sempre 7, ma con la mantissa cambiata.
A ha come esponente 135 (cioè 7), B 133 (cioè 5).
Se in r1 ci metti la mantissa di A, in r2 ci metti la mantissa di B shiftata di due posizioni a destra.
(ri è un registro generico)
Poi fai la somma.
Il risultato avrà esponente sempre 7, ma con la mantissa cambiata.
"ramy1989":
Se gli esponenti non sono uguali riconduci B all' esponente che ha A.
A ha come esponente 135 (cioè 7), B 133 (cioè 5).
Se in r1 ci metti la mantissa di A, in r2 ci metti la mantissa di B shiftata di due posizioni a destra.
(ri è un registro generico)
Poi fai la somma.
Il risultato avrà esponente sempre 7, ma con la mantissa cambiata.
L'esponente di A è 134 (cioè 7) e l'esponente di B è 133 (cioè 6).
Tralasciando per un momento il programma in MIPS, come faccio matematicamente a sommare due numeri binari che sono espressi in FP (floating point)?
Seguendo la formula (‐1)S•(1+m)•2^(e ‐ polarizzazione) ottengo:
-1,001011 * 2^7
1,1111 * 2^6
Come li sommo?
Già, avevo sbagliato le conversioni.
Puoi sommare due float se hanno la stessa base, quindi puoi:
-Trasformare \(-1.001011 \cdot 2^7 \) in \(-2.002022 \cdot 2^6\) ;
-Sommarli (il risultato sarà \(0.890922 \) (se non hai sbagliato le conversioni)).
-Ora \(0.890922\) (ha esponente 6) è minore di 1, per cui lo moltiplichi per due e ottieni:
\(-1.781844 \), con esponente 5.
Il risultato è un float che ha come segno \(-1\), come esponente \(5\), e come mantissa \(1.781844\).
Puoi sommare due float se hanno la stessa base, quindi puoi:
-Trasformare \(-1.001011 \cdot 2^7 \) in \(-2.002022 \cdot 2^6\) ;
-Sommarli (il risultato sarà \(0.890922 \) (se non hai sbagliato le conversioni)).
-Ora \(0.890922\) (ha esponente 6) è minore di 1, per cui lo moltiplichi per due e ottieni:
\(-1.781844 \), con esponente 5.
Il risultato è un float che ha come segno \(-1\), come esponente \(5\), e come mantissa \(1.781844\).
"ramy1989":
Già, avevo sbagliato le conversioni.
Puoi sommare due float se hanno la stessa base, quindi puoi:
-Trasformare \(-1.001011 \cdot 2^7 \) in \(-2.002022 \cdot 2^6\) ;
-Sommarli (il risultato sarà \(0.890922 \) (se non hai sbagliato le conversioni)).
-Ora \(0.890922\) (ha esponente 6) è minore di 1, per cui lo moltiplichi per due e ottieni:
\(-1.781844 \), con esponente 5.
Il risultato è un float che ha come segno \(-1\), come esponente \(5\), e come mantissa \(1.781844\).
Ma non bisogna portare l'esponente uguale a quello più grande tra i due? Cioè \(2^7\)?
Si può fare anche così, basta che quando li sommi hanno lo stesso esponente (attenzione che questo non vale anche per la divisione).
Posso trasformare \(1.1111 \cdot 2^6 \) in \(0.55555 \cdot 2^7\).
Ora lo sommo a \(1.001011 \cdot 2^7\) , ottengo \(-0.445461 \cdot 2^7\).
Devo farlo essere maggiore di 1 perchè la mantissa di un floating point IEEE 754 è sempre maggiore di 1, quindi lo moltiplico per 4 e scalo l' esponente di 2, ottengo sempre \(1.781844 \cdot 2^5\).
Posso trasformare \(1.1111 \cdot 2^6 \) in \(0.55555 \cdot 2^7\).
Ora lo sommo a \(1.001011 \cdot 2^7\) , ottengo \(-0.445461 \cdot 2^7\).
Devo farlo essere maggiore di 1 perchè la mantissa di un floating point IEEE 754 è sempre maggiore di 1, quindi lo moltiplico per 4 e scalo l' esponente di 2, ottengo sempre \(1.781844 \cdot 2^5\).
La questione è assai più semplice di come sembrate affrontarla, pe.
http://www.cs.umd.edu/class/sum2003/cms ... Float.html
Fra l'altro il corso è interessante, date un'occhiata
http://www.cs.umd.edu/class/sum2003/cmsc311/
http://www.cs.umd.edu/class/sum2003/cms ... Float.html
Fra l'altro il corso è interessante, date un'occhiata
http://www.cs.umd.edu/class/sum2003/cmsc311/
L' algoritmo Che hai linkato e' lo stesso Che ho applicato io.
Grazie per le vostre risposte.
E se volessi rappresentare tale numero in notazione virgola fissa (con n=8, m=8)?
"ramy1989":
ottengo sempre \(1.781844 \cdot 2^5\).
E se volessi rappresentare tale numero in notazione virgola fissa (con n=8, m=8)?
n e m cosa rappresentano?
"ramy1989":
n e m cosa rappresentano?
La parte intera e decimale del numero binario.
In poche parole voglio convertire in virgola fissa su 16 bit (8 per la parte intera e 8 per la parte decimale) il numero postato sopra che è espresso in virgola mobile.
Se voglio rappresentare \(1.781844 \cdot 2^5\) innanzitutto calcolo il suo valore:
\(57.019008\)
Poi converto la parte intera (questo penso sia facile per tutti):
\((57)_{10}=(00111001)_{2}\)
Ora converto la parte frazionaria:
\(a=0.019008\) verrà rappresentato con 8 bit, con \(b_0 \cdots b_7\) che calcolo così :
a=0.019008 , i =0;
Finchè i<8 :
- Moltiplico a per 2;
- Se a è minore o uguale a 1 -> a=a-1 ,\(b_i\)=1
altrimenti -> \(b_i\)=0;
- i=i+1;
Il risultato è: \(00000100\)
E' da notare che:
- \(00000100\) non rappresenta il numero reale 0.01900, ma 0.015625, c'è quindi un errore relativo pari a \(-3.383 \cdot 10^-3\);
-L' errore relativo è sempre inferiore in modulo alla precisione della rappresentazione che si ha, quindi in questo caso è inferiore a \(2^{-8}\);
-Usando la rappresentazione finita si possono sommare due numeri senza particolari accorgimenti, si può semplicemente fare la somma bit a bit riportando i resti;
E' sicuramente una rappresentazione più comoda per noi, ma non per una macchina, che preferisce usare i floating point.
\(57.019008\)
Poi converto la parte intera (questo penso sia facile per tutti):
\((57)_{10}=(00111001)_{2}\)
Ora converto la parte frazionaria:
\(a=0.019008\) verrà rappresentato con 8 bit, con \(b_0 \cdots b_7\) che calcolo così :
a=0.019008 , i =0;
Finchè i<8 :
- Moltiplico a per 2;
- Se a è minore o uguale a 1 -> a=a-1 ,\(b_i\)=1
altrimenti -> \(b_i\)=0;
- i=i+1;
Il risultato è: \(00000100\)
E' da notare che:
- \(00000100\) non rappresenta il numero reale 0.01900, ma 0.015625, c'è quindi un errore relativo pari a \(-3.383 \cdot 10^-3\);
-L' errore relativo è sempre inferiore in modulo alla precisione della rappresentazione che si ha, quindi in questo caso è inferiore a \(2^{-8}\);
-Usando la rappresentazione finita si possono sommare due numeri senza particolari accorgimenti, si può semplicemente fare la somma bit a bit riportando i resti;
E' sicuramente una rappresentazione più comoda per noi, ma non per una macchina, che preferisce usare i floating point.
Ciao ramy1989, grazie per la tua esauriente spiegazione!
Ho però avuto un problema a fare un esercizio, che adesso non trovo più, per il quale non sapevo come convertirlo in binario virgola fissa, perchè il numero era qualcosa moltiplicato per 2^113 mi pare. In questo caso come converto in virgola fissa se non ho un numero decimale da scindere in parte intera e frazionaria?
Ho però avuto un problema a fare un esercizio, che adesso non trovo più, per il quale non sapevo come convertirlo in binario virgola fissa, perchè il numero era qualcosa moltiplicato per 2^113 mi pare. In questo caso come converto in virgola fissa se non ho un numero decimale da scindere in parte intera e frazionaria?
\(2^{113}\) è un numero intero, ma appartiene anche all' insieme dei numeri reale perchè sarebbe un numero lunghissimo seguito da .0 ; 8 cifre non ti bastano per memorizzare la parte intera, ti servono almeno 114 cifre,ecco perchè la notazione floating point è più usata di quella in virgola fissa.
In virgola fissa ti servirebbero 114 cifre, facciamo 128 così abbiamo 16 byte per la parte intera e 16 byte per la parte frazionaria.
La parte frazionaria sarebbe semplicemente una stringa di tutti zeri.
Mentre la parte intera sarebbe una stringa in cui solo il 114-esimo bit sarebbe positivo, e tutti gli altri uguali a zero.
E ti serverebbeo 32 byte, mentre ti basterebbero i 4 byte di un float per rappresentarlo interamente,perchè l' esponente può arrivare fino a 255 cioè (sottraendogli il bias) con una mantissa uguale a 1.99999 potrebbe arrivare a rappresentare al massimo un numero \(\approx2^{129}\).
In virgola fissa ti servirebbero 114 cifre, facciamo 128 così abbiamo 16 byte per la parte intera e 16 byte per la parte frazionaria.
La parte frazionaria sarebbe semplicemente una stringa di tutti zeri.
Mentre la parte intera sarebbe una stringa in cui solo il 114-esimo bit sarebbe positivo, e tutti gli altri uguali a zero.
E ti serverebbeo 32 byte, mentre ti basterebbero i 4 byte di un float per rappresentarlo interamente,perchè l' esponente può arrivare fino a 255 cioè (sottraendogli il bias) con una mantissa uguale a 1.99999 potrebbe arrivare a rappresentare al massimo un numero \(\approx2^{129}\).
Scusate ma voglio riniziare da capo. Questo è l'esercizio (ormai il MIPS c'entra ben poco):
Dati i due numeri esadecimali A=C3160000 e B=42F80000
1. tradurre i numeri in binario
2. interpretare le sequenze di bit ottenuti come numeri FP espressi secondo lo standard IEEE754 in singola precisione
3. eseguirne poi la somma specificando tutti i passaggi
4. rappresentare il risultato ottenuto in esadecimale
Mia soluzione:
1.
\(A = 11000011000101100000000000000000\)
\(B = 01000010111110000000000000000000\)
2.
\(A =\)
Segno: \(1\)
Esponente: \(10000110_{2} = 134_{10}\)
Mantissa: \(.001011_{2} = 0,171875_{10}\)
\((-1)^S \cdot (1 + m) \cdot 2^{e-BIAS}\)
\((-1)^1 \cdot (1 + 0,171875) \cdot 2^{134-127}\)
\(-1,171875 \cdot 2^{7}\)
\(B =\)
Segno: \(0\)
Esponente: \(10000101_{2} = 133_{10}\)
Mantissa: \(.1111_{2} = 0,9375_{10}\)
\((-1)^S \cdot (1 + m) \cdot 2^{e-BIAS}\)
\((-1)^0 \cdot (1 + 0,9375) \cdot 2^{133-127}\)
\(1,9375 \cdot 2^{6}\)
3.
???
Come si fa il terzo passaggio?
Dati i due numeri esadecimali A=C3160000 e B=42F80000
1. tradurre i numeri in binario
2. interpretare le sequenze di bit ottenuti come numeri FP espressi secondo lo standard IEEE754 in singola precisione
3. eseguirne poi la somma specificando tutti i passaggi
4. rappresentare il risultato ottenuto in esadecimale
Mia soluzione:
1.
\(A = 11000011000101100000000000000000\)
\(B = 01000010111110000000000000000000\)
2.
\(A =\)
Segno: \(1\)
Esponente: \(10000110_{2} = 134_{10}\)
Mantissa: \(.001011_{2} = 0,171875_{10}\)
\((-1)^S \cdot (1 + m) \cdot 2^{e-BIAS}\)
\((-1)^1 \cdot (1 + 0,171875) \cdot 2^{134-127}\)
\(-1,171875 \cdot 2^{7}\)
\(B =\)
Segno: \(0\)
Esponente: \(10000101_{2} = 133_{10}\)
Mantissa: \(.1111_{2} = 0,9375_{10}\)
\((-1)^S \cdot (1 + m) \cdot 2^{e-BIAS}\)
\((-1)^0 \cdot (1 + 0,9375) \cdot 2^{133-127}\)
\(1,9375 \cdot 2^{6}\)
3.
???
Come si fa il terzo passaggio?
Vedi anche i link che avevo postato prima, mi sembra ben spiegato.