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. Poiché gli errori di arrotondamento di 0,1 e 0,2 non si compensano, la loro somma risulta in una configurazione che differisce di un solo bit da quella che rappresenta esattamente 0,3, ossia 0x3FD3333333333334. Provate a inserire questi valori nello strumento qui sopra e a confrontare l'ultimo bit.
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 `0x` o 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 a colpo d'occhio che differiscono per un solo bit finale.
- 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 `0x` oppure un binario con tante cifre quante ne richiede la precisione scelta, con il prefisso `0b` facoltativo.
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.