Nella maggior parte dei linguaggi di programmazione, i numeri in virgola mobile sono rappresentati in modo molto simile alla notazione scientifica : con un esponente e una mantissa (detto anche significato). Un numero molto semplice, diciamo 9.2
, è in realtà questa frazione:
5179139571476070 * 2 -49
Dov'è l'esponente -49
e la mantissa 5179139571476070
. La ragione per cui è impossibile rappresentare alcuni numeri decimali in questo modo è che sia l'esponente che la mantissa devono essere numeri interi. In altre parole, tutti i float devono essere un numero intero moltiplicato per una potenza intera di 2 .
9.2
può essere semplicemente 92/10
, ma 10 non può essere espresso come 2 n se n è limitato a valori interi.
Vedere i dati
Innanzitutto, alcune funzioni per vedere i componenti che creano un 32 e 64 bit float
. Rifletti su questi se ti preoccupi solo dell'output (esempio in Python):
def float_to_bin_parts(number, bits=64):
if bits == 32: # single precision
int_pack = 'I'
float_pack = 'f'
exponent_bits = 8
mantissa_bits = 23
exponent_bias = 127
elif bits == 64: # double precision. all python floats are this
int_pack = 'Q'
float_pack = 'd'
exponent_bits = 11
mantissa_bits = 52
exponent_bias = 1023
else:
raise ValueError, 'bits argument must be 32 or 64'
bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]
C'è molta complessità dietro quella funzione, e sarebbe abbastanza tangente da spiegare, ma se sei interessato, la risorsa importante per i nostri scopi è la modulo struct .
Python's float
è un numero a 64 bit, doppia precisione. In altri linguaggi come C, C ++, Java e C #, la doppia precisione ha un tipo separatodouble
, che viene spesso implementato come 64 bit.
Quando chiamiamo quella funzione con il nostro esempio 9.2
, ecco cosa otteniamo:
>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']
Interpretazione dei dati
Vedrai che ho diviso il valore restituito in tre componenti. Questi componenti sono:
- Cartello
- Esponente
- Mantissa (chiamato anche Significand, o Fraction)
Cartello
Il segno è memorizzato nel primo componente come un singolo bit. È facile da spiegare: 0
significa che il float è un numero positivo; 1
significa che è negativo. Perché 9.2
è positivo, il nostro valore del segno è 0
.
Esponente
L'esponente è memorizzato nel componente centrale come 11 bit. Nel nostro caso 0b10000000010
,. In decimale, questo rappresenta il valore 1026
. Una stranezza di questo componente è che è necessario sottrarre un numero uguale a 2 (# di bit) - 1 - 1 per ottenere l'esponente vero; nel nostro caso, ciò significa sottrarre 0b1111111111
(numero decimale 1023
) per ottenere l'esponente vero 0b00000000011
(numero decimale 3).
mantissa
La mantissa è memorizzata nel terzo componente come 52 bit. Tuttavia, c'è una stranezza anche per questo componente. Per capire questa stranezza, considera un numero nella notazione scientifica, come questo:
6.0221413x10 23
La mantissa sarebbe la 6.0221413
. Ricordiamo che la mantissa nella notazione scientifica inizia sempre con una singola cifra diversa da zero. Lo stesso vale per il binario, tranne per il fatto che il binario ha solo due cifre: 0
e 1
. Quindi la mantissa binaria inizia sempre con 1
! Quando viene memorizzato un galleggiante, la 1
parte anteriore della mantissa binaria viene omessa per risparmiare spazio; dobbiamo rimetterlo nella parte anteriore del nostro terzo elemento per ottenere la vera mantissa:
1,0010011001100110011001100110011001100110011001100110
Ciò implica più di una semplice aggiunta, poiché i bit memorizzati nel nostro terzo componente rappresentano in realtà la parte frazionaria della mantissa, a destra del punto radicale .
Quando si tratta di numeri decimali, "spostiamo il punto decimale" moltiplicando o dividendo per poteri di 10. In binario, possiamo fare la stessa cosa moltiplicando o dividendo per poteri di 2. Poiché il nostro terzo elemento ha 52 bit, dividiamo per 2 52 per spostarlo di 52 posizioni a destra:
0,0010011001100110011001100110011001100110011001100110
In notazione decimale, che è lo stesso di dividendo 675539944105574
da 4503599627370496
ottenere 0.1499999999999999
. (Questo è un esempio di rapporto che può essere espresso esattamente in binario, ma solo approssimativamente in decimale; per maggiori dettagli, vedere: 675539944105574/4503599627370496 .)
Ora che abbiamo trasformato il terzo componente in un numero frazionario, l'aggiunta 1
dà la vera mantissa.
Ricapitolazione dei componenti
- Segno (primo componente):
0
per positivo, 1
per negativo
- Esponente (componente centrale): Sottrai 2 (numero di bit) - 1 - 1 per ottenere l'esponente vero
- Mantissa (ultimo componente): dividi per 2 (numero di bit) e aggiungi
1
per ottenere la vera mantissa
Calcolo del numero
Mettendo insieme tutte e tre le parti, ci viene dato questo numero binario:
1.0010011001100110011001100110011001100110011001100110 x 10 11
Che possiamo quindi convertire da binario a decimale:
1.1499999999999999 x 2 3 (inesatto!)
E moltiplica per rivelare la rappresentazione finale del numero che abbiamo iniziato con ( 9.2
) dopo essere stato memorizzato come valore in virgola mobile:
9,1999999999999993
Rappresentando come una frazione
9.2
Ora che abbiamo creato il numero, è possibile ricostruirlo in una semplice frazione:
1.0010011001100110011001100110011001100110011001100110 x 10 11
Spostare la mantissa su un numero intero:
10010011001100110011001100110011001100110011001100110 x 10 11-110100
Converti in decimale:
5179139571476070 x 2 3-52
Sottrai l'esponente:
5179139571476070 x 2 -49
Trasforma esponente negativo in divisione:
5179139571476070/2 49
Moltiplicare esponente:
5179139571476070/562949953421312
Che equivale a:
9,1999999999999993
9.5
>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']
Già puoi vedere che la mantissa ha solo 4 cifre seguite da molti zeri. Ma andiamo attraverso i passi.
Montare la notazione scientifica binaria:
1,0011 x 10 11
Spostare il punto decimale:
10011 x 10 11-100
Sottrai l'esponente:
10011 x 10 -1
Da binario a decimale:
19 x 2 -1
Esponente negativo alla divisione:
19/2 1
Moltiplicare esponente:
19/2
È uguale a:
9.5
Ulteriori letture