CodeGym /Blogue Java /Random-PT /BigDecimal em Java
John Squirrels
Nível 41
San Francisco

BigDecimal em Java

Publicado no grupo Random-PT
Oi! Na lição de hoje, falaremos sobre grandes números. Não, quero dizer REALMENTE GRANDE. Anteriormente, encontramos repetidamente a tabela de intervalos de valores para tipos de dados primitivos. Se parece com isso:
tipo primitivo Tamanho na memória Faixa de valor
byte 8 bits -128 a 127
curto 16 bits -32768 a 32767
Caracteres 16 bits 0 a 65536
int 32 bits -2147483648 a 2147483647
longo 64 bits -9223372036854775808 a 9223372036854775807
flutuador 32 bits (2 elevado a -149) para ((2 elevado a -23) * 2 elevado a 127)
dobro 64 bits (-2 elevado a 63) para ((2 elevado a 63) - 1)
boleano 8 (quando usado em arrays), 32 (quando não usado em arrays) verdadeiro ou falso
O tipo de dado inteiro com mais espaço é o long . Quando se trata de números de ponto flutuante, é o double . Mas e se o número de que precisamos for tão grande que nem cabe em um long ? O tipo de dados Long tem um intervalo bastante grande de valores possíveis, mas ainda é limitado a 64 bits. O que precisamos inventar se nosso número muito grande exigir 100 bits? Felizmente, não precisamos inventar nada. Para casos como este, Java possui duas classes especiais: BigInteger (para inteiros) e BigDecimal(para números de ponto flutuante). O que os torna especiais? Em primeiro lugar, em teoria, eles não têm tamanho máximo. Dizemos "em teoria", porque não existem computadores com memória infinita. E se o seu programa criar um número maior que a quantidade de memória disponível, o programa não funcionará, é claro. Mas tais casos são improváveis. Como resultado, podemos dizer que BigInteger e BigDecimal podem representar números de tamanho praticamente ilimitado. Para que servem essas classes? Em primeiro lugar, para cálculos com requisitos de precisão extremamente rigorosos. Por exemplo, a vida humana pode depender da precisão dos cálculos em alguns programas (por exemplo, software que controla aviões, foguetes ou equipamentos médicos). Portanto, se a 150ª casa decimal for importante, BigDecimalé a melhor escolha. Além disso, objetos dessa classe são frequentemente usados ​​no mundo das finanças, onde o cálculo preciso até mesmo dos menores valores também é extremamente importante. Como você trabalha com objetos BigInteger e BigDecimal e precisa saber sobre eles? Os objetos dessas classes são criados assim:

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
Passar uma string para o construtor é apenas uma opção possível. Aqui usamos strings, pois nossos números excedem os valores máximos para long e double , e precisamos sim de alguma forma explicar para o compilador qual número queremos criar :) 1111111111111111111111111111111111111111111111111111111111111111111111111 para o construtor não funcionará: Java tentará colocar o número passado em um dos tipos de dados primitivos, mas não se encaixará em nenhum deles. Por isso usar uma string para passar o número desejado é uma boa opção. Ambas as classes podem extrair automaticamente valores numéricos das strings passadas. Outro ponto importante a ser lembrado ao trabalhar com classes de números grandes é que seus objetos são imutáveis ​​( Immutable ). Você já está familiarizado com a imutabilidade graças à sua experiência com a classe String e as classes wrapper para tipos primitivos (Integer, Long, etc.).

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
Saída do console:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
Como seria de esperar, nosso número não mudou. Para realizar a operação de adição, deve-se criar um novo objeto para receber o resultado da operação.

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
Saída do console:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Veja, agora tudo funciona como deveria :) A propósito, você notou como a operação de adição parece incomum?

BigInteger result = integer.add(BigInteger.valueOf(33333333));
Este é outro ponto importante. Classes de números grandes não usam os operadores + - * /. Em vez disso, eles fornecem um conjunto de métodos. Vamos conhecer os principais (como sempre, você encontra a lista completa dos métodos na documentação do Oracle: aqui e aqui ).
  1. métodos para operações aritméticas: adicionar() , subtrair() , multiplicar() , dividir() . Esses métodos são usados ​​para realizar adição, subtração, multiplicação e divisão, respectivamente.

  2. doubleValue() , intValue() , floatValue() , longValue() , etc. são usados ​​para converter um grande número em um dos tipos primitivos de Java. Tenha cuidado ao usar esses métodos. Não se esqueça das diferenças no tamanho do bit!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }
    

    Saída do console:

    
    8198552921648689607
    
  3. min() e max() permitem encontrar o valor mínimo e máximo de dois números grandes.
    Observe que esses métodos não são estáticos!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }
    

    Saída do console:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
    

Comportamento de arredondamento BigDecimal

Este tópico tem sua própria seção separada, pois arredondar números grandes e configurar o comportamento de arredondamento não são tão simples. Você pode usar o método setScale() para definir o número de casas decimais para um BigDecimal . Por exemplo, suponha que queremos que o número 111,5555555555 tenha três dígitos após o ponto decimal. Porém, não podemos conseguir o que queremos passando o número 3 como argumento para o método setScale() . Como mencionado acima, BigDecimalé para representar números com requisitos rígidos de precisão computacional. Em sua forma atual, nosso número tem 10 dígitos após o ponto decimal. Queremos descartar 7 deles e manter apenas 3. Assim, além do número 3, devemos passar pelo modo de arredondamento. BigDecimal tem um total de 8 modos de arredondamento. Isso é muito! Mas se você realmente precisar ajustar a precisão de seus cálculos, terá tudo o que precisa. Então, aqui estão os 8 modos de arredondamento oferecidos pelo BigDecimal :
  1. ROUND_CEILING — arredonda para cima

    
    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
    
  2. ROUND_DOWN — arredonda para zero

    
    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
    
  3. ROUND_FLOOR — arredonda para baixo

    
     111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
    
    

  4. ROUND_HALF_UP — arredonda para cima se o número após a vírgula >= 0,5

    
    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
    
  5. ROUND_HALF_DOWN — arredonda para cima se o número após a vírgula > 0,5

    
    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
    
  6. ROUND_HALF_EVEN — o arredondamento depende do número à esquerda do ponto decimal. Se o número à esquerda for par, o arredondamento será para baixo. Se o número à esquerda da vírgula for ímpar, o arredondamento será superior.

    
    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2
    

    O número à esquerda da casa decimal é 2 (par). O número é arredondado para baixo. Queremos 0 casas decimais, então o resultado é 2.

    
    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4
    

    O número à esquerda do ponto decimal é 3 (ímpar). O número é arredondado para cima. Queremos 0 casas decimais, então o resultado é 4.

  7. ROUND_UNNECCESSARY — Este modo é usado quando você deve passar um modo de arredondamento para um método, mas o número não precisa ser arredondado. Se você tentar arredondar um número com o modo ROUND_UNNECCESSARY definido, uma ArithmeticException será lançada.

    
    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
    
  8. ROUND_UP — arredonda a partir de zero.

    
    111.5551 -> setScale(3, ROUND_UP) -> 111.556
    

Comparando números grandes

Isso também é importante. Você deve se lembrar que usamos o método equals() para comparar objetos em Java. A implementação é fornecida pela própria linguagem (para classes Java padrão) ou substituída pelo programador. Mas no caso de objetos BigDecimal , não é recomendado usar o método equals() para comparações. Isso porque o método BigDecimal.equals() retorna true somente se os 2 números tiverem o mesmo valor e escala: Vamos comparar o comportamento do método equals() para as classes Double e BigDecimal :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));
      
   }
}
Saída do console:

true 
false
Como você pode ver, para BigDecimal , os números 1,5 e 1,50 acabaram sendo desiguais! Isso ocorreu precisamente devido às especificidades da implementação do método equals() na classe BigDecimal . Para uma comparação mais precisa de dois objetos BigDecimal , é melhor usar o método compareTo() :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
Saída do console:

0
O método compareTo() retornou 0, o que significa que 1,5 e 1,50 são iguais. E esse é o resultado que esperávamos! :) Isso conclui nossa lição de hoje. Agora é hora de voltar às tarefas! :)
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION