Andei pesquisando GUJ e Google afora, mas ainda estou com o mesmo problema para fazer um trunc (truncate) um valor decimal (double).
Alguns casos funciona, mas em outro em específico não.
Vai ai as soluções de truncamento por precisão (casas decimais) que usei, mas o resultado foi o mesmo:
public static double trunc( double val, int precision ) {
BigDecimal bd = new BigDecimal(val).setScale(precision,BigDecimal.ROUND_DOWN);
return bd.doubleValue();
}
OU
[quote=Bruno Laturner]Como disse, depender dos tipos do java pra precisão de cálculos não dá muito certo.
O que pode fazer é um assertEquals com uma margem de erro.[/quote]
Hahahaha… margem de erro? Estou falando de cálculos financeiros, não de cálculos estatísticos.
O que adianta garantir o teste e falhar na execução? POG!
[quote=danieldestro][quote=Bruno Laturner]Como disse, depender dos tipos do java pra precisão de cálculos não dá muito certo.
O que pode fazer é um assertEquals com uma margem de erro.[/quote]
Hahahaha… margem de erro? Estou falando de cálculos financeiros, não de cálculos estatísticos.
O que adianta garantir o teste e falhar na execução? POG![/quote]
Como disse, depender dos tipos nativos do Java para precisão não dá certo. Eles foram projetados para velocidade de execução, e não corretude.
A solução é nunca usar um float nem um double.
O ideal seria usar um value object(do Fowler) Money ou Currency, implementado por baixo com um BigDecimal, em que todas as operações recebam e retornem um outro Money.
[code]
public static BigDecimal trunc( BigDecimal val, int precision ) {
if( precision <= 0 ) {
throw new IllegalArgumentException(“Precisão deve ser maior que zero”);
}
return val.setScale(precision,BigDecimal.ROUND_DOWN);
}
public static double trunc( double val, int precision ) {
return trunc( BigDecimal.valueOf(val), precision ).doubleValue(); // resolvido
}
public static BigDecimal trunc( String val, int precision ) {
return trunc(new BigDecimal(val), precision);
}[/code]
editado: Acabei olhando o fonte do BigDecimal para ver como poderia corrigir.
Uma coisa que aprendi ao custo de perder alguns fios de cabelo, foi o de nunca utilizar float e double (e por sinal algo que pouca gente vai concordar). Na minha opinião a forma que esses números são armazenados é simplesmente idiota, a precisão não é bem definida para eles.
Sempre uso BigDecimal para cálculos finaceiros e cálculos que exijam precisão. float e double só servem em lugares onde um pequeno erro é aceitável em nome da performance, tal como em animações de jogos, e mesmo assim é preciso tomar-se alguns cuidados.
Gostaria que o java tivesse uma classe BigRational, armazenando um numerador e um denominador, pois atualmente não há forma de se representar 1/3, 1/7 ou 1/11 em java nem com float, nem com double e nem com BigDecimal, mas se esta classe existisse, BigDecimal não precisaria mais existir.
Se não puder evitar o float e double, tente usar o modificador [size=18]strictfp[/size].