Convertitore IEEE 754 — Decimale in Bit Floating Point (32/64 bit)
Converte in entrambe le direzioni tra numeri decimali e configurazioni di bit IEEE 754 (precisione singola a 32 bit o doppia a 64 bit). Segno, esponente e mantissa a colori distinti rendono immediati da individuare NaN, infiniti e numeri denormalizzati.
L'esempio classico: perché 0,1 più 0,2 non fa 0,3
Calcolando `0.1 + 0.2` in JavaScript si ottiene `0.30000000000000004`, che non coincide con `0.3`. Osservando la configurazione di bit in precisione doppia se ne comprende la ragione.
| Valore | Esadecimale in precisione doppia (64 bit) | Binario in precisione doppia (64 bit) |
|---|---|---|
| 0.1 | 0x3FB999999999999A | 0011111110111001100110011001100110011001100110011001100110011010 |
| 0.2 | 0x3FC999999999999A | 0011111111001001100110011001100110011001100110011001100110011010 |
| 0.3 | 0x3FD3333333333333 | 0011111111010011001100110011001100110011001100110011001100110011 |
| 0.1 + 0.2 | 0x3FD3333333333334 | 0011111111010011001100110011001100110011001100110011001100110100 |
In binario 0,1, 0,2 e 0,3 sono tutti numeri periodici infiniti: non entrano nei 52 bit finiti della mantissa e vengono arrotondati. Gli errori di arrotondamento di 0,1 e 0,2 non si compensano e la somma arrotondata vale 0x3FD3333333333334, mentre il double più vicino a 0,3 è 0x3FD3333333333333. Sono due valori adiacenti, distanti un'unità nell'ultima posizione (1 ULP); poiché l'ultima cifra esadecimale passa da 3 (0011) a 4 (0100), differiscono i tre bit meno significativi. Provate a inserire questi valori nello strumento qui sopra e a confrontare i bit finali.
Che cos'è la norma IEEE 754? Vedere i numeri in virgola mobile come bit
Quando un computer memorizza un numero decimale, non conserva le cifre digitate: codifica il valore in un numero fisso di bit secondo la norma IEEE 754, suddivisi in segno, esponente e mantissa. Questo strumento mostra esattamente quali bit vengono memorizzati per qualunque valore inserito, sia in precisione singola (32 bit) sia in precisione doppia (64 bit), e funziona anche al contrario: incollando una configurazione esadecimale o binaria si scopre a quale valore decimale corrisponde.
Nella programmazione quotidiana raramente occorre pensare a questo livello, eppure è proprio da qui che nasce il motivo per cui 0.1 + 0.2 non fa 0.3, per cui gli interi molto grandi perdono precisione una volta memorizzati come numeri in virgola mobile, e per cui NaN e infinito si comportano in un certo modo nei confronti. Vedere segno, esponente e mantissa scomposti per un valore reale trasforma queste regole astratte in qualcosa di concreto da osservare.
Come usare lo strumento
- Scegliere verso e precisione Selezionate «Da decimale a configurazione di bit» oppure il verso opposto, quindi la precisione singola (32 bit) o doppia (64 bit).
-
Inserire un valore
In ingresso decimale potete digitare un numero qualsiasi oppure «NaN»/«Infinity»/«-Infinity». In ingresso binario usate una stringa esadecimale con prefisso
0xo una stringa binaria con il numero di cifre corrispondente alla precisione scelta. - Leggere la scomposizione di segno, esponente e mantissa La sequenza di bit a colori e una tabella di dettaglio mostrano l'esponente grezzo, l'esponente al netto della polarizzazione e la rappresentazione esadecimale completa.
- Controllare l'etichetta di classificazione Il risultato viene classificato automaticamente come zero, denormalizzato, normalizzato, infinito o NaN, con una breve spiegazione del significato.
- Provare le impostazioni predefinite e i casi limite Usate i pulsanti per 0,1/0,2/0,3, ±0, ±Infinity e NaN, oppure provate valori negativi e numeri estremamente grandi o piccoli per osservarne la codifica.
Consigli per sfruttarlo al meglio
- Convertendo in bit 0,1, 0,2 e 0,3 in precisione doppia e confrontandoli con il risultato di 0,1 più 0,2, cioè 0.30000000000000004, si vede che si tratta del valore adiacente a 0,3 (a 1 ULP di distanza) e che differiscono i tre bit meno significativi.
- Inserendo «-0» nel campo decimale si ottiene una configurazione in cui è acceso soltanto il bit di segno, diversa da quella del più zero. Numericamente 0 e -0 sono uguali, ma la rappresentazione in bit è un'altra cosa.
- Quando l'esponente è tutto a zero, una mantissa nulla indica lo zero e una mantissa non nulla un numero denormalizzato, cioè la rappresentazione particolare che, a scapito della precisione, esprime valori estremamente vicini allo zero.
- Passando dalla precisione singola, a 32 bit, a quella doppia, a 64 bit, si osserva come per uno stesso valore 0,1 cambi l'entità dell'errore di arrotondamento, maggiore in precisione singola.
- Nella conversione inversa a partire dai bit occorre indicare un numero esadecimale con il prefisso
0xoppure un binario con tante cifre quante ne richiede la precisione scelta, con il prefisso0bfacoltativo.
Quando può servire questo strumento
Corsi di informatica
I manuali descrivono la struttura della virgola mobile in astratto; qui la si può verificare su numeri reali mentre si studia o si prepara una relazione di laboratorio.
Individuare bug di precisione numerica
Capite perché un calcolo risulta leggermente sbagliato inserendo il valore sospetto e osservandone la configurazione di bit esatta, senza scrivere codice.
Programmazione embedded e a basso livello
Decodificate un valore in virgola mobile esadecimale visto in un dump di memoria o in un registro, riportandolo a un numero decimale leggibile.
Preparazione a colloqui tecnici
Esercitatevi a rispondere a domande come «che differenza c'è fra precisione singola e doppia a livello di bit» usando un esempio concreto invece di nozioni mandate a memoria.
Spiegare a qualcuno perché «0,1 + 0,2 ≠ 0,3»
Mostrate le configurazioni di bit reali una accanto all'altra invece di limitarvi ad affermare che la causa è l'arrotondamento in virgola mobile.
Glossario
- IEEE 754
- La norma internazionale che definisce come i computer rappresentano i numeri in virgola mobile. Pubblicata nel 1985, è seguita dal tipo float/double di quasi tutti i linguaggi di programmazione.
- Bit di segno
- Il singolo bit che indica se un valore è positivo (0) o negativo (1). È indipendente da esponente e mantissa, motivo per cui «più zero» e «meno zero» esistono come configurazioni distinte.
- Esponente
- I bit che codificano l'ordine di grandezza del valore: 8 bit in precisione singola, 11 in precisione doppia, memorizzati sommandovi una polarizzazione.
- Mantissa (significando)
- I bit che codificano le cifre significative del valore: 23 bit in precisione singola, 52 in precisione doppia, normalmente interpretati con un uno implicito anteposto.
- Polarizzazione (bias)
- Uno scostamento fisso (127 in precisione singola, 1023 in doppia) sommato all'esponente affinché possa essere memorizzato e confrontato come un semplice intero senza segno.
- Numero denormalizzato (subnormale)
- Una configurazione con esponente tutto a zero e mantissa diversa da zero. Omettendo l'uno implicito, permette di rappresentare valori più vicini allo zero di un numero normalizzato, a scapito della precisione.
- NaN (non è un numero)
- Una configurazione con esponente tutto a uno e mantissa diversa da zero, prodotta da operazioni indefinite come 0 diviso 0 oppure infinito meno infinito.
- Infinito
- Una configurazione con esponente tutto a uno e mantissa tutta a zero, che compare tipicamente quando un calcolo supera l'intervallo rappresentabile.
Domande frequenti
A proposito — come nacque la «lingua comune» chiamata IEEE 754
Prima del 1985 ciascun costruttore adottava una propria rappresentazione dei numeri in virgola mobile. Fra IBM, DEC e Cray, calcolando lo stesso valore 0,1 si ottenevano arrotondamenti e intervalli rappresentabili leggermente diversi, e portare un programma da una macchina all'altra faceva puntualmente divergere i risultati numerici. Per porre fine alla confusione, un gruppo guidato da William Kahan dell'Università della California a Berkeley, che aveva collaborato anche alla progettazione del coprocessore matematico Intel 8087, definì nel 1985 la norma IEEE 754 come standard trasversale al settore.
L'idea centrale della norma sta nel ripartire i compiti fra tre parti — segno, esponente e mantissa — per approssimare con un numero finito di bit, 32 o 64, l'infinità dei numeri reali. L'esponente si occupa dell'ordine di grandezza, la mantissa della precisione delle cifre significative: così, con pochi bit, si trattano con duttilità numeri piccolissimi e grandissimi. Il fatto che l'esponente sia memorizzato sommandovi una polarizzazione — 127 in precisione singola e 1023 in quella doppia — è un accorgimento che permette di stabilire quale numero sia il maggiore confrontando semplicemente le sequenze di bit, senza le complicazioni del complemento a due degli interi con segno.
In binario si rappresentano «esattamente» soltanto le frazioni il cui denominatore è una potenza di due: un mezzo, un quarto, tre ottavi. Il valore decimale 0,1 corrisponde alla frazione un decimo, ma dieci non è una potenza di due e in binario diventa il numero periodico infinito 0,0001100110011… Per farlo entrare in una mantissa finita non resta che troncarlo e arrotondarlo: è questa la ragione di fondo per cui 0,1 non è rappresentabile con esattezza. Ed è per lo stesso motivo che i sistemi contabili, che devono trattare esattamente il decimale, ricorrono all'aritmetica intera o a tipi decimali appositi anziché alla virgola mobile.
La norma è stata poi rivista nel 2008 e nel 2019, con l'aggiunta della mezza precisione a 16 bit, della quadrupla a 128 bit e delle disposizioni sui numeri decimali in virgola mobile, ma la struttura fondamentale in tre parti e l'impostazione delle modalità di arrotondamento sono rimaste quelle della prima edizione del 1985. Poiché i tipi float e double di quasi tutti i linguaggi di programmazione vi si conformano, la domanda «perché 0,1 più 0,2 non fa 0,3» descrive un fenomeno comune a ogni linguaggio.