Perché 0,1 + 0,2 non fa 0,3

Lo standard IEEE 754 scrive un numero come segno, esponente e mantissa, in base due: valore = (−1)^segno × 1,mantissa × 2^(esponente − bias). In precisione singola ci sono 8 bit di esponente e 23 di mantissa, in doppia 11 e 52. È il formato di quasi tutti i processori e di ogni linguaggio di programmazione.

In base due solo le frazioni con denominatore potenza di 2 hanno una scrittura finita. 0,5 e 0,25 sì, 0,1 no: in binario è 0,000110011001100… periodico, e va troncato. Il valore memorizzato è il più vicino disponibile, che per un float è 0,100000001490116…, e sommando valori già approssimati gli errori si accumulano.

Per questo i numeri decimali in virgola mobile non si confrontano con ==, ma controllando che la differenza sia piccola, e i soldi si contano in centesimi interi o con tipi decimali. I valori speciali completano il formato: zero con segno, infiniti, NaN e i subnormali, che riempiono il vuoto vicino allo zero.

Errori frequenti

  • Confrontare due float con ==: 0.1 + 0.2 == 0.3 è falso in quasi tutti i linguaggi.
  • Usare i float per importi di denaro: gli arrotondamenti si sommano. Meglio centesimi interi o un tipo decimale.
  • Pensare che un float a 32 bit abbia 32 bit di precisione: la mantissa ne ha 24, circa 7 cifre decimali; un double ne ha circa 16.

Domande frequenti

Quante cifre decimali ha un float e un double?

Un float a 32 bit garantisce circa 7 cifre decimali significative, un double a 64 bit circa 15-16. Oltre, le cifre che vedi sono il riflesso dell'approssimazione binaria.

Che cosa sono i numeri subnormali?

Sono i valori più piccoli del minimo normale: l'esponente è tutto zero e la mantissa perde il bit implicito 1. Permettono di avvicinarsi allo zero in modo graduale, a costo di meno precisione.

Perché esistono +0 e −0?

Perché il segno è un bit a parte. I due zeri sono uguali nei confronti, ma 1/+0 dà +∞ e 1/−0 dà −∞: conservano il verso da cui si è arrivati allo zero.

Come funziona questo calcolo

Valore = (−1)^s × 1,f × 2^(e − bias) per i numeri normali, con bias 127 in precisione singola e 1023 in doppia; per i subnormali (e = 0) il valore è (−1)^s × 0,f × 2^(1 − bias). Esponente tutto a 1 con mantissa nulla è ±∞, con mantissa non nulla è NaN. Il valore esatto viene calcolato in decimale senza arrotondamenti: ogni float è m × 2^k, e per k negativo equivale a m × 5^(−k) ÷ 10^(−k).