Estou fazendo a soma de uma coluna contendo cerca de 500.000 registros de números de dupla precisão. Todos os números no banco de dados devem normalmente ter duas cifras atrás do ponto. No entanto, ao fazer a soma, obtenho 6 números após o ponto:123123123.549977
Ou tenho dados incorretos em meu banco de dados onde há registros com mais números após o ponto ou há algo que estou perdendo sobre a função de soma.
Então minhas perguntas são:
- A função soma tem alguma propriedade de arredondamento que pode causar isso?
- Existe uma maneira de selecionar todos os registros contendo mais de dois números após o ponto?
Este é um problema comum com números de ponto flutuante em todos os lugares .
Os números de ponto flutuante armazenados em sistemas de computador devem ser considerados apenas aproximações porque existem números fáceis de representar em decimal que saem mais do que a precisão disponível (às vezes, na verdade, nunca terminam) quando convertidos em binário. Veja os links do ypercube e https://stackoverflow.com/questions/588004/is-floating-point-math-broken entre muitas outras referências, para mais detalhes.
O exemplo mais comum fornecido (como visto no link StackOverflow) é 0,1+0,2, não resultando exatamente em 0,3. Você deve aplicar arredondamento extra ou verificação de limites flexíveis (em ambos os casos, reduzindo a precisão efetiva) para obter o comportamento esperado.
Como seus dados têm um número fixo de casas decimais (ou um máximo fixo) em 2, seria muito melhor usar os tipos decimal/numérico de casa fixa ou similares. Na verdade, eles são armazenados e processados como inteiros dimensionados, evitando a necessidade de qualquer representação de ponto flutuante internamente, evitando assim o problema de aproximação (todos os inteiros podem ser representados com precisão na base 10 e na base 2, supondo que você tenha dígitos/bits suficientes). Por exemplo, 0,1 e 0,2 podem ser armazenados como 1000 e 2000, portanto, a adição resulta em 3000 que, quando convertido em uma string para exibição, torna-se 0,3, não o 0,3000000004 que você pode obter de um cálculo de ponto flutuante e, é claro, compara com precisão a 3 em o mesmo tipo que seria escalado para 3000.
Você pode converter em string e contar os caracteres após o ponto decimal (ou vírgula, dependendo do local do sistema). No TSQL, isso encontraria valores que terminaram com mais de duas casas decimais depois de serem armazenados em um formato float binário e depois convertidos de volta para decimal:
(talvez seja necessário ajustar os nomes das funções e a sintaxe relacionada para o postgres).
A resposta de David está correta, exceto pelo código, que não faz sentido no PostgreSQL.
Você está procurando > 2 casas decimais. A maneira mais fácil de descobrir isso é converter para
NUMERIC
(ponto flutuante decimal de precisão arbitrária) e subtrair o valor arredondado do original.(Na verdade, é SQL padrão, deve funcionar em muitos bancos de dados com ajustes para o tipo de dados -
DECIMAL
,NUMBER
,DECFLOAT
,NUMERIC
etc).Outra opção é definir
extra_float_digits=1
para lidar com o erro de imprecisão float/dec na formatação float-to-string e, em seguida, fazer uma correspondência de padrão simples:Uma solução alternativa que tentei é converter para
varchar
e depois converter de volta paraDOUBLE
precisão, como no exemplo a seguir: