MySQL usando FLOOR leva a resultados inesperados

0

No MySQL eu tenho a seguinte fórmula:

SELECT FLOOR(38774/184*126*23+0.5);

O que, para minha surpresa, rende 610690 , embora o resultado da fórmula dentro de FLOOR seja 610691 . No Excel isso funciona muito bem e me dá o resultado desejado, também em qualquer calculadora que eu uso no macOS ou Windows.

Eu estou negligenciando alguma coisa aqui? Existe uma explicação para esse comportamento e, mais importante, como posso evitar que isso aconteça?

    
por TylerDurden 10.07.2017 / 10:50

1 resposta

0

Os cálculos de ponto flutuante são bem engraçados: tente estes:

SELECT FLOOR(38774/184*126*23+0.5);
SELECT FLOOR(38774*126*23/184+0.5);
SELECT FLOOR(ROUND(38774/184*126*23+0.5, 3));

O que está acontecendo aqui?

A parte mais importante é que 38774/184 não tem representação exata como um número de ponto flutuante - você sempre e um pouquinho curto. Com o resto do cálculo somando exatamente 610691, você acaba ficando um pouco abaixo de 610691 resultando em um FLOOR de 610690.

A segunda linha evita isso, reagrupando as partes do cálculo em uma sequência, que tem uma representação exata como um número de ponto flutuante.

A terceira linha usa um ROUND para cortar a pequena diferença, fazendo com que o FLOOR funcione como esperado.

Regra geral: os números de pontos flutuantes não produzem resultados exatos. Embora na maioria das vezes sejam "exatos o suficiente", há casos extremos em que eles não são. Você acaba de acertar um, e é bem comum: Convertendo de volta para o inteiro via FLOOR ou CEIL .

Agora, para responder à sua pergunta: De Experiência, eu teria encomendado o cálculo da mesma forma que a segunda linha - números maiores (dentro do intervalo INT32) têm maior probabilidade de produzir o FLOOR correto. Se o custo computacional for aceitável para você, eu escolheria

SELECT FLOOR(ROUND(38774*126*23/184+0.5, 3));

e esteja bastante confiante para ter todos os casos de limites cobertos.

    
por 10.07.2017 / 11:20

Tags