Overflow somma binaria
Ciao a tutti, ho un esercizio in cui devo sommare tra loro due sequenze binarie espresse in IEEE754 in singola precisione.
Mi viene un overflow e non capisco se devo considerarlo o escluderlo?
$ X = 0 | 10000101 | 0010011 ... 0 $
$ Y = 1 | 10000011 | 111001 ... 0 $
Faccio i passaggi di allineamento, complemento a 2, ecc... e ottengo:
$ X = 01,0010011 * 2^6 $
$ Y = 11,10000111 * 2^6 $
Sommo le mantisse:
$ 01,00100110 + 11,10000111 = (1)00,10101101 $
Ora però ottengo OVERFLOW, quello tra parentesi, devo considerarlo oppure no?
Se effettuo la somma in base 10 ottengo $ 43,25 $ che corrisponde proprio al risultato binario convertito in base 10, escludendo però l'overflow.
Mi viene un overflow e non capisco se devo considerarlo o escluderlo?
$ X = 0 | 10000101 | 0010011 ... 0 $
$ Y = 1 | 10000011 | 111001 ... 0 $
Faccio i passaggi di allineamento, complemento a 2, ecc... e ottengo:
$ X = 01,0010011 * 2^6 $
$ Y = 11,10000111 * 2^6 $
Sommo le mantisse:
$ 01,00100110 + 11,10000111 = (1)00,10101101 $
Ora però ottengo OVERFLOW, quello tra parentesi, devo considerarlo oppure no?
Se effettuo la somma in base 10 ottengo $ 43,25 $ che corrisponde proprio al risultato binario convertito in base 10, escludendo però l'overflow.
Risposte
Certo che devi calcolarlo.. L'overflow significa semplicemente che devi poi "aggiustare" l'esponente. Non mi è però chiara la scelta di usare due bit prima della virgola e in quale situazione dovresti fare il complemento a due.
Quindi il risultato della somma sarebbe $ 100,10101101 $ ?
Riguardo al complemento a 2 e i due bit prima della virgola ti mostro i passaggi che non ho inserito nella domanda:
$X = 1,0010011 * 2^6$
$Y = -1,111001 * 2^4$
Allineo $ Y $e ottengo:
$Y = -0,01111001 * 2^6$
Poi, seguendo le slide del corso, viene aggiunto uno 0 per il segno, nonostante non ne capisca esattamente il motivo, perciò:
$X = 01,0010011 * 2^6$
$Y = -00,01111001 * 2^6$
Quindi, applico il complemento a 2; dato che X è positivo e comincia con 0 ok, mentre Y, che è negativo ma comincia con 0, perciò diventa:
$Y = 11,10000111 * 2^6$
Riguardo al complemento a 2 e i due bit prima della virgola ti mostro i passaggi che non ho inserito nella domanda:
$X = 1,0010011 * 2^6$
$Y = -1,111001 * 2^4$
Allineo $ Y $e ottengo:
$Y = -0,01111001 * 2^6$
Poi, seguendo le slide del corso, viene aggiunto uno 0 per il segno, nonostante non ne capisca esattamente il motivo, perciò:
$X = 01,0010011 * 2^6$
$Y = -00,01111001 * 2^6$
Quindi, applico il complemento a 2; dato che X è positivo e comincia con 0 ok, mentre Y, che è negativo ma comincia con 0, perciò diventa:
$Y = 11,10000111 * 2^6$
Non è corretto. Per vederlo conviene tuttavia eliminare la virgola dalla tua notazione moltiplicando e dividendo tutto per \(2^{23}\). Suppongo che i puntini nei tuoi numeri rappresentassero degli zeri. A questo punto ti viene che i numeri sono uguali a:
\[ \begin{align*}
X &= (1001\,0011\,0000\,0000\,0000\,0000)_2 \times 2^{6-23} = (930000)_{16} \times 2^{-17} \\
Y &= - (1111\,0010\,0000\,0000\,0000\,0000)_2 \times 2^{4-23} = - (f20000)_{16} \times 2^{-19}
\end{align*} \]
A questo punto consideri il numero più grande e porti entrambi i numeri allo stesso esponente:
\[ X = (930000)_{16} \times 2^{-17} \quad Y = - (3c8000)_{16} \times 2^{-17} \]
A questo punto, siccome i due esponenti sono uguali, puoi sommare i due valori come se fossero numeri interi. Non è tuttavia sufficiente aggiungere un bit per il segno. Devi infatti aggiungere almeno due bit, uno per il segno e l'altro per fare in modo che la somma venga rappresentata correttamente. Siccome non ho problemi di spazio in questo esempio posso addirittura supporre di usare 32 bit per la somma e quindi sommare \( (00930000)_{16} + (ffc38000)_{16} = (00568000)_{16}. \)
Il tuo risultato è quindi uguale a (a meno di probabili errori di calcolo):
\[ (568000)_{16} \times 2^{-17} = (0.101\,0110\,1000\,0000\,0000\,0000)_2 \times 2^{6} = (1.010\,1101\,0000\,0000\,0000\,0000)_2 \times 2^{5}. \]
Il tuo numero finale in virgola mobile sarà quindi:
\[ (0\;10000100\;01011010000000000000000)_2 = (422d0000)_{16} \]
EDIT: Ho testato il risultato con il seguente codice C e sembra effettivamente corretto:
\[ \begin{align*}
X &= (1001\,0011\,0000\,0000\,0000\,0000)_2 \times 2^{6-23} = (930000)_{16} \times 2^{-17} \\
Y &= - (1111\,0010\,0000\,0000\,0000\,0000)_2 \times 2^{4-23} = - (f20000)_{16} \times 2^{-19}
\end{align*} \]
A questo punto consideri il numero più grande e porti entrambi i numeri allo stesso esponente:
\[ X = (930000)_{16} \times 2^{-17} \quad Y = - (3c8000)_{16} \times 2^{-17} \]
A questo punto, siccome i due esponenti sono uguali, puoi sommare i due valori come se fossero numeri interi. Non è tuttavia sufficiente aggiungere un bit per il segno. Devi infatti aggiungere almeno due bit, uno per il segno e l'altro per fare in modo che la somma venga rappresentata correttamente. Siccome non ho problemi di spazio in questo esempio posso addirittura supporre di usare 32 bit per la somma e quindi sommare \( (00930000)_{16} + (ffc38000)_{16} = (00568000)_{16}. \)
Il tuo risultato è quindi uguale a (a meno di probabili errori di calcolo):
\[ (568000)_{16} \times 2^{-17} = (0.101\,0110\,1000\,0000\,0000\,0000)_2 \times 2^{6} = (1.010\,1101\,0000\,0000\,0000\,0000)_2 \times 2^{5}. \]
Il tuo numero finale in virgola mobile sarà quindi:
\[ (0\;10000100\;01011010000000000000000)_2 = (422d0000)_{16} \]
EDIT: Ho testato il risultato con il seguente codice C e sembra effettivamente corretto:
#include <stdint.h> #include <stdio.h> int main(int argc, char **argv) { union { float f; uint32_t i; } x, y, z; x.i = 0x42930000; y.i = 0xc1f20000; z.f = x.f + y.f; printf("%x\n", z.i); return 0; }
"apatriarca":
Non è corretto. Per vederlo conviene tuttavia eliminare la virgola dalla tua notazione moltiplicando e dividendo tutto per \(2^{23}\). Suppongo che i puntini nei tuoi numeri rappresentassero degli zeri. A questo punto ti viene che i numeri sono uguali a:
\[ \begin{align*}
X &= (1001\,0011\,0000\,0000\,0000\,0000)_2 \times 2^{6-23} = (930000)_{16} \times 2^{-17} \\
Y &= - (1111\,0010\,0000\,0000\,0000\,0000)_2 \times 2^{4-23} = - (f20000)_{16} \times 2^{-19}
\end{align*} \]
Ciao, intanto grazie della risposta!
Non capisco però perchè riscrivi $ X $ e $ Y $ in questo modo e poi li converti in base 16.
Non è più semplice lavorare con la virgola come stavo facendo io? (almeno per me)
E cosa c'è di sbagliato nel mio procedimento?
Grazie ancora!

L'unica ragione per cui puoi fare il complemento a due è che tratti i due numeri come interi moltiplicati per la stessa potenza di due. Puoi anche scriverli con la virgola, ma devi stare attento ad avere un numero sufficiente di bit prima del bit di segno. Devi insomma inserire due zeri prima di fare il complemento a due. L'eventuale overflow andrà poi scartato. Nota comunque che il numero così scritto non ha senso, sarebbe solo un modo per considerare meno bit.. Il passaggio alla base 16 è in effetti solo per scrivere meno valori.
Ok, credo di aver capito! Un'altra cosa, se ho overflow, ad esempio nel caso che ti ho riportato sopra, cioè
$ 01,00100110+11,10000111= (1)00,10101101 $
l'overflow (tra parentesi) lo scarto, quindi il segno del risultato è positivo?
$ 01,00100110+11,10000111= (1)00,10101101 $
l'overflow (tra parentesi) lo scarto, quindi il segno del risultato è positivo?
Come ti ho detto, hai bisogno di due bit, non uno. Per vedere che hai bisogno di un bit aggiuntivo considera il seguente esempio con un solo bit: \(01,0 + 01,0 = 10,0\). Da questa somma verrebbe fuori un numero negativo, ma il risultato è ovviamente errato.. Avendo due bit avresti invece \(001,0 + 001,0 = 010,0\) che è il risultato corretto. Discorso simile vale per la somma numeri negativi: \( 11,0 + 11,0 = (1)10,0 \). Aggiungendo un bit ulteriore prima di fare il complemento a due avrebbe risolto anche questo caso: \( 111,0 + 111,0 = (1)110,0. \)
Lo scarto va a quel punto trattato nello stesso modo in cui tratteresti quello nella somma tra due numeri in complemento a due.
Lo scarto va a quel punto trattato nello stesso modo in cui tratteresti quello nella somma tra due numeri in complemento a due.