Ao tentar somar 1.75 + 2.68 + 5.56 o resultado esperado é 9.99, contudo algumas engines (na prática, acontece no Firefox e no Google Chrome) me retornam 9.989999999999998.
Alguém sabe a razão disso, e um modo de contornar o problema?
__
Paulo Diovani Gonçalves
http://diovani.com
--
Grupo de jQuery Brasil.
REGRAS: http://groups.google.com/group/jquery-br/web/regras-do-grupo
USE O JSBIN.COM PARA CÓDIGOS.
Email: jque...@googlegroups.com
Biba: jquery-br+...@googlegroups.com
Site: http://groups.google.com/group/jquery-br?hl=pt-BR
--
Grupo de jQuery Brasil.
REGRAS: http://groups.google.com/group/jquery-br/web/regras-do-grupo
USE O JSBIN.COM PARA CÓDIGOS.
Email: jque...@googlegroups.com
Biba: jquery-br+...@googlegroups.com
Site: http://groups.google.com/group/jquery-br?hl=pt-BR
Bem, eu já imaginava que o problema (notem que falo "problema", ou seja, a situação que tenho em mãos, nunca considerei que fosse um erro) é causado pelo modo que uma CPU calcula pontos flutuantes.
Estou lendo o artigo no link que o Henrique mandou, o que já me esclareceu algumas coisas (embora matemática não seja o meu forte).
Flavia, se puder me enviar o artigo de que falou também será de grande ajuda.
Acontece que o problema é um pouco mais complicado do que parece. Vou detalhar o caso...
No sistema que estou trabalhando o usuário tem a opção de definir tanto a quantidade de casas decimais, como se o resultado do cálculo deve, ou não, ser arredondado.
Assim, no caso da soma 1.75 + 2.68 + 5.56, caso o usuário tenha decidido usar duas ou mais casas decimais, o resultado esperado será sempre 9.99, contudo, se ele decidir utilizar apenas uma, caso tenha decidido arredondar, o resultado esperado será 10, caso contrário, será 9.9.
A intenção a regra é como no algoritmo a seguir:
se (arredonda)
resultado = round(resultado)
senao
resultado = trunca(resultado, numero_decimais)
fimse
Assim, caso o usuário decida não arredondar, e utilizar duas casas demais, ele espera os seguintes resultados no cálculo a seguir:
(1.75 + 2.68 + 5.56) / 3 == 3.33
(1.75 + 2.68 + 5.55) / 3 == 3.32
...e caso decida arredondar, ele espera:
(1.75 + 2.68 + 5.56) / 3 == 3.33
(1.75 + 2.68 + 5.55) / 3 == 3.33
Irei procurar agora pelo termo "BigDecimal JavaScript" que o Washington sugeriu.
--
Grupo de jQuery Brasil.
REGRAS: http://groups.google.com/group/jquery-br/web/regras-do-grupo
USE O JSBIN.COM PARA CÓDIGOS.
Email: jque...@googlegroups.com
Biba: jquery-br+...@googlegroups.com
Site: http://groups.google.com/group/jquery-br?hl=pt-BR
Ruan, toPrecision não é aceitável porque ele define o número total de dígitos, e eu posso ter qualquer número de dígitos a esquerda da vírgula.
Reparei agora que o arredondamento por parte do usuário só será necessário nos cálculos em que houverem divisão. Assim não tem problema eu apenas arredondar o resultado da soma previamente.
Só estou pensando agora se uso toFixed() ou se uso um Math.round() juntamente com uma potência de 10 (como o Ruan sugeriu previamente):
parseFloat( soma.toFixed(2) )
ou
Math.round(soma * Math.pow(10,2)) / Math.pow(10,2)
Vou fazer mais alguns testes e optar pela solução mais rápida.
Obrigado a todos pela ajuda.
Criei um método para calcular decimais evitando o erro acima.
O método utiliza uma solução baseada na primeira proposta do Ruan, mas ao invés de arredondar (pois a idéia é justamente evitar o arredondamento) eu transformo o número em inteiro multiplicando por uma potência de 10, e divido o resultado posteriormente pela mesma potência.
Exemplo de uso:
var result = 1.75.sumFloat( 2.68 ).sumFloat( 5.56 );