JavaRush /Java Blog /Random-IT /BigDecimal in Java

BigDecimal in Java

Pubblicato nel gruppo Random-IT
Ciao! Nella lezione di oggi parleremo di grandi numeri. No, riguardo a quelli VERAMENTE GRANDI. In precedenza , abbiamo visto più di una volta una tabella di intervalli di valori per i tipi di dati primitivi. Sembra questo:
Tipo primitivo Dimensioni in memoria Intervallo di valori
byte 8 bit da -128 a 127
corto 16 bit da -32768 a 32767
car 16 bit da 0 a 65536
int 32 bit da -2147483648 a 2147483647
lungo 64 bit da -9223372036854775808 a 9223372036854775807
galleggiante 32 bit da (2 alla potenza -149) a ((2-2 alla potenza -23)*2 alla potenza 127)
Doppio 64 bit da (-2 alla potenza di 63) a ((2 alla potenza di 63) - 1)
booleano 8 (se utilizzato in array), 32 (se utilizzato in non array) vero o falso
Se parliamo di numeri interi, il tipo di dati più capiente è long e quando parliamo di numeri in virgola mobile, double . Ma cosa succede se il numero di cui abbiamo bisogno è così grande da non rientrare nemmeno nel lungo ? La gamma dei possibili valori Long è piuttosto ampia, ma comunque limitata a una certa dimensione: 64 bit. Cosa possiamo ottenere se il nostro Very Large Number pesa 100 bit? Fortunatamente non è necessario inventare nulla. In Java, per questi casi sono state create due classi speciali: BigInteger (per numeri interi) e BigDecimal (per numeri in virgola mobile). Qual è la loro caratteristica? Innanzitutto, teoricamente non hanno una dimensione massima. In teoria, perché non esistono computer con memoria infinita. E se crei nel programma un numero più grande della dimensione della memoria del computer, ovviamente, il programma non funzionerà. Ma tali casi sono improbabili. Pertanto, possiamo dire che la dimensione dei numeri BigIntegerè BigDecimalpraticamente illimitata. A cosa servono queste classi? Innanzitutto per calcoli con requisiti di precisione estremamente elevati. Esistono, ad esempio, programmi in cui la vita umana può dipendere dall'accuratezza dei calcoli (software per aerei e razzi o per apparecchiature mediche). Quindi se anche la 150esima cifra decimale gioca un ruolo importante BigDecimalè la scelta migliore. Inoltre, molto spesso questi oggetti vengono utilizzati nel mondo della finanza, dove anche la precisione dei calcoli fino ai valori più piccoli è estremamente importante. Come lavorare con gli oggetti BigIntegere BigDecimalcosa è importante ricordare di essi? Gli oggetti di queste classi vengono creati in questo modo:
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);
   }
}
Passare una stringa come parametro è solo uno dei possibili costruttori. Here we use strings because our numbers exceed the maximum values long​​and double, and somehow we need to explain to the compiler exactly what number we want to get :) Just pass the number 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 to the constructor 1111111111111111111111111111111111111111111111111111111111111111111 will not work: Java will try to "adatta" il numero passato a uno dei tipi di dati primitivi, ma non si adatterà a nessuno di essi. Pertanto, utilizzare una stringa per trasmettere il numero desiderato è una buona opzione. Entrambe le classi possono estrarre automaticamente valori numerici dalle stringhe passate. Un altro punto importante da ricordare quando si lavora con classi con grandi numeri è che i loro oggetti sono immutabili ( Immutable) . Conosci già bene il principio di immutabilità attraverso l'esempio di una classe Stringe di classi wrapper per primitive (Integer, Long e altre).
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);

   }
}
Uscita console:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
I nostri numeri non sono cambiati, come ci si aspetterebbe. Affinché l'operazione di addizione abbia esito positivo, è necessario creare un nuovo oggetto e assegnargli il risultato dell'addizione.
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);

   }
}
Uscita console:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Ora tutto funziona come dovrebbe :) A proposito, hai notato quanto appare insolita l'operazione di addizione?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
Questo è un altro punto importante. Le classi con numeri grandi non utilizzano gli operatori +-*/ nelle loro operazioni, ma forniscono invece un insieme di metodi. Diamo un'occhiata a quelli principali (potete, come sempre, trovare l'elenco completo dei metodi nella documentazione di Oracle: qui e qui ).
  1. metodi per eseguire operazioni aritmetiche: add() , subtract(), multiply(), divide(). Utilizzato rispettivamente per le operazioni di addizione, sottrazione, moltiplicazione e divisione.

  2. doubleValue(), intValue(), floatValue(), longValue()eccetera. - Utilizzato per convertire un numero elevato in un tipo primitivo Java. Fai attenzione quando li usi e ricorda la differenza di capacità!

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

    Uscita console:

    
    8198552921648689607
  3. min()e max()- consentono di trovare il valore minimo e massimo di due grandi numeri passati.
    Nota: i metodi non sono statici!

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

    Uscita console:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

Controllo dell'arrotondamento BigDecimal

Questo argomento è incluso in una sezione separata, poiché arrotondare grandi numeri e modificarli non è una cosa così semplice. È possibile impostare il numero di cifre decimali per un numero BigDecimalutilizzando il comando setScale(). Ad esempio, vogliamo impostare la precisione del numero 111.5555555555 su tre cifre decimali. Tuttavia non potremo passare il numero 3 come argomento al metodo setScale()e risolvere così il nostro problema. Come accennato in precedenza, BigDecimalquesti sono numeri per calcoli con maggiore precisione. Nella sua forma attuale, il nostro numero ha 10 cifre decimali. Vogliamo scartarne 7 e lasciarne solo 3. Pertanto, oltre al numero 3, dobbiamo passare come parametro la modalità di arrotondamento . Sono disponibili 8 modalità di arrotondamento in totale BigDecimal. Parecchio! Ma se hai bisogno di ottimizzare davvero la precisione dei calcoli nel programma, avrai tutto ciò di cui hai bisogno. Quindi, ecco le 8 modalità di arrotondamento disponibili in BigDecimal:
  1. ROUND_CEILING- arrotondare

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN- scarico scarto

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR- arrotondamento per difetto

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

  4. ROUND_HALF_UP— arrotondamento per eccesso se il numero dopo la virgola >= 0,5

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN— arrotondamento per eccesso se il numero dopo la virgola > 0,5

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN— l'arrotondamento dipenderà dal numero a sinistra della virgola decimale. Se il numero a sinistra è pari, l'arrotondamento verrà effettuato per difetto. Se il numero a sinistra della virgola decimale è dispari, verrà arrotondato per eccesso.

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

    Il numero a sinistra della virgola decimale - 2 - è pari. L'arrotondamento avviene per difetto. Poiché richiediamo 0 cifre decimali, il risultato sarà 2.

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

    Il numero a sinistra della virgola decimale - 3 - è dispari. L'arrotondamento avviene verso l'alto. Poiché richiediamo 0 cifre decimali, il risultato sarà 4.

  7. ROUND_UNNECCESSARY— utilizzato nei casi in cui la modalità di arrotondamento deve essere passata a qualche metodo, ma il numero non necessita di arrotondamento. Se provi ad arrotondare un numero quando è impostata la modalità ROUND_UNNECCESSARY, viene generata un'ArithmeticException.

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP- arrotondare.

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

Confronto di grandi numeri

Anche questa domanda è importante. Ricordi già che il metodo viene utilizzato per confrontare oggetti in Java equals(). Viene fornito dal linguaggio stesso (nel caso delle classi integrate di Java) o sovrascritto dal programmatore. Ma nel caso degli oggetti di classe, non è consigliabile BigDecimalutilizzare il metodo equals()per il confronto. La ragione di ciò è che il BigDecimal.equals()metodo a due numeri restituisce vero solo se i due numeri hanno lo stesso valore e scala : Confrontiamo il comportamento dei metodi 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));

   }
}
Uscita console:

true
false
Come puoi vedere, i numeri 1,5 e 1,50 nel caso c BigDecimalsi sono rivelati disuguali! Ciò è accaduto proprio a causa delle specificità del metodo equals()nella classe BigDecimal. Per un confronto più corretto tra i due BigDecimalè meglio utilizzare il metodo 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));

   }
}
Uscita console:

0
Il metodo compareTo()ha restituito 0, che significa uguale a 1,5 e 1,50. Questo è il risultato su cui contavamo! :) Questo conclude la nostra lezione di oggi. È ora di tornare ai compiti! :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION