Blog do Eduardo Costa Meu blog pessoal

30Out/112

Ponto Flutuante

Estou chegando a conclusão que ninguém nesse mundo lembra como funciona o conceito de "ponto flutuante" na programação. Em uma semana, já tive notícia de uns três ou quatro casos de pessoas falando "não sei porque a soma de decimal às vezes dá um resultado errado".

Vamos começar a aula esclarecendo que conta decimal não pode dar divergência. O que com certeza está acontecendo é que você está usando pontos flutuantes. Tirando COBOL e dBase III, não conheço nenhuma outra linguagem de programação na qual você use pontos decimais numa literal (ex: "83.27") e a linguagem interprete como decimal. Até que alguém prove o contrário, assuma que ela usa pontos flutuantes.

E, antes que alguém diga: "Ah, mas o meu não é float, é double.", vou avisando que "double" quer dizer o dobro de bits de representação, e não o dobro de precisão. Continua sendo ponto flutuante.

Como funciona? Em uma linha: o número é representado como Nx2^M. Lembra de notação científica (Nx10^M)? Mesmo princípio, só que usando base 2 (pois é essa a base que um CPU binário conhece). O número em ponto flutuante consiste de uma "base" N e uma "mantissa" M. Exemplo: N=2 e M=-4 é a representação PF para 2/16 ou 0,125. Como N e M tem uma quantidade finita de bits, claramente vão existir números não-representáveis em PF (ex: 10000000,000000001 - clique aqui e veja).

Se Nx2^M não é preciso, imagine a soma de Nx2^M e Ox2^P! Isso, "computacionalmente falando", significa transformar as mantissas M e P para um valor comum (Q), adaptando as bases N e O, efetuar a soma [Nx2^(M-Q)+Ox2^(P-Q)]x2^Q e normalizar o resultado. Preciso elaborar uma prova matemática para dizer que esse monstro é impreciso? A prova em JavaScript você vê clicando aqui. Mas, por via das dúvidas, se quiser uma prova mais formal, lembre que [Nx2^(M-Q)+Ox2^(P-Q)] vira a nova base, então ela precisa caber nos n bits da base durante a conta!

Resumo da ópera para quem gosta de decorar regra: não use ponto flutuante para valores monetários.

Comentários (2) Trackbacks (0)
  1. Poderoso mestre, se não for PF, devemos usar o quê? (Não vale Big Decimal – essa é tão óbvia que até eu sei…)

    A gente (eu e minha turma, aos 15 anos) costumava brigar por causa de MSX contra o mundo, pois ele era o único no qual 1+1=2 (os outros – especialmente o Apple II – davam 2.00001). :-)

    • Técnica de “Ponto Fixo”. Exemplo: 12.34 vira “1234 com 2 casas” (ou, mais corretamente falando, “sempre usar notação cientítica” – ex: 1234×10^-2). Exatamente o que o BigDecimal faz. Se as “contas” sempre forem monetárias de 2 casas, simplifica drasticamente o problema: sempre guardar os números Ponto Fixo multiplicados por 100 – nas multiplicações entre dois monetários divide por 100 (equivalente a “tirar duas casas”) e nas divisões, pré-multiplicar o numerador por 100 (equivalente a “colocar duas casas” – mas usar o numerador aumenta a precisão da conta).


Leave a comment

(required)


*

Sem trackbacks