Tire a prova real e veja quem está certo ou errado…
Vi um post no br-linux de autoria do blog Tuxtoriais que inicia com uma pergunta simples, mas com uma resposta intrigante:
“Responda rápido: quanto é 1 * (0,5 - 0,4 - 0,1) ?”
Segundo o blog, para o Excel o resultado é: -2,77556E-17 e para o BrOffice é 0!
Para fins de curiosidade resolvi testar como este mesmo cálculo se comporta em algumas linguagens e programas e eis as surpresas…
PHP
guedes@atlantis ~$ php -a php > $a = 0.5-0.4-0.1; php > echo $a; -2.77555756156E-17
Python
guedes@atlantis ~$ python >>> a=0.5-0.4-0.1; >>> a -2.7755575615628914e-17
Ruby
guedes@atlantis ~$ irb irb(main):001:0> 0.5-0.4-0.1 => -2.77555756156289e-17
bc
guedes@atlantis ~$ bc -l 0.5-0.4-0.1 0
Java
guedes@atlantis ~$ cat > teste.java
class teste{
public static void main(String args[]) {
Double a=0.5-0.4-0.1;
System.out.println(a);
}
}
^D
guedes@atlantis ~$ javac teste.java
guedes@atlantis ~$ java teste
-2.7755575615628914E-17
C
guedes@atlantis ~$ cat > teste.c #includeMe preocupou um pouco quanto aos bancos de dados, mas o resultado já era o que eu esperava…int main(){ double a=0.5-0.4-0.1; printf("%e\n", a); } ^D guedes@atlantis ~$ gcc teste.c -o teste guedes@atlantis ~$ ./teste -2.775558e-17
PostgreSQL
guedes@atlantis ~$ psql -c "SELECT 0.5-0.4-0.1" ?column? ---------- 0.0
No entanto, se deixarmos explicito o tipo de dado numérico que estamos utilizando os resultados podem nos surpreender. O Osvaldo Kussama alertou (em comentário mais abaixo) e postou um teste um pouco mais detalhado que o meu que esponho aqui:
bdteste=# SELECT 0.5::numeric - 0.4::numeric - 0.1::numeric;
?column?
----------
0.0
(1 registro)
bdteste=# SELECT 0.5::real - 0.4::real - 0.1::real;
?column?
--------------
-7.45058e-09
(1 registro)
bdteste=# SELECT 0.5::double precision - 0.4::double precision - 0.1::double precision;
?column?
-----------------------
-2.77555756156289e-17
(1 registro)
Como o próprio Osvaldo alertou, o problema é da aritmética binária, conforme itens 8.1.2 e 8.1.3 da documentação sobre os tipos numéricos no PostgreSQL.
MySQL
Não sei como deixar explícito que os valores abaixo estão em reais ou dupla precisão, se alguém souber favor comentar.
guedes@atlantis ~$ mysql mysql> select 0.5-0.4-0.1; +-------------+ | 0.5-0.4-0.1 | +-------------+ | 0.0 | +-------------+
E se você gosta de um pouco de matemática, vale a pena dar uma olhada na Wikipédia
Quando se trata de ponto flutuante é importante dar uma atenção à precisão da escala utilizada para não encontrarmos surpresas pela frente…
Bom é isso… “:)
O printf no seu programa em C está truncando a precisão do resultado obtido. Utilize:
printf("%e\n", a);
Obrigado pelo toque, foi um equívoco que passou despercebido para mim, mas é bom que sempre existem os mais atentos que nós para alertar-nos!
Um abraço. “:D
Quanto ao PostgreSQL:
bdteste=# SELECT 0.5::numeric - 0.4::numeric - 0.1::numeric;
?column?
———-
0.0
(1 registro)
bdteste=# SELECT 0.5::real - 0.4::real - 0.1::real;
?column?
————–
-7.45058e-09
(1 registro)
bdteste=# SELECT 0.5::double precision - 0.4::double precision - 0.1::double precision;
?column?
———————–
-2.77555756156289e-17
(1 registro)
Como podemos ver o problema é da aritmética binária.
http://www.postgresql.org/docs/current/interactive/datatype-numeric.html
Itens 8.1.2 e 8.1.3.
Obrigado Osvaldo! Já atualizei no post!