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

  1. 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).
  2. 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.
  3. 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.
  4. Controllare l'etichetta di classificazione Il risultato viene classificato automaticamente come zero, denormalizzato, normalizzato, infinito o NaN, con una breve spiegazione del significato.
  5. 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

In binario 0,1, 0,2 e 0,3 sono tutti numeri periodici infiniti e l'elaboratore, per farli entrare in una mantissa finita — 52 bit in precisione doppia — li arrotonda. Poiché gli errori di arrotondamento di 0,1 e 0,2 non si compensano, la loro somma differisce lievemente dalla configurazione che rappresenta esattamente 0,3 e vale 0,30000000000000004. Non è il difetto di un linguaggio particolare, ma un fenomeno comune a tutti quelli conformi alla norma IEEE 754.

La precisione singola, float su 32 bit, si compone di un bit di segno, otto di esponente e ventitré di mantissa; quella doppia, double su 64 bit, di un bit di segno, undici di esponente e cinquantadue di mantissa. Più bit ha la mantissa, maggiore è il numero di cifre significative, cioè la precisione; più ne ha l'esponente, più ampio è l'intervallo dei valori rappresentabili. Nei linguaggi di programmazione il tipo in virgola mobile predefinito è spesso quello a precisione doppia.

Sono le configurazioni con esponente tutto a zero e mantissa diversa da zero. Ai numeri normalizzati si antepone alla mantissa un uno implicito; i denormalizzati vi rinunciano e fissano l'esponente al minimo, riuscendo così a rappresentare valori ancora più vicini allo zero del più piccolo normalmente esprimibile, ma sacrificando le cifre significative.

Nella norma IEEE 754 il bit di segno esiste indipendentemente: anche con esponente e mantissa tutti a zero si hanno perciò due configurazioni distinte, il «più zero» con il bit di segno a zero e il «meno zero» con il bit a uno. Nel confronto numerico 0 e -0 risultano uguali, ma nei calcoli emergono differenze: uno diviso zero dà più infinito, uno diviso meno zero dà meno infinito.

Entrambi hanno l'esponente tutto a uno. Se la mantissa è tutta a zero si tratta dell'infinito, con il bit di segno a distinguere più infinito e meno infinito; se la mantissa è diversa da zero si tratta di NaN, cioè di un valore che non è un numero. Si generano come esito di operazioni matematicamente indefinite, come la divisione per zero o infinito meno infinito.
Tool-kun

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.