logo

Arredondando erros em Java

Compactar muitos números reais infinitos em um número finito de bits requer uma representação aproximada. A maioria dos programas armazena o resultado de cálculos inteiros em 32 ou 64 bits no máximo. Dado qualquer número fixo de bits, a maioria dos cálculos com números reais produzirá quantidades que não podem ser representadas com exatidão usando tantos bits. Portanto, o resultado de um cálculo de ponto flutuante deve muitas vezes ser arredondado para caber novamente na sua representação finita. Este erro de arredondamento é uma característica da computação de ponto flutuante. Portanto, ao lidar com cálculos em números de ponto flutuante (especialmente se os cálculos forem em termos de dinheiro), precisamos cuidar dos erros de arredondamento em uma linguagem de programação. Vejamos um exemplo:

Java
public class Main {  public static void main(String[] args)  {  double a = 0.7;  double b = 0.9;  double x = a + 0.1;  double y = b - 0.1;  System.out.println('x = ' + x);  System.out.println('y = ' + y );  System.out.println(x == y);  } } 


como encontrar coisas escondidas no Android

Saída:



x = 0.7999999999999999  
y = 0.8
false

Aqui a resposta não é o que esperávamos, pois o arredondamento foi feito pelo compilador java.

Razão por trás do erro de arredondamento

Os tipos de dados Float e Double implementam a especificação IEEE de ponto flutuante 754. Isso significa que os números são representados em uma forma como:

SIGN FRACTION * 2 ^ EXP 

0,15625 = (0,00101)2que em formato de ponto flutuante é representado como: 1,01 * 2^-3
Nem todas as frações podem ser representadas exatamente como uma fração de uma potência de dois. Como um exemplo simples 0,1 = (0,000110011001100110011001100110011001100110011001100110011001…)2 e, portanto, não pode ser armazenado dentro de uma variável de ponto flutuante.

Outro exemplo:

java
public class Main {  public static void main(String[] args)  {  double a = 0.7;  double b = 0.9;  double x = a + 0.1;  double y = b - 0.1;  System.out.println('x = ' + x);  System.out.println('y = ' + y );  System.out.println(x == y);  } } 

Saída:

x = 0.7999999999999999  
y = 0.8
false

Outro exemplo:

Java
public class Main {  public static void main(String args[])  {  double a = 1.0;  double b = 0.10;  double x = 9 * b;  a = a - (x);  // Value of a is expected as 0.1  System.out.println('a = ' + a);  } } 

Saída:

a = 0.09999999999999998

Como corrigir erros de arredondamento?

  • Arredonde o resultado: A função Round() pode ser usada para minimizar quaisquer efeitos de imprecisão no armazenamento aritmético de ponto flutuante. O usuário pode arredondar os números para o número de casas decimais exigido pelo cálculo. Por exemplo, ao trabalhar com moeda, você provavelmente arredondaria para 2 casas decimais.
  • Algoritmos e Funções: Use algoritmos numericamente estáveis ​​ou projete suas próprias funções para lidar com tais casos. Você pode truncar/arredondar dígitos dos quais não tem certeza se estão corretos (você também pode calcular a precisão numérica das operações)
  • Classe BigDecimal: Você pode usar o java.math.BigDecimal classe que é projetada para nos dar precisão, especialmente no caso de grandes números fracionários. O programa a seguir mostra como o erro pode ser removido:
Java
import java.math.BigDecimal; import java.math.RoundingMode; public class Main {  public static void main(String args[]) {  BigDecimal a = new BigDecimal('1.0');  BigDecimal b = new BigDecimal('0.10');  BigDecimal x = b.multiply(new BigDecimal('9'));  a = a.subtract(x);  // Rounding to 1 decimal place  a = a.setScale(1 RoundingMode.HALF_UP);  System.out.println('a = ' + a);  } } 


Saída:

0.1

Aqui a = a.setScale(1 RoundingMode.HALF_UP);

Rodadas apara 1 casa decimal usando o modo de arredondamento HALF_UP. Portanto, usar BigDecimal fornece um controle mais preciso sobre as operações aritméticas e de arredondamento, o que pode ser particularmente útil para cálculos financeiros ou outros casos onde a precisão é crucial.

Nota importante:

Math.round arredonda o valor para o número inteiro mais próximo. Como 0,10 está mais próximo de 0 do que de 1, ele é arredondado para 0. Após o arredondamento e divisão por 1,0 o resultado é 0,0. Então você pode notar a diferença entre as saídas com a classe BigDecimal e a função Maths.round.

Java
public class Main {  public static void main(String args[])  {  double a = 1.0;  double b = 0.10;  double x = 9 * b;  a = a - (x);  /* We use Math.round() function to round the answer to  closest long then we multiply and divide by 1.0 to  to set the decimal places to 1 place (this can be done  according to the requirements.*/  System.out.println('a = ' + Math.round(a*1.0)/1.0);  } } 

Saída:

0.0