BigDecimal en BigInteger in Java

1. Overzicht

In deze tutorial zullen we demonstreren BigDecimal en de BigInteger klassen.

We beschrijven de twee gegevenstypen, hun kenmerken en hun gebruiksscenario's. We zullen ook kort ingaan op de verschillende bewerkingen met behulp van de twee klassen.

2. BigDecimal

BigDecimal vertegenwoordigt een onveranderlijk decimaal getal met willekeurige precisie. Het bestaat uit twee delen:

  • Niet-geschaalde waarde - een geheel getal met willekeurige precisie
  • Schaal - een 32-bits geheel getal dat het aantal cijfers rechts van de komma vertegenwoordigt

Bijvoorbeeld de BigDecimal 3.14 heeft de ongeschaalde waarde van 314 en de schaal van 2.

We gebruiken BigDecimal voor hoge precisie rekenkunde. We gebruiken het ook voor berekeningen waarbij schaalbeheersing en afrondingsgedrag vereist zijn. Een voorbeeld hiervan zijn berekeningen met financiële transacties.

We kunnen een BigDecimal bezwaar tegen Draad, tekenreeks, int, lang, en BigInteger:

@Test public void whenBigDecimalCreated_thenValueMatches () {BigDecimal bdFromString = new BigDecimal ("0.1"); BigDecimal bdFromCharArray = new BigDecimal (new char [] {'3', '.', '1', '6', '1', '5'}); BigDecimal bdlFromInt = nieuwe BigDecimal (42); BigDecimal bdFromLong = nieuwe BigDecimal (123412345678901L); BigInteger bigInteger = BigInteger.probablePrime (100, nieuwe Random ()); BigDecimal bdFromBigInteger = nieuwe BigDecimal (bigInteger); assertEquals ("0.1", bdFromString.toString ()); assertEquals ("3.1615", bdFromCharArray.toString ()); assertEquals ("42", bdlFromInt.toString ()); assertEquals ("123412345678901", bdFromLong.toString ()); assertEquals (bigInteger.toString (), bdFromBigInteger.toString ()); }

We kunnen ook creëren BigDecimal van dubbele:

@Test openbare leegte whenBigDecimalCreatedFromDouble_thenValueMayNotMatch () {BigDecimal bdFromDouble = nieuwe BigDecimal (0.1d); assertNotEquals ("0.1", bdFromDouble.toString ()); }

Het resultaat is in dit geval echter anders dan verwacht (dat is 0,1). Dit is zo omdat:

  • de dubbele constructor doet een exacte vertaling
  • 0.1 heeft geen exacte weergave in dubbele

Daarom we zouden de S moeten gebruikentring constructor in plaats van de dubbele constructeur.

Bovendien kunnen we converteren dubbele en lang naar BigInteger de ... gebruiken waarde van statische methode:

@Test openbare leegte whenBigDecimalCreatedUsingValueOf_thenValueMatches () {BigDecimal bdFromLong1 = BigDecimal.valueOf (123412345678901L); BigDecimal bdFromLong2 = BigDecimal.valueOf (123412345678901L, 2); BigDecimal bdFromDouble = BigDecimal.valueOf (0.1d); assertEquals ("123412345678901", bdFromLong1.toString ()); assertEquals ("1234123456789.01", bdFromLong2.toString ()); assertEquals ("0.1", bdFromDouble.toString ()); }

Deze methode converteert dubbele naar zijn Draad vertegenwoordiging alvorens te converteren naar BigDecimal. Bovendien kan het objectexemplaren hergebruiken.

Vandaar, we zouden de waarde van methode in plaats van de constructeurs.

3. Bewerkingen aan BigDecimal

Net als de andere Aantal klassen (Geheel getal, Lang, Dubbele enz.), BigDecimal biedt bewerkingen voor rekenkundige bewerkingen en vergelijkingsbewerkingen. Het biedt ook bewerkingen voor schaalmanipulatie, afronding en formaatconversie.

Het belast de rekenkundige (+, -, /, *) of logische (>. <Etc) operatoren niet. In plaats daarvan gebruiken we de overeenkomstige methoden - toevoegen, aftrekken, vermenigvuldigen, verdelen en vergelijk met.

BigDecimal heeft methoden om verschillende attributen te extraheren, zoals precisie, schaal en teken:

@Test public void whenGettingAttributes_thenExpectedResult () {BigDecimal bd = new BigDecimal ("- 12345.6789"); assertEquals (9, bd.precision ()); assertEquals (4, bd.scale ()); assertEquals (-1, bd.signum ()); }

We vergelijken de waarde van twee BigDecimals met behulp van de vergelijk met methode:

@Test public void whenComparingBigDecimals_thenExpectedResult () {BigDecimal bd1 = new BigDecimal ("1.0"); BigDecimal bd2 = nieuwe BigDecimal ("1.00"); BigDecimal bd3 = nieuwe BigDecimal ("2.0"); assertTrue (bd1.compareTo (bd3) 0); assertTrue (bd1.compareTo (bd2) == 0); assertTrue (bd1.compareTo (bd3) = 0); assertTrue (bd1.compareTo (bd3)! = 0); }

Deze methode negeert de schaal tijdens het vergelijken.

Aan de andere kant, de is gelijk aan methode beschouwt twee BigDecimal objecten zijn alleen gelijk als ze gelijk zijn in waarde en schaal. Dus, BigDecimals 1,0 en 1,00 zijn niet gelijk bij vergelijking met deze methode.

@Test public void whenEqualsCalled_thenSizeAndScaleMatched () {BigDecimal bd1 = new BigDecimal ("1.0"); BigDecimal bd2 = nieuwe BigDecimal ("1.00"); assertFalse (bd1.equals (bd2)); }

We voeren rekenkundige bewerkingen uit door de overeenkomstige methoden aan te roepen:

@Test public void whenPerformingArithmetic_thenExpectedResult () {BigDecimal bd1 = new BigDecimal ("4.0"); BigDecimal bd2 = nieuwe BigDecimal ("2.0"); BigDecimal som = bd1.add (bd2); BigDecimal verschil = bd1.subtract (bd2); BigDecimal-quotiënt = bd1.divide (bd2); BigDecimal product = bd1.multiply (bd2); assertTrue (sum.compareTo (new BigDecimal ("6.0")) == 0); assertTrue (differ.compareTo (new BigDecimal ("2.0")) == 0); assertTrue (quotient.compareTo (new BigDecimal ("2.0")) == 0); assertTrue (product.compareTo (new BigDecimal ("8.0")) == 0); }

Sinds BigDecimal onveranderlijk is, wijzigen deze bewerkingen de bestaande objecten niet. Ze geven eerder nieuwe objecten terug.

4. Afronding en BigDecimal

Door een getal af te ronden, vervangen we het door een ander met een kortere, eenvoudigere en meer betekenisvolle weergave. We ronden bijvoorbeeld $ 24,784917 af op $ 24,78 omdat we geen fractionele centen hebben.

De te gebruiken precisie en afrondingsmodus is afhankelijk van de berekening. In de Amerikaanse federale belastingaangiften wordt bijvoorbeeld aangegeven dat op hele dollarbedragen moet worden afgerond met HALF_UP.

Er zijn twee klassen die het afrondgedrag bepalen: Afrondingsmodus en MathContext.

De enum RoundingMode biedt acht afrondingsmodi:

  • PLAFOND - rondt af naar positieve oneindigheid
  • VERDIEPING - rondt af naar negatief oneindig
  • OMHOOG - rondt af van nul
  • OMLAAG - rondt af naar nul
  • HALF_UP - rondt af naar "naaste buur" tenzij beide buren op gelijke afstand staan, in welk geval naar boven afgerond
  • HALF_DOWN - rondt af op "naaste buur", tenzij beide buren op gelijke afstand staan, in welk geval naar beneden wordt afgerond
  • HALF_EVEN - rondt af naar de "naaste buur" tenzij beide buren op gelijke afstand staan, in welk geval rondt naar de even buur
  • ONNODIG - afronding is niet nodig en ArithmeticException wordt gegooid als er geen exact resultaat mogelijk is

HALF_EVEN afrondingsmodus minimaliseert de vertekening als gevolg van afrondingsbewerkingen. Het wordt veelvuldig gebruikt. Het is ook bekend als de afronding van de bankier.

MathContext omvat zowel precisie- als afrondingsmodus. Er zijn enkele voorgedefinieerde MathContexts:

  • DECIMAAL32 - 7 cijfers precisie en een afrondingsmodus van HALF_EVEN
  • DECIMAAL 64 - 16 cijfers precisie en een afrondingsmodus van HALF_EVEN
  • DECIMAAL 128 - 34 cijfers precisie en een afrondingsmodus van HALF_EVEN
  • ONBEPERKT - onbeperkte rekenkundige precisie

Met behulp van deze klasse kunnen we een afronden BigDecimal getal met gespecificeerde precisie en afrondingsgedrag:

@Test public void whenRoundingDecimal_thenExpectedResult () {BigDecimal bd = new BigDecimal ("2.5"); // Rond af op 1 cijfer met HALF_EVEN BigDecimal afgerond = bd .round (nieuwe MathContext (1, RoundingMode.HALF_EVEN)); assertEquals ("2", rounded.toString ()); }

Laten we nu het afrondingsconcept bekijken met behulp van een rekenvoorbeeld.

Laten we een methode schrijven om het totale bedrag te berekenen dat voor een artikel moet worden betaald, gegeven een hoeveelheid en een eenheidsprijs. Laten we ook een kortingstarief en een btw-tarief toepassen. We ronden het eindresultaat af op centen met behulp van de setScale methode:

openbare statische BigDecimal berekenTotalAmount (BigDecimal hoeveelheid, BigDecimal unitPrice, BigDecimal discountRate, BigDecimal taxRate) {BigDecimal bedrag = hoeveelheid.multiply (unitPrice); BigDecimal korting = amount.multiply (discountRate); BigDecimal discountedAmount = amount.subtract (korting); BigDecimal tax = discountedAmount.multiply (taxRate); BigDecimal total = discountedAmount.add (belasting); // rond af op 2 decimalen met HALF_EVEN BigDecimal afgerondTotaal = total.setScale (2, RoundingMode.HALF_EVEN); return afgerondTotaal; }

Laten we nu een eenheidstest schrijven voor deze methode:

@Test openbare ongeldig gegevenPurchaseTxn_whenCalculatingTotalAmount_thenExpectedResult () {BigDecimal hoeveelheid = nieuwe BigDecimal ("4.5"); BigDecimal unitPrice = nieuwe BigDecimal ("2,69"); BigDecimal discountRate = nieuwe BigDecimal ("0.10"); BigDecimal taxRate = nieuwe BigDecimal ("0.0725"); BigDecimal amountToBePaid = BigDecimalDemo .calculateTotalAmount (hoeveelheid, unitPrice, discountRate, taxRate); assertEquals ("11.68", amountToBePaid.toString ()); }

5. BigInteger

BigInteger staat voor onveranderlijke gehele getallen met willekeurige precisie. Het is vergelijkbaar met de primitieve integer-typen, maar laat willekeurige grote waarden toe.

Het wordt gebruikt wanneer de betrokken gehele getallen groter zijn dan de limiet van lang type. De faculteit van 50 is bijvoorbeeld 30414093201713378043612608166064768844377641568960512000000000000. Deze waarde is te groot voor een int of lang datatype dat moet worden afgehandeld. Het kan alleen worden opgeslagen in een BigInteger variabele.

Het wordt veel gebruikt in beveiligings- en cryptografietoepassingen.

We kunnen creëren BigInteger van een byte matrix of Draad:

@Test public void whenBigIntegerCreatedFromConstructor_thenExpectedResult () {BigInteger biFromString = new BigInteger ("1234567890987654321"); BigInteger biFromByteArray = nieuwe BigInteger (nieuwe byte [] {64, 64, 64, 64, 64, 64}); BigInteger biFromSignMagnitude = new BigInteger (-1, nieuwe byte [] {64, 64, 64, 64, 64, 64}); assertEquals ("1234567890987654321", biFromString.toString ()); assertEquals ("70644700037184", biFromByteArray.toString ()); assertEquals ("- 70644700037184", biFromSignMagnitude.toString ()); }

Daarnaast, we kunnen een lang naar BigInteger met behulp van de statische methode waarde van:

@Test openbare leegte whenLongConvertedToBigInteger_thenValueMatches () {BigInteger bi = BigInteger.valueOf (2305843009213693951L); assertEquals ("2305843009213693951", bi.toString ()); }

6. Bewerkingen aan BigInteger

Gelijkwaardig aan int en lang, BigInteger implementeert alle rekenkundige en logische bewerkingen. Maar het belast de operators niet.

Het implementeert ook de overeenkomstige methoden van Wiskunde klasse: buikspieren, min, max. hoogte, pow, signum.

We vergelijken de waarde van twee BigIntegers met behulp van de vergelijk met methode:

@Test openbare ongeldige gegevenBigIntegers_whentCompared_thenExpectedResult () {BigInteger i = new BigInteger ("123456789012345678901234567890"); BigInteger j = new BigInteger ("123456789012345678901234567891"); BigInteger k = new BigInteger ("123456789012345678901234567892"); assertTrue (i.compareTo (i) == 0); assertTrue (j.compareTo (i)> 0); assertTrue (j.compareTo (k) <0); }

We voeren rekenkundige bewerkingen uit door de overeenkomstige methoden aan te roepen:

@Test openbare leegte gegevenBigIntegers_whenPerformingArithmetic_thenExpectedResult () {BigInteger i = nieuwe BigInteger ("4"); BigInteger j = nieuwe BigInteger ("2"); BigInteger sum = i.add (j); BigInteger-verschil = i. Aftrekken (j); BigInteger-quotiënt = i.divide (j); BigInteger product = i.multiply (j); assertEquals (new BigInteger ("6"), som); assertEquals (new BigInteger ("2"), verschil); assertEquals (new BigInteger ("2"), quotiënt); assertEquals (new BigInteger ("8"), product); }

Net zo BigInteger is onveranderlijk, deze bewerkingen wijzigen de bestaande objecten niet. In tegenstelling tot, int en lang, deze operaties lopen niet over.

BigInteger heeft de bit-bewerkingen vergelijkbaar met int en lang. Maar we moeten de methoden gebruiken in plaats van operators:

@Test openbare leegte gegevenBigIntegers_whenPerformingBitOperations_thenExpectedResult () {BigInteger i = nieuwe BigInteger ("17"); BigInteger j = new BigInteger ("7"); BigInteger en = i. En (j); BigInteger of = i. Of (j); BigInteger niet = j.not (); BigInteger xor = i.xor (j); BigInteger andNot = i.andNot (j); BigInteger shiftLeft = i.shiftLeft (1); BigInteger shiftRight = i.shiftRight (1); assertEquals (new BigInteger ("1"), en); assertEquals (new BigInteger ("23"), of); assertEquals (new BigInteger ("- 8"), niet); assertEquals (new BigInteger ("22"), xor); assertEquals (new BigInteger ("16"), andNot); assertEquals (new BigInteger ("34"), shiftLeft); assertEquals (new BigInteger ("8"), shiftRight); }

Het heeft extra bitmanipulatiemethoden:

@Test openbare leegte gegevenBigIntegers_whenPerformingBitManipulations_thenExpectedResult () {BigInteger i = nieuwe BigInteger ("1018"); int bitCount = i.bitCount (); int bitLength = i.bitLength (); int getLowestSetBit = i.getLowestSetBit (); boolean testBit3 = i.testBit (3); BigInteger setBit12 = i.setBit (12); BigInteger flipBit0 = i.flipBit (0); BigInteger clearBit3 = i.clearBit (3); assertEquals (8, bitCount); assertEquals (10, bitLength); assertEquals (1, getLowestSetBit); assertEquals (true, testBit3); assertEquals (new BigInteger ("5114"), setBit12); assertEquals (new BigInteger ("1019"), flipBit0); assertEquals (new BigInteger ("1010"), clearBit3); }

BigInteger biedt methoden voor GCD-berekening en modulaire rekenkunde:

@Test openbare leegte gegevenBigIntegers_whenModularCalculation_thenExpectedResult () {BigInteger i = nieuwe BigInteger ("31"); BigInteger j = new BigInteger ("24"); BigInteger k = new BigInteger ("16"); BigInteger gcd = j.gcd (k); BigInteger multiplyAndmod = j.multiply (k) .mod (i); BigInteger modInverse = j.modInverse (i); BigInteger modPow = j.modPow (k, i); assertEquals (new BigInteger ("8"), gcd); assertEquals (new BigInteger ("12"), multiplyAndmod); assertEquals (new BigInteger ("22"), modInverse); assertEquals (new BigInteger ("7"), modPow); }

Het heeft ook methoden die verband houden met primaire generatie en primaliteitstesten:

@Test openbare ongeldige gegevenBigIntegers_whenPrimeOperations_thenExpectedResult () {BigInteger i = BigInteger.probablePrime (100, nieuwe Random ()); boolean isProbablePrime = i.isProbablePrime (1000); assertEquals (true, isProbablePrime); }

7. Conclusie

In deze korte tutorial hebben we de lessen verkend BigDecimal en BigInteger. Ze zijn handig voor geavanceerde numerieke berekeningen waarbij de primitieve integer-typen niet voldoen.

Zoals gewoonlijk is de volledige broncode te vinden op GitHub.