CodeGym/Blog Java/Aleatoriu/BigDecimal în Java
John Squirrels
Nivel
San Francisco

BigDecimal în Java

Publicat în grup
Bună! În lecția de astăzi, vom vorbi despre numerele mari. Nu, vreau să spun FOARTE MARE. Am întâlnit anterior în mod repetat tabelul cu intervale de valori pentru tipurile de date primitive. Arata cam asa:
Tipul primitiv Dimensiunea în memorie Interval de valori
octet 8 biți -128 până la 127
mic de statura 16 biți -32768 până la 32767
char 16 biți 0 la 65536
int 32 de biți -2147483648 până la 2147483647
lung pe 64 de biți -9223372036854775808 până la 9223372036854775807
pluti 32 de biți (2 la puterea lui -149) la ((2 la puterea lui -23) * 2 la puterea lui 127)
dubla pe 64 de biți (-2 la puterea lui 63) la ((2 la puterea lui 63) - 1)
boolean 8 (când este folosit în matrice), 32 (când nu este utilizat în matrice) adevărat sau fals
Cel mai spațios tip de date întreg este lung . Când vine vorba de numere în virgulă mobilă, este dublu . Dar dacă numărul de care avem nevoie este atât de mare încât nici măcar nu se încadrează într-un lung ? Tipul de date Long are o gamă destul de mare de valori posibile, dar este încă limitat la 64 de biți. Ce trebuie să găsim dacă numărul nostru foarte mare necesită 100 de biți? Din fericire, nu trebuie să inventăm nimic. Pentru cazuri ca acesta, Java are două clase speciale: BigInteger (pentru numere întregi) și BigDecimal(pentru numere în virgulă mobilă). Ce îi face speciali? În primul rând, în teorie, nu au dimensiune maximă. Spunem „în teorie”, pentru că nu există computere cu memorie infinită. Și dacă programul dvs. creează un număr mai mare decât cantitatea de memorie disponibilă, atunci programul nu va funcționa, desigur. Dar astfel de cazuri sunt puțin probabile. Ca rezultat, putem spune că BigInteger și BigDecimal pot reprezenta numere de dimensiuni practic nelimitate. La ce sunt folosite aceste clase? În primul rând, pentru calcule cu cerințe de precizie extrem de riguroase. De exemplu, viața umană poate depinde de acuratețea calculelor din unele programe (de exemplu, software care controlează avioane, rachete sau echipamente medicale). Deci, dacă a 150-a zecimală este importantă, atunci BigDecimaleste cea mai buna alegere. În plus, obiectele din această clasă sunt adesea folosite în lumea finanțelor, unde calculul precis chiar și al celor mai mici valori este, de asemenea, extrem de important. Cum lucrați cu obiectele BigInteger și BigDecimal și trebuie să știți despre ele? Obiectele acestor clase sunt create astfel:
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);
   }
}
Trecerea unui șir către constructor este doar o opțiune posibilă. Aici folosim șiruri de caractere, deoarece numerele noastre depășesc valorile maxime pentru long și double și avem nevoie de o modalitate de a explica compilatorului ce număr dorim să creăm :) Trecând pur și simplu numărul 11111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111 la constructor nu va funcționa: Java va încerca să înghesuie numărul transmis într-unul dintre tipurile de date primitive, dar nu se va potrivi în niciunul dintre ele. De aceea, folosirea unui șir pentru a trece numărul dorit este o opțiune bună. Ambele clase pot extrage automat valori numerice din șirurile transmise. Un alt punct important de reținut atunci când lucrați cu clase cu număr mare este că obiectele lor sunt imuabile ( Immutable ). Sunteți deja familiarizat cu imuabilitatea datorită experienței dvs. cu clasa String și clasele wrapper pentru tipurile primitive (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);

   }
}
Ieșire din consolă:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
După cum v-ați aștepta, numărul nostru nu s-a schimbat. Pentru a efectua operația de adăugare, trebuie să creați un nou obiect pentru a primi rezultatul operației.
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);

   }
}
Ieșire din consolă:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Vezi, acum totul funcționează așa cum ar trebui :) Apropo, ai observat cât de neobișnuit arată operația de adăugare?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
Acesta este un alt punct important. Clasele cu numere mari nu folosesc operatorii + - * /. În schimb, ele oferă un set de metode. Să ne familiarizăm cu principalele (ca întotdeauna, o listă completă a metodelor o găsiți în documentația Oracle: aici și aici ).
  1. metode pentru operații aritmetice: adunare() , scădere() , înmulțire() , împărțire() . Aceste metode sunt folosite pentru a efectua adunarea, scăderea, înmulțirea și, respectiv, împărțirea.

  2. doubleValue() , intValue() , floatValue() , longValue() etc. sunt folosite pentru a converti un număr mare într-unul dintre tipurile primitive ale Java. Aveți grijă când utilizați aceste metode. Nu uitați de diferențele de dimensiune a biților!

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

    Ieșire din consolă:

    8198552921648689607
  3. min() și max() vă permit să găsiți valoarea minimă și maximă a două numere mari.
    Rețineți că aceste metode nu sunt statice!

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

    Ieșire din consolă:

    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

Comportamentul de rotunjire BigDecimal

Acest subiect are propria sa secțiune separată, deoarece rotunjirea numerelor mari și configurarea comportamentului de rotunjire nu sunt atât de simple. Puteți utiliza metoda setScale() pentru a seta numărul de zecimale pentru un BigDecimal . De exemplu, să presupunem că dorim ca numărul 111,5555555555 să aibă trei cifre după virgulă. Cu toate acestea, nu putem realiza ceea ce ne dorim trecând numărul 3 ca argument la metoda setScale() . După cum am menționat mai sus, BigDecimaleste pentru reprezentarea numerelor cu cerințe stricte privind precizia de calcul. În forma sa actuală, numărul nostru are 10 cifre după virgulă zecimală. Vrem să scăpăm 7 dintre ele și să păstrăm doar 3. În consecință, pe lângă numărul 3, trebuie să trecem modul de rotunjire. BigDecimal are un total de 8 moduri de rotunjire. Sunt multe! Dar dacă într-adevăr trebuie să ajustați precizia calculelor dvs., veți avea tot ce aveți nevoie. Deci, iată cele 8 moduri de rotunjire oferite de BigDecimal :
  1. ROUND_CEILING — rotunjește în sus

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN — se rotunjește spre zero

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR — se rotunjește în jos

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

  4. ROUND_HALF_UP — rotunjește în sus dacă numărul după virgulă zecimală >= 0,5

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN — rotunjește în sus dacă numărul după virgulă zecimală > 0,5

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN — rotunjirea depinde de numărul din stânga punctului zecimal. Dacă numărul din stânga este par, rotunjirea va fi în jos. Dacă numărul din stânga punctului zecimal este impar, atunci rotunjirea va fi în sus.

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

    Numărul din stânga zecimalei este 2 (par). Numărul este rotunjit în jos. Vrem 0 zecimale, deci rezultatul este 2.

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

    Numărul din stânga punctului zecimal este 3 (impar). Numărul este rotunjit în sus. Vrem 0 zecimale, deci rezultatul este 4.

  7. ROUND_UNNECESSARY — Acest mod este utilizat atunci când trebuie să treceți un mod de rotunjire unei metode, dar numărul nu trebuie să fie rotunjit. Dacă încercați să rotunjiți un număr cu modul ROUND_UNNECESSARY setat, este lansată o excepție ArithmeticException.

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP — se rotunjește de la zero.

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

Compararea numerelor mari

Acest lucru este, de asemenea, important. Vă veți aminti că folosim metoda equals() pentru a compara obiectele în Java. Implementarea este fie furnizată de limbajul în sine (pentru clasele standard Java) fie suprascrisă de programator. Dar în cazul obiectelor BigDecimal , utilizarea metodei equals() pentru comparații nu este recomandată. Acest lucru se datorează faptului că metoda BigDecimal.equals() returnează adevărat numai dacă cele 2 numere au aceeași valoare și scară: Să comparăm comportamentul metodei equals() pentru clasele Double și 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));

   }
}
Ieșire din consolă:
true
false
După cum puteți vedea, pentru BigDecimal , numerele 1,5 și 1,50 s-au dovedit a fi inegale! Acest lucru a fost tocmai din cauza specificului implementării metodei equals() în clasa BigDecimal . Pentru o comparație mai precisă a două obiecte BigDecimal , este mai bine să utilizați metoda 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));

   }
}
Ieșire din consolă:
0
Metoda compareTo() a returnat 0, ceea ce înseamnă că 1,5 și 1,50 sunt egale. Și acesta este rezultatul la care ne așteptam! :) Asta se încheie lecția noastră de astăzi. Acum este timpul să ne întoarcem la sarcini! :)
Comentarii
  • Popular
  • Nou
  • Vechi
Trebuie să fii conectat pentru a lăsa un comentariu
Această pagină nu are încă niciun comentariu