Na maioria das linguagens de programação, os números de ponto flutuante são representados de maneira semelhante à notação científica : com um expoente e uma mantissa (também chamada de significando). Um número muito simples, digamos 9.2
, é realmente essa fração:
5179139571476070 * 2 -49
Onde está o expoente -49
e a mantissa 5179139571476070
. A razão pela qual é impossível representar alguns números decimais dessa maneira é que o expoente e a mantissa devem ser inteiros. Em outras palavras, todos os carros alegóricos devem ser um número inteiro multiplicado por uma potência inteira de 2 .
9.2
pode ser simples 92/10
, mas 10 não pode ser expresso como 2 n se n for limitado a valores inteiros.
Vendo os dados
Primeiro, algumas funções para ver os componentes que compõem um 32 e 64 bits float
. Passe por cima deles se você se importa apenas com a saída (exemplo em 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)]
Há muita complexidade por trás dessa função, e seria bastante tangível de explicar, mas se você estiver interessado, o recurso importante para nossos propósitos é o módulo struct .
O Python's float
é um número de precisão dupla de 64 bits. Em outras linguagens como C, C ++, Java e C #, a precisão dupla tem um tipo separado double
, que é frequentemente implementado como 64 bits.
Quando chamamos essa função com o nosso exemplo 9.2
, aqui está o que obtemos:
>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']
Interpretando os dados
Você verá que eu dividi o valor de retorno em três componentes. Esses componentes são:
- Placa
- Expoente
- Mantissa (também chamada de Significand, ou Fração)
Placa
O sinal é armazenado no primeiro componente como um único bit. É fácil de explicar: 0
significa que o flutuador é um número positivo; 1
significa que é negativo. Porque 9.2
é positivo, nosso valor de sinal é 0
.
Expoente
O expoente é armazenado no componente do meio como 11 bits. No nosso caso 0b10000000010
,. Em decimal, isso representa o valor 1026
. Uma peculiaridade desse componente é que você deve subtrair um número igual a 2 (# de bits) - 1 - 1 para obter o expoente verdadeiro; no nosso caso, isso significa subtrair 0b1111111111
(número decimal 1023
) para obter o expoente verdadeiro 0b00000000011
(número decimal 3).
Mantissa
A mantissa é armazenada no terceiro componente como 52 bits. No entanto, há uma peculiaridade nesse componente também. Para entender essa peculiaridade, considere um número em notação científica, assim:
6.0221413x10 23
A mantissa seria a 6.0221413
. Lembre-se de que a mantissa na notação científica sempre começa com um único dígito diferente de zero. O mesmo vale para o binário, exceto que o binário possui apenas dois dígitos: 0
e 1
. Assim, a mantissa binária sempre começa com 1
! Quando um flutuador é armazenado, a 1
parte frontal da mantissa binária é omitida para economizar espaço; temos que colocá-lo de volta na frente do nosso terceiro elemento para obter a verdadeira mantissa:
1.0010011001100110011001100110011001100110011001100110
Isso envolve mais do que apenas uma simples adição, porque os bits armazenados em nosso terceiro componente representam, na verdade, a parte fracionária da mantissa, à direita do ponto de raiz .
Ao lidar com números decimais, "movemos o ponto decimal" multiplicando ou dividindo por potências de 10. Em binário, podemos fazer o mesmo multiplicando ou dividindo por potências de 2. Como nosso terceiro elemento possui 52 bits, dividimos por 2 52 para movê-lo 52 lugares para a direita:
0.0010011001100110011001100110011001100110011001100110
Em notação decimal, é o mesmo que dividir 675539944105574
por 4503599627370496
obter 0.1499999999999999
. (Este é um exemplo de uma proporção que pode ser expressa exatamente em binário, mas apenas aproximadamente em decimal; para obter mais detalhes, consulte: 675539944105574/4503599627370496 .)
Agora que transformamos o terceiro componente em um número fracionário, a adição 1
fornece a verdadeira mantissa.
Recapitulando os componentes
- Sinal (primeiro componente):
0
para positivo, 1
para negativo
- Expoente (componente do meio): Subtraia 2 (número de bits) - 1 - 1 para obter o verdadeiro expoente
- Mantissa (último componente): divida por 2 (# de bits) e adicione
1
para obter a verdadeira mantissa
Cálculo do número
Juntando todas as três partes, recebemos este número binário:
1.0010011001100110011001100110011001100110011001100110 x 10 11
Que podemos então converter de binário em decimal:
1.1499999999999999 x 2 3 (inexato!)
E multiplique para revelar a representação final do número com o qual começamos ( 9.2
) depois de ser armazenado como um valor de ponto flutuante:
9.1999999999999993
Representando como uma fração
9.2
Agora que criamos o número, é possível reconstruí-lo em uma fração simples:
1.0010011001100110011001100110011001100110011001100110 x 10 11
Mude a mantissa para um número inteiro:
10010011001100110011001100110011001100110011001100110 x 10 11-110100
Converter em decimal:
5179139571476070 x 2 3-52
Subtraia o expoente:
5179139571476070 x 2 -49
Transforme expoente negativo em divisão:
5179139571476070/2 49
Multiplicar expoente:
5179139571476070/562949953421312
Qual é igual a:
9.1999999999999993
9,5
>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']
Já é possível ver que a mantissa tem apenas 4 dígitos seguidos por muitos zeros. Mas vamos percorrer os passos.
Monte a notação científica binária:
1.0011 x 10 11
Mude o ponto decimal:
10011 x 10 11-100
Subtraia o expoente:
10011 x 10 -1
Binário para decimal:
19 x 2 -1
Expoente negativo para divisão:
19/2 1
Multiplicar expoente:
19/2
É igual a:
9,5
Leitura adicional