JavaRush /Blogue Java /Random-PT /BigDecimal em Java

BigDecimal em Java

Publicado no grupo Random-PT
Olá! Na palestra de hoje falaremos sobre grandes números. Não, sobre os REALMENTE GRANDES. Anteriormente , vimos uma tabela de intervalos de valores para tipos de dados primitivos mais de uma vez. Se parece com isso:
Tipo primitivo Tamanho na memória Faixa de valores
byte 8 bits -128 a 127
curto 16 bits para -32768 a 32767
Caracteres 16 bits de 0 a 65536
interno 32 bits de -2147483648 a 2147483647
longo 64 bits de -9223372036854775808 a 9223372036854775807
flutuador 32 bits de (2 elevado a -149) a ((2-2 elevado a -23)*2 elevado a 127)
dobro 64 bits de (-2 elevado a 63) a ((2 elevado a 63) - 1)
boleano 8 (quando usado em arrays), 32 (quando usado em não arrays) verdadeiro ou falso
Se estamos falando de números inteiros, o tipo de dados com maior capacidade é long e, quando falamos de números de ponto flutuante, double . Mas e se o número que precisamos for tão grande que nem cabe em long ? A faixa de valores Long possíveis é bastante grande, mas ainda limitada a um determinado tamanho - 64 bits. O que podemos fazer se nosso número muito grande pesa 100 bits? Felizmente, você não precisa inventar nada. Em Java, duas classes especiais foram criadas para tais casos - BigInteger (para números inteiros) e BigDecimal (para números de ponto flutuante). Qual é a sua característica? Em primeiro lugar, teoricamente não têm tamanho máximo. Teoricamente, porque não existem computadores com memória infinita. E se você criar um número no programa maior que o tamanho da memória do computador, é claro que o programa não funcionará. Mas tais casos são improváveis. Portanto, podemos dizer que o tamanho dos números BigIntegeré BigDecimalpraticamente ilimitado. Para que servem essas aulas? Em primeiro lugar, para cálculos com requisitos de precisão extremamente elevados. Existem, por exemplo, programas em que a vida humana pode depender da precisão dos cálculos (softwares para aviões e foguetes ou para equipamentos médicos). Portanto, mesmo que a 150ª casa decimal desempenhe um papel importante, BigDecimalé a melhor escolha. Além disso, muitas vezes esses objetos são utilizados no mundo das finanças, onde a precisão dos cálculos até os menores valores também é extremamente importante. Como trabalhar com objetos BigIntegere BigDecimalo que é importante lembrar 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 como parâmetro é apenas um dos construtores possíveis. Aqui usamos strings porque nossos números excedem os valores máximos longe double, e de alguma forma precisamos explicar ao compilador exatamente qual número queremos obter :) Basta passar o número 111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111 para o construtor 11111111111111111111111111111111111111111111111111111111111111111 não funcionará: Java tentará “encaixa” o número passado em um dos tipos de dados primitivos, mas não cabe em nenhum deles. Portanto, utilizar uma string para passar o número desejado é uma boa opção. Ambas as classes podem extrair automaticamente valores numéricos de strings passadas. Outro ponto importante a lembrar ao trabalhar com classes de grande número é que seus objetos são imutáveis ​​( Immutable) . Você já conhece bem o princípio da imutabilidade através do exemplo de uma classe Stringe classes wrapper para primitivas (Integer, Long e outras).
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:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Nossos números não mudaram, como seria de esperar. Para que a operação de adição seja bem-sucedida, você deve criar um novo objeto e atribuir a ele o resultado da adiçã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:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
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 suas operações, mas fornecem um conjunto de métodos. Vamos dar uma olhada nos principais (você pode, como sempre, encontrar uma lista completa de métodos na documentação do Oracle: aqui e aqui ).
  1. métodos para realizar operações aritméticas: add() , subtract(), multiply(), divide(). Usado para operações de adição, subtração, multiplicação e divisão, respectivamente.

  2. doubleValue(), intValue(), floatValue(), longValue()etc - Usado para converter um grande número em um tipo primitivo Java. Tenha cuidado ao usá-los e lembre-se da diferença de capacidade!

    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()- permite encontrar o valor mínimo e máximo de dois números grandes passados.
    Observação: os 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

Controle de arredondamento BigDecimal

Este tópico está incluído em uma seção separada, pois arredondar números grandes e ajustá-los não é uma coisa tão simples. Você pode definir o número de casas decimais para um número BigDecimalusando o setScale(). Por exemplo, queremos definir a precisão do número 111,5555555555 com três casas decimais. Porém, não conseguiremos passar o número 3 como argumento para o método setScale()e assim resolver nosso problema. Conforme mencionado acima, BigDecimalestes são números para cálculos com maior precisão. Em sua forma atual, nosso número possui 10 casas decimais. Queremos descartar 7 deles e deixar apenas 3. Portanto, além do número 3, devemos passar como parâmetro o modo de arredondamento . Existem 8 modos de arredondamento no total BigDecimal. Bastante! Mas se precisar realmente ajustar a precisão dos cálculos no programa, você terá tudo o que precisa para isso. Então, aqui estão os 8 modos de arredondamento disponíveis em BigDecimal:
  1. ROUND_CEILING- arredondamento para cima

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN- descarte de descarga

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

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

  4. ROUND_HALF_UP— arredondamento 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— arredondamento 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 dependerá do número à esquerda da vírgula. Se o número à esquerda for par, o arredondamento será feito para baixo. Se o número à esquerda da vírgula for ímpar, será arredondado para cima.

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

    O número à esquerda da vírgula – 2 – é par. O arredondamento ocorre para baixo. Como exigimos 0 casas decimais, o resultado será 2.

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

    O número à esquerda da vírgula – 3 – é ímpar. O arredondamento ocorre para cima. Como exigimos 0 casas decimais, o resultado será 4.

  7. ROUND_UNNECCESSARY— utilizado nos casos em que o modo de arredondamento precisa ser passado para algum método, mas o número não necessita de arredondamento. Se você tentar arredondar um número quando o modo ROUND_UNNECCESSARY estiver definido, uma ArithmeticException será lançada.

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP- arredondamento para cima.

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

Comparação de grandes números

Esta questão também é importante. Você já lembra que o método serve para comparar objetos em Java equals(). Ele é fornecido pela própria linguagem (no caso das classes internas do Java) ou substituído pelo programador. Mas no caso de objetos de classe, não é recomendado BigDecimalusar o método equals()para comparação. A razão para isso é que o BigDecimal.equals()método de dois números retorna verdadeiro apenas se os dois números tiverem o mesmo valor e escala : Vamos comparar o comportamento dos métodos equals()y Doublee y 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, os números 1,5 e 1,50 no caso de c BigDecimalrevelaram-se desiguais! Isso aconteceu justamente por causa das especificidades do método equals()na classe BigDecimal. Para uma comparação mais correta dos dois, 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 igual a 1,5 e 1,50. Este é o resultado com que estávamos contando! :) Isso conclui nossa lição de hoje. É hora de voltar às tarefas! :)
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION