Ponto flutuante, um decimal de cada vez

Digite um número decimal. Os passos abaixo detalham a conversão, feita exatamente como a faria no papel, e a linha no topo mostra o que um computador acaba por guardar.

A carregar a simulação interativa...
Lição

A teoria — Ponto flutuante284 palavras

Um número de ponto flutuante é um número inteiro multiplicado por uma potência de dois: (−1)s × 1.f × 2E−1023. O formato decide quantos bits pertencem a E e quantos a f, e essa única divisão define tanto o alcance do formato quanto a sua precisão ao distinguir dois números.

O que significa cada símbolo

s
o bit de sinal, 0 para positivo e 1 para negativo. Permanece isolado em vez de ser incorporado no número, razão pela qual o formato apresenta tanto um +0 como um −0.
E
o campo do expoente, armazenado com o acréscimo de 1023 para que possa assumir valores negativos sem precisar de um sinal próprio. É ele que escolhe em que intervalo o número se encontra, e é o intervalo que decide a distância entre os vizinhos.
f
a fração: 52 bits que sucedem a um 1 inicial que nunca é armazenado, dado que um número normalizado começa sempre por um. Estes 52 bits representam toda a precisão do formato, à qual o expoente não acrescenta nada.
Pressupõe
Que o número é finito e normal. Abaixo de 2−1022, o 1 inicial é omitido e o formato mantém-se sacrificando a precisão. Como resultado, o menor double positivo é 4,94 × 10−324 e carrega um único bit de significando.
Falha quando
Em dois lugares, ambos em código real. Comparar dois valores calculados com = falha sempre que venham de vias distintas, porque rotas diferentes introduzem arredondamentos diferentes. Uma soma longa depende também da ordem de adição: some uma lista numa direção e depois na outra, e os totais divergem. Somar primeiro os termos menores é a forma de perder menos.

Oito entre mil

Dos números de 0,001 a 1,000, exatamente oito são mantidos sem nenhum erro: 0,125; 0,25; 0,375; 0,5; 0,625; 0,75; 0,875 e 1. Uma fração binária é uma soma de metades, quartos, oitavos e por aí adiante, e um denominador de 1000 contém um fator de 125 que nenhuma potência de dois jamais eliminará. Digite 0,375 e a ferramenta considera o valor exato. Digite 0,376 e ela não o fará.

0,1 + 0,2 cai exatamente a meio

Os dois valores armazenados somam 0,3000000000000000166533453693773481063544750213623046875, e esse é o ponto médio preciso entre os dois números de dupla precisão de cada lado de 0,3. A adição propriamente dita é impecável. O empate tem de ser desfeito de alguma forma, e a regra consiste em adotar o vizinho cujo último bit seja par. O valor de dupla precisão abaixo de 0,3 termina a sua fração num bit ímpar e o que se encontra acima termina num bit par, pelo que a soma é arredondada para cima. É daí que provém a cauda do número 0,30000000000000004.

Menos bits, a resposta certa

Selecione binary32 com os mesmos dois números. O 0,1 + 0,2 dá 0,300000011920928955078125, que é exatamente a forma como o 0,3 é armazenado nesse formato. O célebre fracasso desta conta exige que a soma resulte num empate. Com 24 bits, o resultado fica a um quarto de intervalo de distância de o ser, pelo que arredonda de volta para o número que esperava. Tem metade da precisão e a resposta que pretendia.

O intervalo duplica a cada potência de dois

Em qualquer ponto entre 0,0625 e 0,125, a distância de um número representável para o seguinte é de 1,39 × 10⁻¹⁷, sem sofrer qualquer variação dentro dessa faixa. Ao passar para a faixa superior, a distância duplica. A escadaria no gráfico ilustra precisamente isso: um degrau por cada potência de dois. É por este motivo que o mesmo formato consegue armazenar 10⁻³⁰⁰ e 10³⁰⁰, mas é incapaz de guardar o 9007199254740993.

Problema resolvido na íntegra

  1. Um sistema de pagamentos armazena montantes em libras no formato binary64. Mostre que £0,10 e £0,20 são ambos armazenados ligeiramente por excesso, que a sua soma não dá £0,30, e explique o que um engenheiro de pagamentos faz para solucionar o problema.

    Abrir este problema na ferramenta

    1. O valor 0,1 na base dois é 0,0001 seguido de 1001 a repetir-se infinitamente. Um décimo requer um cinco no seu denominador e uma fração binária é composta apenas por fatores de dois, de modo que a expansão nunca termina.

      0.110=0.00011001‾2=1.1001‾2×2−40.1_{10} = 0.0001\overline{1001}_{2} = 1.\overline{1001}_{2}\times 2^{-4}
    2. São mantidos 53 algarismos binários e os restantes são eliminados por arredondamento. Neste caso arredondam para cima, pelo que o valor armazenado fica 5,55 × 10⁻¹⁸ acima de 0,1. O passo de arredondamento na página ilustra essa direção com uma seta.

      fl(0.1)=0.1000000000000000055511151231257827021181583404541015625\mathrm{fl}(0.1) = 0.1000000000000000055511151231257827021181583404541015625
    3. O número 0,2 corresponde a esses mesmos 53 algarismos mas com o expoente superior em uma unidade, logo o seu erro é o dobro exato: 1,11 × 10⁻¹⁷. Introduza 0,2 na caixa e compare os dois cartões de erro.

      fl(0.2)=2 fl(0.1) ⟹ fl(0.2)−0.2=2(fl(0.1)−0.1)=+1.1102×10−17\mathrm{fl}(0.2) = 2\,\mathrm{fl}(0.1)\ \Longrightarrow\ \mathrm{fl}(0.2)-0.2 = 2\left(\mathrm{fl}(0.1)-0.1\right) = +1.1102\times 10^{-17}
    4. Quando somados, os dois valores armazenados recaem exatamente no ponto médio entre os dois números de dupla precisão de cada lado de 0,3. Em caso de empate, escolhe-se o vizinho que termina num bit par, que aqui corresponde ao valor imediatamente superior.

      fl(0.1)+fl(0.2)=12(fl(0.3)+fl(0.3)+)\mathrm{fl}(0.1)+\mathrm{fl}(0.2) = \tfrac{1}{2}\left(\mathrm{fl}(0.3)+\mathrm{fl}(0.3)^{+}\right)
    5. Assim, o resultado devolvido é 0,3000000000000000444089209850062616169452667236328125, e todos os cálculos seguintes vão arrastá-lo.

      fl(0.1)+fl(0.2)  ⟶  0.3000000000000000444089209850062616169452667236328125≠0.3\mathrm{fl}(0.1)+\mathrm{fl}(0.2)\;\longrightarrow\; 0.3000000000000000444089209850062616169452667236328125 \ne 0.3
    6. Agora digite 10 e 20 em vez de 0,1 e 0,2. Ambos são números inteiros bastante inferiores a 2⁵³, ambos são armazenados de forma exata, e 10 + 20 é 30 sem qualquer perda no processo.

      ∣n∣<253 ⟹ fl(n)=n:10+20=30|n| < 2^{53}\ \Longrightarrow\ \mathrm{fl}(n)=n: \qquad 10+20=30

    Resposta

    Guarde o dinheiro como um número inteiro da unidade mais pequena, pence em vez de libras, e a aritmética torna-se exata porque todos os inteiros até 2⁵³ são exatos. O único arredondamento que resta é aquele que você próprio escreve, no momento em que decidir fazê-lo, e para o qual pode apontar. A ferramenta mostra os dois lados em dez segundos: digite 0,1 e o cartão de erro não será nulo; digite 10 e será.

    fl(0.1)+fl(0.2)=fl(0.3)+,fl(10)+fl(20)=30\mathrm{fl}(0.1)+\mathrm{fl}(0.2)=\mathrm{fl}(0.3)^{+}, \qquad \mathrm{fl}(10)+\mathrm{fl}(20)=30