BigDecimal i BigInteger u Javi

1. Pregled

U ovom uputstvu ćemo pokazati BigDecimal i BigInteger razreda.

Opisat ćemo dvije vrste podataka, njihove karakteristike i scenarije korištenja. Također ćemo ukratko obraditi razne operacije pomoću dvije klase.

2. BigDecimal

BigDecimal predstavlja nepromjenjiv decimalni broj s potpisom proizvoljne preciznosti. Sastoji se iz dva dijela:

  • Nerazmjerena vrijednost - proizvoljan cijeli broj preciznosti
  • Ljestvica - 32-bitni cijeli broj koji predstavlja broj znamenki desno od decimalne točke

Na primjer, BigDecimal 3.14 ima neomjerenu vrijednost 314 i ljestvicu 2.

Koristimo BigDecimal za aritmetiku visoke preciznosti. Također ga koristimo za izračune koji zahtijevaju kontrolu nad razmjerom i ponašanje zaokruživanja. Jedan od takvih primjera su izračuni koji uključuju financijske transakcije.

Možemo stvoriti BigDecimal objekt od Niz, niz znakova, int, dugo, i BigInteger:

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

Možemo i stvarati BigDecimal iz dvostruko:

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

Međutim, rezultat se u ovom slučaju razlikuje od očekivanog (to je 0,1). Ovo je zbog:

  • the dvostruko konstruktor vrši točan prijevod
  • 0.1 nema točan prikaz u dvostruko

Stoga, trebali bismo koristiti String konstruktor umjesto dvostruko konstruktor.

Osim toga, možemo pretvoriti dvostruko i dugo do BigInteger koristiti vrijednost statička metoda:

@Test public void 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 ()); }

Ova metoda pretvara dvostruko na svoje Niz predstavljanje prije pretvorbe u BigDecimal. Osim toga, može ponovno upotrijebiti instance objekta.

Stoga, trebali bismo koristiti vrijednost metoda u prednost konstruktorima.

3. Operacije na BigDecimal

Baš kao i druga Broj satovi (Cijeli broj, Dugo, Dvostruko itd.), BigDecimal pruža operacije za računske i usporedbene operacije. Također pruža operacije za manipulaciju razmjerom, zaokruživanje i pretvorbu formata.

Ne preopterećuje aritmetičke (+, -, /, *) ili logičke (>. <Itd) operatore. Umjesto toga koristimo odgovarajuće metode - dodati, oduzeti, pomnožiti, podijeliti i usporediTo.

BigDecimal ima metode za izdvajanje različitih atributa, kao što su preciznost, skala i znak:

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

Uspoređujemo vrijednost dva BigDecimala pomoću usporediTo metoda:

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

Ova metoda zanemaruje ljestvicu tijekom usporedbe.

S druge strane, the jednako metoda razmatra dvije BigDecimal predmeti kao jednaki samo ako su jednaki po vrijednosti i mjerilu. Tako, BigDecimals 1.0 i 1.00 nisu jednaki u usporedbi ovom metodom.

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

Aritmetičke operacije izvodimo pozivanjem odgovarajućih metoda:

@Test public void whenPerformingArithmetic_thenExpectedResult () {BigDecimal bd1 = new BigDecimal ("4.0"); BigDecimal bd2 = novi BigDecimal ("2.0"); VelikiDecimalni zbroj = bd1.add (bd2); BigDecimalna razlika = bd1.subtract (bd2); BigDecimalni količnik = bd1.divide (bd2); VelikiDecimalni proizvod = bd1.multiply (bd2); assertTrue (sum.compareTo (novi BigDecimal ("6.0")) == 0); assertTrue (razlika.compareTo (novi BigDecimal ("2.0")) == 0); assertTrue (quotient.compareTo (novi BigDecimal ("2.0")) == 0); assertTrue (product.compareTo (novi BigDecimal ("8.0")) == 0); }

Od BigDecimal je nepromjenjiv, ove operacije ne mijenjaju postojeće objekte. Dapače, vraćaju nove predmete.

4. Zaokruživanje i BigDecimal

Zaokruživanjem broja zamjenjujemo ga drugim koji ima kraći, jednostavniji i značajniji prikaz. Na primjer, zaokružimo 24,784917 USD na 24,78 USD jer nemamo djeliće centi.

Način preciznosti i zaokruživanja koji se koristi razlikuje se ovisno o izračunu. Na primjer, američke porezne prijave navode da se zaokružuju na cijele dolarske iznose pomoću POLUVREME.

Postoje dvije klase koje kontroliraju ponašanje zaokruživanja - Način zaokruživanja i MathContext.

The enum RoundingMode pruža osam načina zaokruživanja:

  • PLAFON - zaokružuje prema pozitivnoj beskonačnosti
  • KAT - zaokružuje prema negativnoj beskonačnosti
  • GORE - zaokružuje od nule
  • DOLJE - zaokružuje prema nuli
  • POLUVREME - zaokružuje prema "najbližem susjedu", osim ako su oba susjeda jednako udaljena, u tom se slučaju zaokružuje
  • POLU DOLJE - zaokružuje prema "najbližem susjedu", osim ako su oba susjeda jednako udaljena, u tom slučaju zaokružuje prema dolje
  • POL_EVEN - zaokružuje prema "najbližem susjedu", osim ako su oba susjeda jednako udaljena, u tom slučaju zaokružuje prema parnom susjedu
  • POTREBNO - nije potrebno zaokruživanje i ArithmeticException baca se ako nije moguć točan rezultat

POL_EVEN način zaokruživanja minimalizira pristranost zbog operacija zaokruživanja. Često se koristi. Također je poznat kao bankarsko zaokruživanje.

MathContext obuhvaća i preciznost i način zaokruživanja. Postoji nekoliko unaprijed definiranih MathContexts:

  • DECIMALNO32 - Preciznost od 7 znamenki i način zaokruživanja POLA_EVEN
  • DECIMALNI64 - Preciznost od 16 znamenki i način zaokruživanja POLA_EVEN
  • DECIMALNI128 - preciznost od 34 znamenke i način zaokruživanja POLA_EVEN
  • NEOGRANIČEN - neograničena aritmetika preciznosti

Pomoću ove klase možemo zaokružiti a BigDecimal broj pomoću određene preciznosti i ponašanja zaokruživanja:

@Test public void whenRoundingDecimal_thenExpectedResult () {BigDecimal bd = novi BigDecimal ("2.5"); // Zaokruživanje na 1 znamenku pomoću HALF_EVEN BigDecimal rounded = bd .round (novi MathContext (1, RoundingMode.HALF_EVEN)); assertEquals ("2", rounded.toString ()); }

Sada, ispitajmo koncept zaokruživanja pomoću uzorka izračuna.

Napišimo metodu za izračunavanje ukupnog iznosa koji treba platiti za predmet s obzirom na količinu i jediničnu cijenu. Primijenimo i diskontnu stopu i stopu poreza na promet. Konačni rezultat zaokružujemo u centi pomoću setScale metoda:

javni statički BigDecimal izračunajTotalAmount (BigDecimal količina, BigDecimal unitPrice, BigDecimal discountRate, BigDecimal taxRate) {BigDecimal iznos = količina.multiply (unitPrice); BigDecimalni popust = iznos.množiti (discountRate); BigDecimal discountAmount = iznos.subtract (popust); BigDecimal porez = discountAmount.multiply (taxRate); BigDecimal total = discountAmount.add (porez); // zaokruživanje na 2 decimale pomoću HALF_EVEN BigDecimal roundedTotal = total.setScale (2, RoundingMode.HALF_EVEN); povratak roundedTotal; }

Napišimo sada jedinstveni test za ovu metodu:

@Test javna praznina givenPurchaseTxn_whenCalculatingTotalAmount_thenExpectedResult () {BigDecimal količina = nova BigDecimal ("4.5"); BigDecimal unitPrice = novi BigDecimal ("2.69"); BigDecimal discountRate = novi BigDecimal ("0,10"); BigDecimal taxRate = novi BigDecimal ("0,0725"); BigDecimal amountToBePaid = BigDecimalDemo .calculateTotalAmount (količina, unitPrice, discountRate, taxRate); assertEquals ("11,68", iznosToBePaid.toString ()); }

5. BigInteger

BigInteger predstavlja nepromjenjive cijele brojeve proizvoljne preciznosti. Sličan je primitivnim vrstama cijelih brojeva, ali dopušta proizvoljne velike vrijednosti.

Koristi se kada su uključeni cijeli brojevi veći od ograničenja od dugo tip. Na primjer, faktor od 50 je 30414093201713378043612608166064768844377641568960512000000000000. Ova je vrijednost prevelika za int ili long tip podataka za obradu. Može se pohraniti samo u BigInteger varijabilna.

Široko se koristi u sigurnosnim i kriptografskim aplikacijama.

Možemo stvarati BigInteger od bajt niz ili Niz:

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

U Dodatku, možemo pretvoriti a dugo do BigInteger koristeći statičku metodu vrijednost:

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

6. Operacije na BigInteger

Slično int i dugo, BigInteger provodi sve aritmetičke i logičke operacije. Ali, to ne preopterećuje operatere.

Također implementira odgovarajuće metode iz Matematika razred: trbušnjaci, min, maks, prah, signum.

Usporedimo vrijednost dva BigIntegersa pomoću usporediTo metoda:

@Test javna praznina givenBigIntegers_whentCompared_thenExpectedResult () {BigInteger i = novi BigInteger ("123456789012345678901234567890"); BigInteger j = novi BigInteger ("123456789012345678901234567891"); BigInteger k = novi BigInteger ("123456789012345678901234567892"); assertTrue (i.compareTo (i) == 0); assertTrue (j.compareTo (i)> 0); assertTrue (j.compareTo (k) <0); }

Aritmetičke operacije izvodimo pozivanjem odgovarajućih metoda:

@Test javna praznina givenBigIntegers_whenPerformingArithmetic_thenExpectedResult () {BigInteger i = novi BigInteger ("4"); BigInteger j = novi BigInteger ("2"); Zbroj velikog broja = i.add (j); BigInteger razlika = i.subtract (j); BigInteger količnik = i.divide (j); BigInteger proizvod = i.multiply (j); assertEquals (novi BigInteger ("6"), zbroj); assertEquals (novi BigInteger ("2"), razlika); assertEquals (novi BigInteger ("2"), količnik); assertEquals (novi BigInteger ("8"), proizvod); }

Kao BigInteger je nepromjenjiv, ove operacije ne mijenjaju postojeće objekte. Za razliku od int i dugo, ove se operacije ne prelijevaju.

BigInteger ima bit operacije slične int i dugo. Ali, moramo koristiti metode umjesto operatora:

@Test javna praznina givenBigIntegers_whenPerformingBitOperations_thenExpectedResult () {BigInteger i = novi BigInteger ("17"); BigInteger j = novi BigInteger ("7"); BigInteger i = i.and (j); BigInteger ili = i.or (j); BigInteger nije = j.not (); BigInteger xor = i.xor (j); BigInteger andNot = i.andNot (j); BigInteger shiftLeft = i.shiftLeft (1); BigInteger shiftRight = i.shiftRight (1); assertEquals (novi BigInteger ("1") i); assertEquals (novi BigInteger ("23") ili); assertEquals (novi BigInteger ("- 8"), nije); assertEquals (novi BigInteger ("22"), xor); assertEquals (novi BigInteger ("16"), andNot); assertEquals (novi BigInteger ("34"), shiftLeft); assertEquals (novi BigInteger ("8"), shiftRight); }

Ima dodatne metode manipulacije bitovima:

@Test javna praznina givenBigIntegers_whenPerformingBitManipulations_thenExpectedResult () {BigInteger i = novi 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 (novi BigInteger ("5114"), setBit12); assertEquals (novi BigInteger ("1019"), flipBit0); assertEquals (novi BigInteger ("1010"), clearBit3); }

BigInteger pruža metode za GCD računanje i modularnu aritmetiku:

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

Također ima metode povezane s osnovnom generacijom i ispitivanjem primarnosti:

@Test javna praznina givenBigIntegers_whenPrimeOperations_thenExpectedResult () {BigInteger i = BigInteger.probablePrime (100, novo slučajno ()); boolean isProbablePrime = i.isProbablePrime (1000); assertEquals (true, isProbablePrime); }

7. Zaključak

U ovom smo brzom vodiču istražili nastavu BigDecimal i BigInteger. Korisni su za napredna numerička izračunavanja gdje primitivni cijeli tipovi nisu dovoljni.

Kao i obično, puni izvorni kod možete pronaći na GitHubu.