CodeGym /Java Blog /Willekeurig /BigDecimal in Java
John Squirrels
Niveau 41
San Francisco

BigDecimal in Java

Gepubliceerd in de groep Willekeurig
Hoi! In de les van vandaag gaan we het hebben over grote getallen. Nee, ik bedoel ECHT GROOT. We zijn eerder herhaaldelijk de tabel met waardebereiken voor primitieve gegevenstypen tegengekomen. Het ziet er zo uit:
Primitieve soort Grootte in het geheugen Waardebereik
byte 8 bit -128 tot 127
kort 16 bit -32768 tot 32767
char 16 bit 0 tot 65536
int 32 bits -2147483648 tot 2147483647
lang 64 bit -9223372036854775808 tot 9223372036854775807
vlot 32 bits (2 tot de macht van -149) tot ((2 tot de macht van -23) * 2 tot de macht van 127)
dubbele 64 bit (-2 tot de macht van 63) tot ((2 tot de macht van 63) - 1)
booleaans 8 (indien gebruikt in arrays), 32 (indien niet gebruikt in arrays) waar of niet waar
Het meest ruime gegevenstype met gehele getallen is het lange . Als het gaat om getallen met drijvende komma, is het de dubbele . Maar wat als het aantal dat we nodig hebben zo groot is dat het niet eens in een lange past ? Het gegevenstype Long heeft een vrij groot bereik van mogelijke waarden, maar is nog steeds beperkt tot 64 bits. Wat moeten we bedenken als ons Very Large Number 100 bits nodig heeft? Gelukkig hoeven we niets uit te vinden. Voor dergelijke gevallen heeft Java twee speciale klassen: BigInteger (voor gehele getallen) en BigDecimal(voor getallen met drijvende komma). Wat maakt ze speciaal? Allereerst hebben ze in theorie geen maximale grootte. We zeggen "in theorie", omdat er geen computers zijn met een oneindig geheugen. En als je programma een getal creëert dat groter is dan de hoeveelheid beschikbaar geheugen, dan zal het programma natuurlijk niet werken. Maar dergelijke gevallen zijn onwaarschijnlijk. Als gevolg hiervan kunnen we zeggen dat BigInteger en BigDecimal getallen van vrijwel onbeperkte grootte kunnen vertegenwoordigen. Waar worden deze lessen voor gebruikt? Allereerst voor berekeningen met extreem hoge nauwkeurigheidseisen. Het menselijk leven kan bijvoorbeeld afhangen van de nauwkeurigheid van berekeningen in sommige programma's (bijvoorbeeld software die vliegtuigen, raketten of medische apparatuur bestuurt). Dus als de 150e decimaal belangrijk is, dan BigDecimalis de beste keuze. Bovendien worden objecten van deze klasse vaak gebruikt in de financiële wereld, waar nauwkeurige berekening van zelfs de kleinste waarden ook uiterst belangrijk is. Hoe werk je met BigInteger- en BigDecimal- objecten en moet je hiervan op de hoogte zijn? Objecten van deze klassen worden als volgt gemaakt:

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);
   }
}
Een string doorgeven aan de constructor is slechts één mogelijke optie. Hier gebruiken we strings, omdat onze nummers de maximale waarden voor long en double overschrijden, en we hebben een manier nodig om aan de compiler uit te leggen welk nummer we willen maken :) Gewoon het nummer doorgeven 11111111111111111111111111111111111111111111111111111111111111111111 naar de constructor werkt niet: Java zal proberen het doorgegeven getal in een van de primitieve gegevenstypen te proppen, maar het past in geen van hen. Daarom is het een goede optie om een ​​string te gebruiken om het gewenste nummer door te geven. Beide klassen kunnen automatisch numerieke waarden extraheren uit de doorgegeven tekenreeksen. Een ander belangrijk punt om te onthouden bij het werken met klassen met een groot aantal is dat hun objecten onveranderlijk zijn ( Immutable ). U bent al bekend met onveranderlijkheid dankzij uw ervaring met de String- klasse en de wrapper-klassen voor primitieve typen (Integer, Long, enz.).

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

   }
}
Console-uitvoer:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
Zoals je zou verwachten, is ons nummer niet veranderd. Om de optelbewerking uit te voeren, moet u een nieuw object maken om het resultaat van de bewerking te ontvangen.

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

   }
}
Console-uitvoer:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Kijk, nu werkt alles zoals het hoort :) Is het je trouwens opgevallen hoe ongewoon de optelbewerking eruit ziet?

BigInteger result = integer.add(BigInteger.valueOf(33333333));
Dit is een ander belangrijk punt. Klassen met een groot aantal gebruiken de operatoren + - * / niet. In plaats daarvan bieden ze een reeks methoden. Laten we kennis maken met de belangrijkste (zoals altijd vindt u een volledige lijst met methoden in de Oracle-documentatie: hier en hier ).
  1. methoden voor rekenkundige bewerkingen: optellen() , aftrekken() , vermenigvuldigen() , delen() . Deze methoden worden gebruikt om respectievelijk optellen, aftrekken, vermenigvuldigen en delen uit te voeren.

  2. doubleValue() , intValue() , floatValue() , longValue() , enz. worden gebruikt om een ​​groot getal om te zetten in een van Java's primitieve typen. Wees voorzichtig bij het gebruik van deze methoden. Vergeet de verschillen in bitmaat niet!

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

    Console-uitvoer:

    
    8198552921648689607
    
  3. min() en max() laten je de minimum- en maximumwaarde van twee grote getallen vinden.
    Merk op dat deze methoden niet statisch zijn!

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

    Console-uitvoer:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
    

BigDecimal afrondingsgedrag

Dit onderwerp heeft zijn eigen aparte sectie, aangezien het afronden van grote getallen en het configureren van afrondingsgedrag niet zo eenvoudig is. U kunt de methode setScale() gebruiken om het aantal decimalen voor een BigDecimal in te stellen . Stel dat we willen dat het getal 111.5555555555 drie cijfers achter de komma heeft. We kunnen echter niet bereiken wat we willen door het getal 3 als argument door te geven aan de methode setScale() . Zoals hierboven vermeld, BigDecimalis voor het weergeven van getallen met strikte eisen aan computationele precisie. In zijn huidige vorm heeft ons nummer 10 cijfers achter de komma. We willen er 7 laten vallen en er slechts 3 behouden. Daarom moeten we naast het cijfer 3 de afrondingsmodus passeren. BigDecimal heeft in totaal 8 afrondingsmodi. Dat is een hoop! Maar als u de precisie van uw berekeningen echt moet verfijnen, heeft u alles wat u nodig hebt. Dus, hier zijn de 8 afrondingsmodi aangeboden door BigDecimal :
  1. ROUND_CEILING — wordt naar boven afgerond

    
    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
    
  2. ROUND_DOWN — rondt af naar nul

    
    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
    
  3. ROUND_FLOOR — wordt naar beneden afgerond

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

  4. ROUND_HALF_UP — rondt naar boven af ​​als het getal achter de komma >= 0,5

    
    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
    
  5. ROUND_HALF_DOWN — rondt naar boven af ​​als het getal achter de komma > 0,5 is

    
    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
    
  6. ROUND_HALF_EVEN — afronding is afhankelijk van het getal links van de komma. Als het getal aan de linkerkant even is, wordt er naar beneden afgerond. Als het getal links van de komma oneven is, wordt naar boven afgerond.

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

    Het getal links van de komma is 2 (even). Het aantal wordt naar beneden afgerond. We willen 0 decimalen, dus het resultaat is 2.

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

    Het getal links van de komma is 3 (oneven). Het aantal wordt naar boven afgerond. We willen 0 decimalen, dus het resultaat is 4.

  7. ROUND_UNNECCESSARY — Deze modus wordt gebruikt wanneer u een afrondingsmodus moet doorgeven aan een methode, maar het getal hoeft niet te worden afgerond. Als u een getal probeert af te ronden terwijl de modus ROUND_UNNECCESSARY is ingesteld, wordt er een ArithmeticException gegenereerd.

    
    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
    
  8. ROUND_UP — rondt af van nul.

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

Grote getallen vergelijken

Dit is ook belangrijk. U zult zich herinneren dat we de methode equals() gebruiken om objecten in Java te vergelijken. De implementatie wordt geleverd door de taal zelf (voor standaard Java-klassen) of overschreven door de programmeur. Maar in het geval van BigDecimal- objecten wordt het gebruik van de methode equals() voor vergelijkingen niet aanbevolen. De reden hiervoor is dat de methode BigDecimal.equals() alleen true retourneert als de 2 getallen dezelfde waarde en schaal hebben: Laten we het gedrag van de methode equals() vergelijken voor de klassen Double en 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));
      
   }
}
Console-uitvoer:

true 
false
Zoals je kunt zien, bleken voor BigDecimal de getallen 1.5 en 1.50 ongelijk te zijn! Dit was precies vanwege de specifieke kenmerken van de implementatie van de methode equals() in de BigDecimal- klasse. Voor een nauwkeurigere vergelijking van twee BigDecimal- objecten is het beter om de methode CompareTo() te gebruiken:

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

   }
}
Console-uitvoer:

0
De methode CompareTo() retourneerde 0, wat betekent dat 1,5 en 1,50 gelijk zijn. En dit is het resultaat dat we verwacht hadden! :) Dat besluit onze les vandaag. Nu is het tijd om terug te gaan naar de taken! :)
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION