Lo standard IEEE 754 Standard for Binary Floating-Point Arithmetic definisce il formato a virgola mobile per il calcolo automatico.
La rappresentazione con virgola mobile è un modo per rappresentare numeri reali (compresi quelli con parte frazionaria) in sistemi di calcolo che lavorano con numeri interi.
Questo standard ha diversi formati, i più importanti sono a singola precisione (32 bit) e il formato doppia precisione (64 bit).
Entrambi i formati hanno una parte dedicata al segno, una all'esponente e una alla mantissa che è proprio quella che varia, rispettivamente 23 e 52 bit.
Vediamo il caso dei 32 bit, la stringa è rappresentata in questo modo:
1 8 23 (bit)
+----+--------+-----------------------+
| S | X | M |
+----+--------+-----------------------+
Nella stringa è presente:
- Segno: 0 se il numero è positivo e 1 se è negativo.
- X (esponente)
- M (mantissa)
Per convertire un numero decimale nello standard IEEE 754 inizialmente dobbiamo convertirlo in binario.
Facciamo un esempio con il numero 22,31.
Convertiamo in binario il numero 22:
: 2
22 | 0
11 | 1 /\
5 | 1 | |
2 | 0 | | lettura
1 | 1 | |
0 |
Risultato: 10110
.
Convertiamo in binario il numero 31 dopo la virgola (quindi moltiplichiamo):
x 2
0,31 | 0
0,62 | 1
0,24 | 0 | |
0,48 | 0 | | lettura
0,96 | 1 | |
0,92 | 1 \/
0,84 | ...
Risultato: 010011
Il numero 22,31 in binario è: 10110,010011
Scriviamo la notazione scientifica del numero:
1,0110010011 x 24
Ora che conosciamo la potenza possiamo calcolare X (esponente) in decimale usando la formula X = E (potenza) + 127
.
Perché proprio 127? Essendo che l'esponente ha 8 bit può restituire 256 valori, in particolare tra -126 e 127 in modo da poter convertire anche numeri molto grandi.
In questo caso X = 4 + 127 = 131
.
Convertiamo il numero 131 in binario:
: 2
131 | 1
65 | 1 /\
32 | 0 | |
16 | 0 | | lettura
8 | 0 | |
4 | 0
2 | 0
1 | 1
0 |
Risultato: 10000011
Ora siamo pronti a scrivere il numero nello standard IEEE 754:
Ora che abbiamo visto il procedimento per la conversione proviamo a scrivere un programma in C++ che usando la virgola mobile converta un numero nello standard.
L'utente inizialmente dovrà fornire un numero binario come input e tramite cin lo memorizza nella variabile input.
Il primo bit del binario fornito determina il segno: se è '1' il segno è '0' cioè positivo. Se è '0' il segno è '1', negativo.
Usiamo un while
che legge i caratteri del binario fino alla virgola (o la fine del numero). In questo modo si può costruire la parte intera (pI). La parte frazionaria (pF) viene costruita con un secondo ciclo che memorizza i caratteri dopo la virgola.
Per semplificarci un calcolo inutile la parte X (esponente) viene calcolato sommando 127 alla posizione della virgola -1.
bin
converte l'esponente calcolato in binario (in questo caso il 131). La stringa binaria subito dopo viene invertita perché la lettura va dal basso verso l'alto.
La mantissa è il concatenamento della parte intera e frazionaria del numero binario e infine abbiamo il cout dove vengono restituiti i risultati.
#include <iostream>
using namespace std;
int bin(int n,char binario[]) {
int l=0;
while (n>0) {
binario[l++]=(n % 2 == 0)?'0':'1';
n=n/2;
}
return l;
}
int main() {
char input[50];
char pI[50];
char pF[50];
char eB[50];
char mant[50];
cout<<"Inserisci un numero binario: ";
cin>>input;
char segno=(input[0]=='1')?'0':'1';
int posVirgola=0;
while (input[posVirgola]!=','&&input[posVirgola]!='\0') {
pI[posVirgola]=input[posVirgola];
posVirgola++;
}
pI[posVirgola]='\0';
int pos=posVirgola+1;
int lParteFrazionaria=0;
while (input[pos]!='\0') {
pF[lParteFrazionaria++]=input[pos++];
}
pF[lParteFrazionaria]='\0';
int esponente=posVirgola-1 + 127;
int lEsponente=bin(esponente, eB);
eB[lEsponente]='\0';
for (int i=0, j=lEsponente-1; i<j; i++, j--) {
char temp=eB[i];
eB[i]=eB[j];
eB[j]=temp;
}
int lMantissa=0;
for (int i=1; pI[i]!='\0'; i++) {
mant[lMantissa++]=pI[i];
}
for (int i=0; pF[i]!='\0'; i++) {
mant[lMantissa++]=pF[i];
}
mant[lMantissa]='\0';
cout<<"| Segno | Esponente | Mantissa |" << endl;
cout<<"| " << segno << " | " << eB << " | " << mant << " |" << endl;
cout<<"Esponente = potenza + 127 => " << posVirgola - 1 + 127 << endl;
return 0;
}
Output:
Inserisci un numero binario: 10110,010011
| Segno | Esponente | Mantissa |
| 0 | 10000011 | 0110010011 |
Esponente = potenza + 127 => 131