BigDecimal a BigInteger v Jave

1. Prehľad

V tomto návode si ukážeme BigDecimal a BigInteger triedy.

Popíšeme si dva dátové typy, ich charakteristiky a scenáre ich použitia. V krátkosti sa tiež venujeme rozličným operáciám pomocou týchto dvoch tried.

2. BigDecimal

BigDecimal predstavuje nezmeniteľné desatinné číslo so znamienkom ľubovoľnej presnosti. Skladá sa z dvoch častí:

  • Hodnota bez škály - celé číslo s ľubovoľnou presnosťou
  • Stupnica - 32-bitové celé číslo predstavujúce počet číslic napravo od desatinnej čiarky

Napríklad BigDecimal 3.14 má hodnotu bez škály 314 a stupnicu 2.

Používame BigDecimal pre vysoko presnú aritmetiku. Používame ho tiež na výpočty vyžadujúce kontrolu nad mierkou a zaokrúhľovaním správania. Jedným z takýchto príkladov sú výpočty týkajúce sa finančných transakcií.

Môžeme vytvoriť BigDecimal objekt z String, pole znakov, int, dlhoa BigInteger:

@Test public void whenBigDecimalCreated_thenValueMatches () {BigDecimal bdFromString = nový BigDecimal ("0,1"); BigDecimal bdFromCharArray = nový BigDecimal (nový znak [] {'3', '.', '1', '6', '1', '5'}); BigDecimal bdlFromInt = nový BigDecimal (42); BigDecimal bdFromLong = nový BigDecimal (123412345678901L); BigInteger bigInteger = BigInteger.probablePrime (100, new Random ()); BigDecimal bdFromBigInteger = nový 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 ()); }

Môžeme aj tvoriť BigDecimal od dvojitý:

@Test public void whenBigDecimalCreatedFromDouble_thenValueMayNotMatch () {BigDecimal bdFromDouble = nový BigDecimal (0,1 d); assertNotEquals ("0,1", bdFromDouble.toString ()); }

Výsledok sa však v tomto prípade líši od očakávaného (to je 0,1). To je preto, že:

  • the dvojitý konštruktor robí presný preklad
  • 0.1 nemá presné zastúpenie v dvojitý

Preto mali by sme použiť String konštruktor namiesto dvojitý konštruktér.

Okrem toho môžeme prevádzať dvojitý a dlho do BigInteger pomocou hodnota statická metóda:

@Test public void whenBigDecimalCreatedUsingValueOf_thenValueMatches () {BigDecimal bdFromLong1 = BigDecimal.valueOf (123412345678901L); BigDecimal bdFromLong2 = BigDecimal.valueOf (123412345678901L, 2); BigDecimal bdFromDouble = BigDecimal.valueOf (0,1 d); assertEquals ("123412345678901", bdFromLong1.toString ()); assertEquals ("1234123456789.01", bdFromLong2.toString ()); assertEquals ("0,1", bdFromDouble.toString ()); }

Táto metóda sa prevádza dvojitý k jeho String zastúpenie pred konverziou na BigDecimal. Okrem toho môže znova použiť inštancie objektov.

Teda mali by sme použiť hodnota prednostne pred konštruktérmi.

3. Operácie zapnuté BigDecimal

Rovnako ako ten druhý Číslo triedy (Celé číslo, Dlhé, Dvojitý atď.), BigDecimal poskytuje operácie pre aritmetické a porovnávacie operácie. Poskytuje tiež operácie na manipuláciu s mierkou, zaokrúhľovanie a prevod formátu.

Nepreťažuje aritmetické (+, -, /, *) alebo logické (>. <Atď.) Operátory. Namiesto toho používame zodpovedajúce metódy - pridať, odčítať, znásobiť, rozdeliť a porovnať s.

BigDecimal má metódy na extrahovanie rôznych atribútov, napríklad presnosti, mierky a znamienka:

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

Hodnotu dvoch BigDecimals porovnávame pomocou znaku porovnať s metóda:

@Test public void whenComparingBigDecimals_thenExpectedResult () {BigDecimal bd1 = nový BigDecimal ("1.0"); BigDecimal bd2 = nový BigDecimal ("1,00"); BigDecimal bd3 = nový BigDecimal ("2.0"); assertTrue (bd1.compareTo (bd3) 0); assertTrue (bd1.compareTo (bd2) == 0); assertTrue (bd1.compareTo (bd3) = 0); assertTrue (bd1.compareTo (bd3)! = 0); }

Táto metóda pri porovnávaní ignoruje mierku.

Na druhej strane, the rovná sa metóda považuje za dve BigDecimal objekty sú rovnaké iba vtedy, ak sú si rovné v hodnote a mierke. Teda BigDecimals 1,0 a 1,00 nie sú rovnaké, ak sa porovnajú touto metódou.

@Test public void whenEqualsCalled_thenSizeAndScaleMatched () {BigDecimal bd1 = nový BigDecimal ("1.0"); BigDecimal bd2 = nový BigDecimal ("1,00"); assertFalse (bd1.equals (bd2)); }

Aritmetické operácie vykonávame volaním zodpovedajúcich metód:

@Test public void whenPerformingArithmetic_thenExpectedResult () {BigDecimal bd1 = nový BigDecimal ("4.0"); BigDecimal bd2 = nový BigDecimal ("2.0"); BigDecimal sum = bd1.add (bd2); BigDecimal difference = bd1.subtract (bd2); BigDecimal kvocient = bd1.divide (bd2); BigDecimal product = bd1.multiply (bd2); assertTrue (sum.compareTo (nový BigDecimal ("6.0")) == 0); assertTrue (difference.compareTo (nový BigDecimal ("2.0")) == 0); assertTrue (quotient.compareTo (nový BigDecimal ("2.0")) == 0); assertTrue (product.compareTo (nový BigDecimal ("8.0")) == 0); }

Odkedy BigDecimal je nemenná, tieto operácie nezmenia existujúce objekty. Namiesto toho vracajú nové objekty.

4. Zaokrúhlenie a BigDecimal

Zaokrúhlením čísla ho nahradíme iným, ktoré má kratšie, jednoduchšie a zmysluplnejšie zastúpenie. Napríklad zaokrúhľujeme 24,784917 na 24,78 dolárov, pretože nemáme zlomkové centy.

Použitý režim presnosti a zaokrúhľovania sa líši v závislosti od výpočtu. Napríklad americké federálne daňové priznania určujú zaokrúhlenie na celé doláre pomocou HALF_UP.

Existujú dve triedy, ktoré riadia správanie zaokrúhľovania - RoundingMode a MathContext.

The enum RoundingMode poskytuje osem režimov zaokrúhľovania:

  • STROP - zaokrúhľuje smerom k pozitívnemu nekonečnu
  • PODLAHA - zaokrúhľuje smerom k negatívnemu nekonečnu
  • HORE - zaokrúhľuje od nuly
  • NADOL - zaokrúhľuje na nulu
  • HALF_UP - zaokrúhli smerom k „najbližšiemu susedovi“, pokiaľ nie sú obaja susedia v rovnakej vzdialenosti. V takom prípade sa zaokrúhli nahor
  • HALF_DOWN - zaokrúhľuje na „najbližší sused“, pokiaľ nie sú obaja susedia v rovnakej vzdialenosti, v takom prípade sa zaokrúhli smerom nadol
  • HALF_EVEN - zaokrúhľuje na „najbližšieho suseda“, pokiaľ nie sú obaja susedia v rovnakej vzdialenosti, v takom prípade sa zaokrúhľuje na rovnomerného suseda
  • ZBYTOČNÉ - nie je potrebné žiadne zaokrúhľovanie a Aritmetická výnimka je vyhodený, ak nie je možný presný výsledok

HALF_EVEN režim zaokrúhľovania minimalizuje skreslenie spôsobené operáciami zaokrúhľovania. Často sa používa. Je tiež známy ako zaokrúhlenie bankára.

MathContext zapuzdruje režim presnosti aj zaokrúhľovania. Existuje niekoľko preddefinovaných MathContexts:

  • DECIMÁLNE32 - Presnosť 7 číslic a režim zaokrúhľovania na HALF_EVEN
  • DECIMAL64 - Presnosť 16 číslic a režim zaokrúhľovania na HALF_EVEN
  • DECIMÁLNE 128 - Presnosť 34 číslic a režim zaokrúhľovania na HALF_EVEN
  • NEOBMEDZENÉ - neobmedzená presnosť aritmetiky -

Pomocou tejto triedy môžeme zaokrúhliť a BigDecimal číslo pomocou zadanej presnosti a správania zaokrúhľovania:

@Test public void whenRoundingDecimal_thenExectedResult () {BigDecimal bd = new BigDecimal ("2.5"); // Zaokrúhlenie na 1 číslicu pomocou HALF_EVEN BigDecimal zaoblené = bd .okruh (nový MathContext (1, RoundingMode.HALF_EVEN)); assertEquals ("2", zaokrúhlené.toString ()); }

Teraz poďme preskúmať koncept zaokrúhľovania pomocou vzorového výpočtu.

Poďme napísať metódu na výpočet celkovej sumy, ktorá sa má zaplatiť za položku, vzhľadom na množstvo a jednotkovú cenu. Aplikujme tiež diskontnú sadzbu a sadzbu dane z obratu. Konečný výsledok zaokrúhľujeme na centy pomocou setScale metóda:

verejná statická BigDecimal countTotalAmount (BigDecimal množstvo, BigDecimal unitPrice, BigDecimal discountRate, BigDecimal taxRate) {BigDecimal suma = množstvo.multiply (unitPrice); BigDecimal zľava = čiastka.multiply (discountRate); BigDecimal discountedAmount = suma.subtract (zľava); BigDecimal tax = discountedAmount.multiply (taxRate); BigDecimal total = discountedAmount.add (daň); // zaokrúhlenie na 2 desatinné miesta pomocou HALF_EVEN BigDecimal roundedTotal = total.setScale (2, RoundingMode.HALF_EVEN); návrat RoundedTotal; }

Teraz napíšeme jednotkový test pre túto metódu:

@Test public void givenPurchaseTxn_whenCalculatingTotalAmount_thenExectedResult () {BigDecimal množstvo = nový BigDecimal ("4,5"); BigDecimal unitPrice = nový BigDecimal ("2,69"); BigDecimal discountRate = nový BigDecimal ("0,10"); BigDecimal taxRate = nový BigDecimal ("0,0725"); BigDecimal amountToBePaid = BigDecimalDemo .calculateTotalAmount (množstvo, jednotkaCena, zľavaRazba, sadzba dane); assertEquals ("11,68", amountToBePaid.toString ()); }

5. BigInteger

BigInteger predstavuje nemenné celé čísla s ľubovoľnou presnosťou. Je to podobné ako u primitívnych celočíselných typov, ale umožňuje ľubovoľné veľké hodnoty.

Používa sa, keď sú príslušné celé čísla väčšie ako limit dlho typu. Napríklad faktoriál 50 je 30414093201713378043612608166064768844377641568960512000000000000. Táto hodnota je príliš veľká pre int alebo long dátový typ, ktorý sa má spracovať. Môže byť uložený iba v a BigInteger premenná.

Je široko používaný v bezpečnostných a kryptografických aplikáciách.

Môžeme vytvárať BigInteger od a bajt pole alebo String:

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

Navyše, môžeme previesť a dlho do BigInteger pomocou statickej metódy hodnota:

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

6. Operácie zapnuté BigInteger

Podobný int a dlho, BigInteger implementuje všetky aritmetické a logické operácie. Nepreťažuje však obsluhu.

Implementuje tiež zodpovedajúce metódy z Matematika trieda: abs, min, max, pow, signum.

Porovnávame hodnotu dvoch BigIntegers pomocou porovnať s metóda:

@Test public void givenBigIntegers_whentCompared_thenExpectedResult () {BigInteger i = new BigInteger ("123456789012345678901234567890"); BigInteger j = nový BigInteger ("123456789012345678901234567891"); BigInteger k = nový BigInteger ("123456789012345678901234567892"); assertTrue (i.compareTo (i) == 0); assertTrue (j.compareTo (i)> 0); assertTrue (j.compareTo (k) <0); }

Aritmetické operácie vykonávame volaním zodpovedajúcich metód:

@Test public void givenBigIntegers_whenPerformingArithmetic_thenExpectedResult () {BigInteger i = nový BigInteger ("4"); BigInteger j = nový BigInteger ("2"); Suma BigInteger = i.add (j); Rozdiel BigInteger = i.subtract (j); Kvocient BigInteger = i.divide (j); BigInteger product = i.multiply (j); assertEquals (nový BigInteger ("6"), súčet); assertEquals (nový BigInteger ("2"), rozdiel); assertEquals (nový BigInteger ("2"), kvocient); assertEquals (nový produkt BigInteger ("8"), produkt); }

Ako BigInteger je nemenný, tieto operácie nemenia existujúce objekty. Na rozdiel od int a dlho, tieto operácie nepretekajú.

BigInteger má bitové operácie podobné int a dlho. Namiesto operátorov však musíme použiť metódy:

@Test public void givenBigIntegers_whenPerformingBitOperations_thenExectedResult () {BigInteger i = nový BigInteger ("17"); BigInteger j = nový BigInteger ("7"); BigInteger a = i.and (j); BigInteger alebo = i.or (j); BigInteger not = j.not (); BigInteger xor = i.xor (j); BigInteger andNot = i.andNot (j); BigInteger shiftLeft = i.shiftLeft (1); BigInteger shiftRight = i.shiftRight (1); assertEquals (nový BigInteger ("1") a); assertEquals (nový BigInteger („23“) alebo); assertEquals (nový BigInteger ("- 8"), nie); assertEquals (nový BigInteger ("22"), xor); assertEquals (nový BigInteger ("16") aNot); assertEquals (nový BigInteger ("34"), shiftLeft); assertEquals (nový BigInteger ("8"), shiftRight); }

Má ďalšie metódy manipulácie s bitmi:

@Test public void givenBigIntegers_whenPerformingBitManipulations_thenExectedResult () {BigInteger i = nový 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 (nový BigInteger ("5114"), setBit12); assertEquals (nový BigInteger ("1019"), flipBit0); assertEquals (nový BigInteger ("1010"), clearBit3); }

BigInteger poskytuje metódy na výpočet GCD a modulárnu aritmetiku:

@Test public void givenBigIntegers_whenModularCalculation_thenExpectedResult () {BigInteger i = nový BigInteger ("31"); BigInteger j = nový BigInteger ("24"); BigInteger k = nový 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 (nový BigInteger ("8"), gcd); assertEquals (nový BigInteger ("12"), multiplyAndmod); assertEquals (nový BigInteger ("22"), modInverse); assertEquals (nový BigInteger ("7"), modPow); }

Má tiež metódy súvisiace s generovaním prvočísel a testovaním primality:

@Test public void givenBigIntegers_whenPrimeOperations_thenExpectedResult () {BigInteger i = BigInteger.probablePrime (100, new Random ()); boolean isProbablePrime = i.isProbablePrime (1000); assertEquals (true, isProbablePrime); }

7. Záver

V tomto rýchlom výučbe sme preskúmali triedy BigDecimal a BigInteger. Sú užitočné pre pokročilé numerické výpočty, kde nestačia primitívne celočíselné typy.

Celý zdrojový kód nájdete ako obvykle na GitHub.