© 2014-2025 Roberto Foschini All rights reserved

Conversione da decimale in virgola fissa

Esistono diversi modi per rappresentare numeri in virgola fissa, ma il sistema più utilizzato è quello in modulo/segno (analogamente alla conversione in virgola mobile). Tuttavia, talvolta si usa anche la conversione in complemento a 2.

Conversione in formato modulo/segno

Si procede come segue:

Negli esempi che seguono supponiamo 1 bit segno, 8 bit parte intera, 7 bit parte frazionaria.

Esempio: -14,25

Escludo temporaneamente il segno e converto prima la parte intera: 1410 = 11102
14:2=7 R=0	0
 7:2=3 R=1	1
 3:2=1 R=1	2
 1:2=0 R=1	3
e poi la parte frazionaria: 0,2510=0,012 (riempio il resto della parte frazionaria con 0).
0,25*2=0,5	U=0	-1
0,5 *2=1,0	U=1	-2
0   (termino conversione perché ho incontrato 0)
Risultato(valore assoluto): 14,2510 = 1110,012
Infine estendo il numero (al numero di bit effettivo) e cambio il primo bit (segno):
Risultato(modulo/segno): -14,2510 = 10001110,012

Esempio: -123,21

Escludo temporaneamente il segno e converto prima la parte intera: 12310 = 11110112 e poi la parte frazionaria: 0,2110=0,0011012 (approssimato).
Risultato(valore assoluto): 123,2110 = 1111011,0011012
Infine estendo il numero (al numero di bit effettivo) e cambio il primo bit (segno):
Risultato(modulo/segno): -123,2110 = 11111011,0011012

Conversione in formato complemento a 2

Come per la conversione precedente, per questa conversione si procede convertendo il valore assoluto del numero (sia parte intera che parte frazionaria). Fatto questo però, si esegue il NOT del numero e si somma 1 al bit meno significativo (che vale 1) della parte frazionaria, gestendo gli eventuali riporti.

Negli esempi che seguono supponiamo 1 bit segno, 8 bit parte intera, 7 bit parte frazionaria.

Esempio: -14,25

Escludo temporaneamente il segno e converto prima la parte intera: 1410 = 11102
14:2=7 R=0	0
 7:2=3 R=1	1
 3:2=1 R=1	2
 1:2=0 R=1	3
e poi la parte frazionaria: 0,2510=0,012 (riempio il resto della parte frazionaria con 0).
0,25*2=0,5	U=0	-1
0,5 *2=1,0	U=1	-2
0   (termino conversione perché ho incontrato 0)
Risultato(valore assoluto): 14,2510 = 1110,012
Infine estendo il numero (al numero di bit effettivo), ne eseguo il NOT e aggiungo 1 al bit meno significativo:
Risultato(complemento a 2): -14,2510 = 11110001,102 + 00000000,012 = 11110001,112
La verifica che i due numeri opposti hanno somma 0 viene lasciata al lettore: 00001110,012 + 11110001,112 = ?

Esempio: -123,21

Escludo temporaneamente il segno e converto prima la parte intera: 12310 = 11110112 e poi la parte frazionaria: 0,2110=0,0011012 (approssimato).
Risultato(valore assoluto): 123,2110 = 1111011,0011012
Infine estendo il numero (al numero di bit effettivo), ne eseguo il NOT e aggiungo 1 al bit meno significativo:
a) Risultato(complemento a 2): -123,2110 = 10000100,1100102 + 00000000,0000012 = 10000100,1100112
b) Risultato(complemento a 2): -123,2110 = (-(12310)) + (-(0,2110)) = 100001012 + 11111111,1100112 = 10000100,1100112

Il problema della precisione finita. Numeri aperiodici, periodici con e senza antiperiodo

Supponiamo di voler convertire alcuni numeri in virgola fissa (formato modulo/segno), avendo a disposizione un totale di 24 bit, di cui: 1 bit di segno, 7 cifre di parte intera e 16 cifre di parte frazionaria. Notare che 23 bit di mantissa sono gli stessi presenti in IEEE-754 (singola precisione)

Esempio: -14,25 (numero aperiodico)

Escludo temporaneamente il segno e converto prima la parte intera: 1410 = 11102
14:2=7 R=0	0
 7:2=3 R=1	1
 3:2=1 R=1	2
 1:2=0 R=1	3
e poi la parte frazionaria: 0,2510=0,012 (riempio il resto della parte frazionaria con 0).
0,25*2=0,5	U=0	-1
0,5 *2=1,0	U=1	-2
0   (termino conversione perché ho incontrato 0)
Risultato(valore assoluto): 1110,012

Esempio: -14,2 (numero con periodo)

Escludo temporaneamente il segno e converto prima la parte intera: 1410 = 11102
14:2=7 R=0	0
 7:2=3 R=1	1
 3:2=1 R=1	2
 1:2=0 R=1	3
e poi la parte frazionaria: 0,210=0,00112 (tutte le cifre dopo la virgola costituiscono il periodo).
0,2 *2=0,4	U=0	-1
0,4 *2=0,8	U=0	-2
0,8 *2=1,6	U=1	-3
0,6 *2=1,2	U=1	-4
0,2 (termino conversione perché ho già incontrato questo numero)
Risultato(valore assoluto): 1110,00112

Esempio: -14,3 (numero con periodo e antiperiodo)

Escludo temporaneamente il segno e converto prima la parte intera: 1410 = 11102
14:2=7 R=0	0
 7:2=3 R=1	1
 3:2=1 R=1	2
 1:2=0 R=1	3
e poi la parte frazionaria: 0,310 = 0,010012 (il primo zero dopo la virgola costituisce l'antiperiodo, le cifre rimanenti costituiscono il periodo).
0,3 *2=0,6	U=0	-1
0,6 *2=1,2	U=1	-2
0,2 *2=0,4	U=0	-3
0,4 *2=0,8	U=0	-4
0,8 *2=1,6	U=1	-5
0,6 (termino conversione perché ho già incontrato questo numero)
Risultato(valore assoluto): 1110,010012

Esempio: -14,33 (numero aperiodico entro la mantissa)

Escludo temporaneamente il segno e converto prima la parte intera: 1410 = 11102
14:2=7 R=0	0
 7:2=3 R=1	1
 3:2=1 R=1	2
 1:2=0 R=1	3
e poi la parte frazionaria: 0,3310 = 0,01010100011100002.
0,33*2=0,66	U=0	-1
0,66*2=1,32	U=1	-2
0,32*2=0,64	U=0	-3
0,64*2=1,28	U=1	-4
0,28*2=0,56	U=0	-5
0,56*2=1,12	U=1	-6
0,12*2=0,24	U=0	-7
0,24*2=0,48	U=0	-8
0,48*2=0,96	U=0	-9
0,96*2=1,92	U=1	-10
0,92*2=1,84	U=1	-11
0,84*2=1,68	U=1	-12
0,68*2=0,36	U=0	-13
0,36*2=0,72	U=0	-14
0,72*2=1,44	U=0	-15
0,44*2=0,88	U=0	-16
0,88 ... (termino conversione perché sono finiti i bit disponibili per la parte frazionaria)
Risultato(valore assoluto): 1110,01010100011100002
Notiamo che se avessimo avuto a disposizione qualche ulteriore bit per la parte frazionaria, avremmo notato che il numero è periodico (con antiperiodo).
La parte frazionaria sarebbe risultata: 0,3310 = 0,01010100011100001110002. Infatti:
0,88*2=1,76	U=1	-17
0,76*2=1,52	U=1	-18
0,52*2=1,04	U=1	-19
0,04*2=0,08	U=0	-20
0,08*2=0,16	U=0	-21
0,16*2=0,32	U=0	-22
0,32 (termino conversione perché ho già incontrato questo numero)
Risultato(valore assoluto): 1110,01010100011100001110002

Conversione da decimale in virgola mobile (in formato P754)

Esistono diversi modi per rappresentare numeri in virgola mobile, ma il sistema più utilizzato è lo standard IEEE-P754; questo metodo comporta l'utilizzo della notazione scientifica, in cui ogni numero è identificato dal segno, da una mantissa (1,xxxxx) e dall'esponente (nyyyyy).

La procedura standard per la conversione da numero decimale a numero binario P754 è la seguente:

Come si può vedere, se k è il numero di bit occupati dall'esponente, il bias vale 2k-1-1. Ricordo che il valore 2k-1 (tutti i bit a 1) è riservato per scopi specifici (NaN, Inf, etc).

Esempio1

Convertire in floating point IEEE-754 il numero -14,312510.

Escludo temporaneamente il segno e converto (in binario) prima la parte intera: 1410 = 11102

14:2=7 R=0	0
 7:2=3 R=1	1
 3:2=1 R=1	2
 1:2=0 R=1	3
e poi converto (in binario) la parte frazionaria: 0,312510 = 0,01012.
0,3125*2=0,625   U=0
0,625 *2=1,25    U=1
0,25  *2=0,5     U=0
0,5   *2=1       U=1
0   (termino conversione perché ho incontrato 0)
Risultato(valore assoluto): 1110,01012

Ora normalizzo il numero, spostando la virgola di 3 posizioni verso sinistra: 1110,01012 = 1,11001012 * 23.

Una volta eliminato l'hidden bit, la mantissa diventa quindi 1100101, mentre l'esponente è 3.

Single-precision

Completo la mantissa con zeri fino ad arrivare ai 16 bit a mia disposizione.

Esprimo l'esponente in eccesso 127: 127 + 3 = 13010 = 100000102

Mettendo ad 1 il bit di segno (in quanto siamo partiti da un numero negativo) e completando con zeri la mantissa, risulta quindi:

-14.312510=1 10000010 11001010000000000000000P754/single

Half-precision

Completo la mantissa con zeri fino ad arrivare ai 10 bit a mia disposizione.

Esprimo l'esponente in eccesso 15: 15 + 3 = 1810 = 100102

Mettendo ad 1 il bit di segno (in quanto siamo partita da un numero negativo) e completando con zeri la mantissa, risulta quindi:

-14.312510=1 10010 1100101000P754/half

Esempio2 (Trasformazione in virgola fissa)

Convertire in floating point IEEE-754 il numero -5,82812510.

Escludo temporaneamente il segno e converto (in binario) prima la parte intera:

5:2=2 R=1	0
2:2=1 R=0	1
1:2=0 R=1	2
510 = 1012

e poi converto (in binario) la parte frazionaria:

0,828125*2=1,65625 U=1	-1
0,65625 *2=1,3125  U=1	-2
0,3125  *2=0,625   U=0	-3
0,625   *2=1,25    U=1	-4
0,25    *2=0,5     U=0	-5
0,5     *2=1       U=1	-6
0,82812510 = 1101012

Risultato(valore assoluto): 101,1101012

Esempio2 (Trasformazione in virgola mobile, continua da esempio precedente)

Ora normalizzo il numero, spostando la virgola due posizioni verso sinistra:

1,01110101*22

Una volta eliminato l'hidden bit, la mantissa diventa quindi 01110101, mentre l'esponente è 2.

Single-precision

Esprimo l'esponente in eccesso 127 (sommando 2 al bias):

127+2=129

Trasformiamo questo numero in binario:

129:2=64 R=1	0
 64:2=32 R=0	1
 32:2=16 R=0	2
 16:2= 8 R=0	3
  8:2= 4 R=0	4
  4:2= 2 R=0	5
  2:2= 1 R=0	6
  1:2= 0 R=1	7
12910=100000012

Mettendo ad 1 il bit del segno in quanto siamo partiti da un numero negativo, e completando con zeri la mantissa, risulta quindi:

-5,828112510=1 1000 0001 0111 0101 0000 0000 0000 000P754/single

Half-precision

Esprimo l'esponente in eccesso 15 (sommando 2 al bias):

15+2=17

Trasformiamo questo numero in binario:

 17:2= 8 R=1	0
  8:2= 4 R=0	1
  4:2= 2 R=0	2
  2:2= 1 R=0	3
  1:2= 0 R=1	4

Mettendo ad 1 il bit del segno in quanto siamo partiti da un numero negativo, e di completando con zeri la mantissa, risulta quindi:

-5,828112510=1 10 001 0111 0101 00P754/half

Esempi di conversione in floating point IEEE-754

Esempio1 Esempio2 Esempio3 Esempio4 Esempio5
Numero da convertire -49.526 (single prec) 625.00137 (single prec) 3.14 (half prec) 2.99E+3 (half prec) 8.85E-3 (half prec)
parte intera
49|1 0
24|0 1
12|0 2
 6|0 3
 3|1 4
 1|1 5
 0

parte frazion.
0.526|1 -1
0.052|0 -2
0.104|0 -3
0.208|0 -4
0.416|0 -5
0.832……………
…………………………
parte intera
625|1 0
312|0 1
156|0 2
 78|0 3
 39|1 4
 19|1 5
  9|1 6
  4|0 7
  2|0 8
  1|1 9
  0

parte frazion.
0.00137|0 -1
0.00274……………
………………………………
parte intera
 3|1 0
 1|1 1
 0

parte frazion.
0.14|0 -1
0.28|0 -2
0.56|1 -3
0.12|0 -4
0.24|0 -5
0.48|0 -6
0.96|1 -7
0.92|1 -8
0.84|1 -9
0.68
parte intera
2990|0  0
1495|1  1
 747|1  2
 373|1  3
 186|0  4
  93|1  5
  46|0  6
  23|1  7
  11|1  8
   5|1  9
   2|0 10
   1|1 11
   0
parte frazion.
0.00885|0  -1
0.0177 |0  -2
0.0354 |0  -3
0.0708 |0  -4
0.1416 |0  -5
0.2832 |0  -6
0.5664 |1  -7
0.1328 |0  -8
0.2656 |0  -9
0.5312 |1 -10
0.0624 |0 -11
0.1248 |0 -12
0.2496 |0 -13
0.4992 |0 -14
0.9984 |1 -15
0.9968 |1 -16
0.9936 |1 -17
0.9872	
In virgola fissa 110001,10000… 1001110001,0… 11,001000111 101110101110 0,00000010010000111
Normalizzazione 1,1000110000…*25 1,0011100010…*29 1,1001000111*21 1,0111010111*211 1,0010000111*2-7
Biasing esponente e conv. in binario 127+5=132 → 100001002 127+9=136 → 100010002 15+1=16 → 100002 15+11=26 → 110102 15-7=8 → 010002
Risultato 1 10000100 1000110000… 0 10001000 0011100010… 0 10000 1001000111 0 11010 0111010111 0 01000 0010000111

Appendice di ripasso

NUMERO DECIMALE

Da numero decimale a frazione generatrice

Da frazione generatrice a numero decimale

Data una frazione, eseguendo la divisione tra numeratore e denominatore si ottiene un numero decimale. Ancor prima di eseguire la divisione è però possibile stabilire che tipo di numero decimale genera la frazione. Prima si riduce la frazione ai minimi termini, poi si calcola la scomposizione in fattori primi del denominatore. A questo punto:

Come cambiano le regole se la base di destinazione non è 10 (ad esempio 2)?

Calcolo la frazione generatrice del numero in base 10, poi ricerco i fattori primi del denominatore.

// @brief Algoritmo (salvo errori)
// @author Roberto Foschini
// @date 31/01/2022
// @param $num di una frazione generatrice
// @param $den di una frazione generatrice

// semplifico la frazione
$num /= gcd($num, $den);
$den /= gcd($num, $den)

// $lap = lunghezza antiperiodo (dipende solo da $den)
for ($lap=0; $den%2==0; ++$lap)
	$den/=2;

// $lp = lunghezza periodo (dipende solo da $den)
for ($r=1, $lp=0; $r>1 || $lp==0; ++$lp)
	$r = ($r*2) % $den;

// determino la tipologia di numero binario
if($den==1)
	return $lap;	// binario limitato con $lap cifre binarie
else {
	if($lap==0)
		return $lp;	// binario illimitato periodico con $lp cifre binarie
	else
		return $lap, $lp;	// binario illimitato misto con $lap|$lp cifre binarie
}