Esses dias “lá na firma” alguém me perguntou se os números fracionários eram gravados no banco de dados com ponto ou com vírgula, na separação de casas decimais. Eu respondi que não era nenhum dos dois. Umas duas ou três semanas depois, apareceu no registro de uma tabela, um valor bem estranho onde deveria estar armazenado um peso em Kg: 13.170000000000001. Acredito que o dado que deveria estar armazenado era 13,170 Kg (treze quilos e cento e setenta gramas), mas por que aquele dígito na décima quinta casa decimal? Você sabe como essas duas coisas estão relacionadas?
Ponto flutuante é a maneira mais comum que os computadores usam para armazenar e processar números fracionários. É uma forma de se trabalhar com números reais com uma certa aproximação, e deve seguir padrões de implementação tanto no hardware quanto no software.
Um número em notação de ponto flutuante é representado da seguinte forma:
mantissa x base expoente
Exemplos:
O padrão IEEE-754 foi criado em 1985 para tratar diversos problemas encontrados em várias implementações de ponto flutuante, que causavam problemas de confiabilidade e portabilidade. Esse padrão estabelece o formato de precisão simples e precisão dupla (entre outros, mas esses dois são os mais usados), para armazenamento de valores em ponto flutuante. Segundo o padrão, os números de precisão simples devem ser armazenados em uma expressão de 32 bits, enquanto os de precisão dupla são armazenados em 64 bits, conforme o esquema abaixo:
Em resumo, o padrão IEEE-754 estabelece que para armazenar um valor em ponto flutuante deve-se usar o seguinte método:
Isso responde a primeira pergunta: No banco de dados, os números não são armazenados nem com ponto e nem com vírgula. Eles são armazenados normalmente num formato de 32 ou 64 bits dependendo da precisão. Por exemplo, o tipo de campo REAL do PostgreSQL é compatível com o padrão IEEE-754 de precisão simples (32 bits), enquanto que o tipo DOUBLE é de precisão dupla (64 bits).
Ah, essa é uma parte bem curiosa. Abra o console Javascript do seu navegador e digite:
x = 0.1 + 0.2
Essa é a parte em que muita gente pensa “Ué… vai dar 0.3, não?”. Vou colocar abaixo o “print” do resultado:
Não, o navegador não está “bugado” e nem é problema do Javascript. Pode ter passado batido, mas lá no primeiro parágrafo que fala sobre ponto flutuante, eu digo que “é uma forma de se trabalhar com números reais com uma certa aproximação”. Isso acontece porque não é possível representar uma quantidade infinita de valores usando uma quantidade finita de recursos. Veja bem: não estou dizendo que não é possível representar o valor infinito. Estou dizendo que entre 0 e 1, matematicamente há uma quantidade infinita de valores, e não é possível representar todos esses valores possíveis usando apenas 32 ou 64 bits, então erros de aproximação estão sujeitos a acontecer em operações matemáticas com ponto flutuante. Eu falo sobre isso no capítulo 2 do livro que eu estou escrevendo.
Veja o mesmo exemplo feito na linguagem Rust:
A especificação de 1985 do padrão IEEE-754 permite alguns valores especiais:
Esses valores são armazenados de acordo com as seguintes regras:
| Valor | Bit de Sinal | Expoente | Mantissa |
| NaN | 0 ou 1 | Todos os bits 1 | Pelo menos um bit 1 |
| Infinito Positivo | 0 | Todos os bits 1 | Todos os bits 0 |
| Infinito Negativo | 1 | Todos os bits 1 | Todos os bits 0 |
Veja esse novo exemplo em linguagem Rust:
Esse site aqui mostra de maneira bem detalhada, como os valores em ponto flutuante são armazenados bit a bit.