CodeGym/Blog Java/Random-ES/BigDecimal en Java
Autor
Oleksandr Miadelets
Head of Developers Team at CodeGym

BigDecimal en Java

Publicado en el grupo Random-ES
¡Hola! En la lección de hoy, hablaremos sobre los números grandes. No, quiero decir REALMENTE GRANDE. Anteriormente nos hemos encontrado repetidamente con la tabla de rangos de valores para tipos de datos primitivos. Se parece a esto:
tipo primitivo Tamaño en memoria Rango de valores
byte 8 bits -128 a 127
corto 16 bits -32768 a 32767
carbonizarse 16 bits 0 a 65536
En t 32 bits -2147483648 al 2147483647
largo 64 bits -9223372036854775808 al 9223372036854775807
flotar 32 bits (2 elevado a -149) a ((2 elevado a -23) * 2 elevado a 127)
doble 64 bits (-2 elevado a 63) a ((2 elevado a 63) - 1)
booleano 8 (cuando se usa en matrices), 32 (cuando no se usa en matrices) verdadero o falso
El tipo de datos entero más espacioso es el long . Cuando se trata de números de punto flotante, es el doble . Pero, ¿y si el número que necesitamos es tan grande que ni siquiera cabe en un largo ? El tipo de datos Long tiene un rango bastante amplio de valores posibles, pero todavía está limitado a 64 bits. ¿Qué necesitamos si nuestro Número muy grande requiere 100 bits? Afortunadamente, no necesitamos inventar nada. Para casos como este, Java tiene dos clases especiales: BigInteger (para enteros) y BigDecimal(para números de punto flotante). ¿Qué los hace especiales? En primer lugar, en teoría, no tienen un tamaño máximo. Decimos "en teoría", porque no hay computadoras con memoria infinita. Y si su programa crea un número mayor que la cantidad de memoria disponible, entonces, por supuesto, el programa no funcionará. Pero tales casos son poco probables. Como resultado, podemos decir que BigInteger y BigDecimal pueden representar números de tamaño virtualmente ilimitado. ¿Para qué sirven estas clases? En primer lugar, para cálculos con requisitos de precisión extremadamente rigurosos. Por ejemplo, la vida humana puede depender de la precisión de los cálculos en algunos programas (por ejemplo, software que controla aviones, cohetes o equipos médicos). Entonces, si el lugar decimal 150 es importante, entonces BigDecimales la mejor opción. Además, los objetos de esta clase se utilizan a menudo en el mundo de las finanzas, donde el cálculo preciso incluso de los valores más pequeños también es extremadamente importante. ¿Cómo trabaja con objetos BigInteger y BigDecimal y necesita saber sobre ellos? Los objetos de estas clases se crean así:
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);
   }
}
Pasar una cadena al constructor es solo una opción posible. Aquí usamos cadenas, porque nuestros números exceden los valores máximos para long y double , y necesitamos alguna forma de explicarle al compilador qué número queremos crear :) Simplemente pasando el número 1111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111111 al constructor no funcionará: Java intentará meter el número pasado en uno de los tipos de datos primitivos, pero no encajará en ninguno de ellos. Es por eso que usar una cadena para pasar el número deseado es una buena opción. Ambas clases pueden extraer automáticamente valores numéricos de las cadenas pasadas. Otro punto importante a recordar cuando se trabaja con clases de números grandes es que sus objetos son inmutables ( Immutable ). Ya estás familiarizado con la inmutabilidad gracias a tu experiencia con la clase String y las clases contenedoras 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);

   }
}
Salida de la consola:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Como era de esperar, nuestro número no ha cambiado. Para realizar la operación de suma, debe crear un nuevo objeto para recibir el resultado de la operación.
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);

   }
}
Salida de la consola:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Mira, ahora todo funciona como debería :) Por cierto, ¿te diste cuenta de lo inusual que se ve la operación de suma?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
Este es otro punto importante. Las clases de números grandes no usan los operadores + - * /. En su lugar, proporcionan un conjunto de métodos. Conozcamos los principales (como siempre, puede encontrar una lista completa de métodos en la documentación de Oracle: aquí y aquí ).
  1. métodos para operaciones aritméticas: sumar() , restar() , multiplicar() , dividir() . Estos métodos se utilizan para realizar sumas, restas, multiplicaciones y divisiones, respectivamente.

  2. doubleValue() , intValue() , floatValue() , longValue() , etc. se utilizan para convertir un gran número en uno de los tipos primitivos de Java. Tenga cuidado al usar estos métodos. ¡No te olvides de las diferencias en el tamaño de los bits!

    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);
    
       }
    }

    Salida de la consola:

    8198552921648689607
  3. min() y max() te permiten encontrar el valor mínimo y máximo de dos números grandes.
    ¡Tenga en cuenta que estos métodos no son 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));
    
       }
    }

    Salida de la consola:

    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

Comportamiento de redondeo BigDecimal

Este tema tiene su propia sección separada, ya que redondear números grandes y configurar el comportamiento de redondeo no es tan simple. Puede usar el método setScale() para establecer la cantidad de lugares decimales para un BigDecimal . Por ejemplo, supongamos que queremos que el número 111.5555555555 tenga tres dígitos después del punto decimal. Sin embargo, no podemos lograr lo que queremos pasando el número 3 como argumento al método setScale() . Como se mencionó anteriormente, BigDecimales para representar números con estrictos requisitos de precisión computacional. En su forma actual, nuestro número tiene 10 dígitos después del punto decimal. Queremos eliminar 7 de ellos y quedarnos solo con 3. En consecuencia, además del número 3, debemos pasar el modo de redondeo. BigDecimal tiene un total de 8 modos de redondeo. ¡Eso es mucho! Pero si realmente necesita afinar la precisión de sus cálculos, tendrá todo lo que necesita. Entonces, aquí están los 8 modos de redondeo que ofrece BigDecimal :
  1. ROUND_CEILING — redondea hacia arriba

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN — redondea hacia cero

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR — redondea hacia abajo

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

  4. ROUND_HALF_UP — redondea hacia arriba si el número después del punto decimal >= 0.5

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN — redondea hacia arriba si el número después del punto decimal > 0.5

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN : el redondeo depende del número a la izquierda del punto decimal. Si el número de la izquierda es par, el redondeo será hacia abajo. Si el número a la izquierda del punto decimal es impar, el redondeo será hacia arriba.

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

    El número a la izquierda del lugar decimal es 2 (par). El número se redondea hacia abajo. Queremos 0 decimales, por lo que el resultado es 2.

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

    El número a la izquierda del punto decimal es 3 (impar). El número se redondea. Queremos 0 decimales, por lo que el resultado es 4.

  7. ROUND_UNNECCESSARY : este modo se usa cuando debe pasar un modo de redondeo a un método, pero no es necesario redondear el número. Si intenta redondear un número con el modo ROUND_UNNECCESSARY establecido, se lanza una ArithmeticException.

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP — redondea desde cero.

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

Comparar números grandes

Esto también es importante. Recordará que usamos el método equals() para comparar objetos en Java. La implementación la proporciona el propio lenguaje (para las clases estándar de Java) o el programador la anula. Pero en el caso de objetos BigDecimal , no se recomienda usar el método equals() para realizar comparaciones. Esto se debe a que el método BigDecimal.equals() devuelve verdadero solo si los 2 números tienen el mismo valor y escala: Comparemos el comportamiento del método equals() para las clases Double 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));

   }
}
Salida de la consola:
true
false
Como puede ver, para BigDecimal , ¡los números 1.5 y 1.50 resultaron ser desiguales! Esto se debió precisamente a los detalles de la implementación del método equals() en la clase BigDecimal . Para una comparación más precisa de dos objetos BigDecimal , es mejor usar el 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));

   }
}
Salida de la consola:
0
El método compareTo() devolvió 0, lo que significa que 1,5 y 1,50 son iguales. ¡Y este es el resultado que esperábamos! :) Eso concluye nuestra lección de hoy. ¡Ahora es el momento de volver a las tareas! :)
Comentarios
  • Populares
  • Nuevas
  • Antiguas
Debes iniciar sesión para dejar un comentario
Esta página aún no tiene comentarios