Recentemente, estudei os problemas de cálculo de ponto flutuante do Java, consultei informações relevantes na Internet, resumi e passei por alguma classificação e depuração e, finalmente, concluí este artigo. Todos são bem-vindos para apontar os erros e problemas.
Em Java, as variáveis declaradas por float são números de ponto flutuante de precisão simples e as variáveis declaradas por double são números de ponto flutuante de precisão dupla. Como o nome indica, as entidades do tipo double ocupam o dobro do espaço de memória de float. float tem 4 bytes e double tem 8 bytes. Os dados do tipo float e double não podem representar com precisão os resultados do cálculo. Isso ocorre porque float e double são cálculos imprecisos. Você pode ver isso através do seguinte código:
Copie o código do código da seguinte forma:
Teste de classe pública
{
público estático void principal(String[] args)
{
System.out.println(0,05 + 0,01);
System.out.println(1,0 - 0,42);
System.out.println(4.015 * 100);
System.out.println(123,3/100);
}
}
O resultado da corrida é:
0,06000000000000005
0,580000000000001
401.49999999999994
1.23299999999999999
Para obter o efeito desejado, podemos tentar usar java.text.DecimalFormat para formatar números de ponto flutuante:
DecimalFormat pode formatar números de acordo com um determinado formato. Os caracteres de formatação comumente usados são #, 0, etc. exemplo:
Copie o código do código da seguinte forma:
System.out.println(new java.text.DecimalFormat("0.00").format(3.125));
System.out.println(new java.text.DecimalFormat("0.00").format(3.135));
Mas o resultado é:
3.12
3.14
Isso ocorre porque DecimalFormat usa arredondamento meio par (ROUND_HALF_EVEN). Simplificando, ele depende do número par mais próximo ao arredondar para 5. Portanto, números de ponto flutuante confiáveis não podem ser obtidos usando DecimalForamt. Finalmente podemos considerar o uso de BigDecimal para cálculos mais precisos:
BigDecimal fornece vários construtores relacionados a números de ponto flutuante:
Copie o código do código da seguinte forma:
BigDecimal(double val) Traduz um double em um BigDecimal.
BigDecimal(String val) Traduz a representação String de um BigDecimal em um BigDecimal.
No entanto, usar parâmetros duplos para criar objetos resultará em valores imprecisos. Somente a criação de objetos por meio de String é a mais precisa.
Por exemplo:
Copie o código do código da seguinte forma:
BigDecimal bd1 = novo BigDecimal (0,05);
System.out.println(bd1.toString());
BigDecimal bd2=new BigDecimal("0,05");
System.out.println(bd2.toString());
Obtenha o resultado:
0,050000000000000277555756156289135105907917022705078125
0,05
Portanto, em última análise, precisamos usar String para criar objetos, para que os resultados obtidos sejam mais precisos. Além disso, se for um número duplo, também podemos usar: BigDecimal.valueOf(double val). O motivo é muito simples.
Copie o código do código da seguinte forma:
valor BigDecimal estático públicoOf (val duplo)
{
retornar novo BigDecimal(Double.toString(val));
}
A última coisa a observar é: a adição, subtração, multiplicação e divisão de BigDecimal, na verdade, retornam um novo objeto BigDecimal. Como BigDecimal é imutável, um novo objeto será gerado durante cada operação, portanto, um .add(b); é executado, a não salva o valor após a operação de adição. O uso correto deve ser a=a.add(b).