BigDecimal és BigInteger Java-ban
1. Áttekintés
Ebben az oktatóanyagban bemutatjuk BigDecimal és a BigInteger osztályok.
Leírjuk a két adattípust, azok jellemzőit és használati forgatókönyveit. Röviden kitérünk a két művelet különböző műveleteire is.
2. BigDecimal
BigDecimal megváltoztathatatlan tetszőleges pontosságú előjelű tizedes számot jelent. Két részből áll:
- Skálázatlan érték - tetszőleges pontosságú egész szám
- Méretarány - 32 bites egész szám, amely a tizedesvesszőtől jobbra lévő számjegyek számát jelenti
Például a BigDecimal A 3.14 skálázatlan értéke 314, skálája 2.
Használunk BigDecimal nagy pontosságú számtanra. Számításokhoz is használjuk, amelyek megkövetelik a skála ellenőrzését és a viselkedés lekerekítését. Ilyen például a pénzügyi tranzakciókat tartalmazó számítás.
Hozhatunk létre a BigDecimal objektum Húr, karaktertömb, int, hosszú, és 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 = new BigDecimal (42); BigDecimal bdFromLong = új BigDecimal (123412345678901L); BigInteger bigInteger = BigInteger.probablePrime (100, új Random ()); BigDecimal bdFromBigInteger = új 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 ()); }
Alkothatunk is BigDecimal tól től kettős:
@Test public void whenBigDecimalCreatedFromDouble_thenValueMayNotMatch () {BigDecimal bdFromDouble = new BigDecimal (0.1d); assertNotEquals ("0,1", bdFromDouble.toString ()); }
Az eredmény azonban ebben az esetben eltér a vártól (azaz 0,1). Ez azért van, mert:
- a kettős a konstruktor pontos fordítást végez
- A 0.1-nek nincs pontos reprezentációja kettős
Ebből kifolyólag, az S-t kell használnunktring kivitelező helyett kettős konstruktőr.
Ezen felül tudunk átalakítani kettős és hosszú nak nek BigInteger használni a értéke statikus módszer:
@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 ()); }
Ez a módszer konvertál kettős annak Húr reprezentáció a konvertálás előtt BigDecimal. Ezenkívül újból felhasználhatja az objektumpéldányokat.
Ennélfogva, használnunk kell a értéke módszer a kivitelezők helyett.
3. Műveletek BigDecimal
Akárcsak a másik Szám osztályok (Egész szám, Hosszú, Kettős stb.), BigDecimal műveleteket nyújt számtani és összehasonlítási műveletekhez. Ezenkívül műveleteket végez a skála manipulálásához, a kerekítéshez és a formátumkonvertáláshoz.
Nem terheli túl az aritmetikai (+, -, /, *) vagy a logikai (>. <Stb.) Operátorokat. Ehelyett a megfelelő módszereket alkalmazzuk - hozzá, kivonni, szaporodnak, feloszt és összehasonlítani.
BigDecimal rendelkezik módszerekkel a különféle attribútumok, például a pontosság, a méretarány és az előjelek kinyerésére:
@Test public void whenGettingAttributes_thenExpectedResult () {BigDecimal bd = new BigDecimal ("- 12345.6789"); assertEquals (9, bd.precision ()); assertEquals (4, skála skála ()); assertEquals (-1, bd.signum ()); }
Két BigDecimal értékét hasonlítjuk össze a összehasonlítani módszer:
@Test public void whenComparingBigDecimals_thenExpectedResult () {BigDecimal bd1 = new BigDecimal ("1.0"); BigDecimal bd2 = new BigDecimal ("1,00"); BigDecimal bd3 = új BigDecimal ("2.0"); assertTrue (bd1.compareTo (bd3) 0); assertTrue (bd1.compareTo (bd2) == 0); assertTrue (bd1.compareTo (bd3) = 0); assertTrue (bd1.compareTo (bd3)! = 0); }
Ez a módszer az összehasonlítás során figyelmen kívül hagyja a skálát.
Másrészről, a egyenlő módszer kettőt vesz figyelembe BigDecimal az objektumok csak akkor egyenlőek, ha értékükben és skálájukban egyenlőek. Így, BigDecimals Az 1.0 és az 1.00 nem egyenlő ezzel a módszerrel összehasonlítva.
@Test public void whenEqualsCalled_thenSizeAndScaleMatched () {BigDecimal bd1 = new BigDecimal ("1.0"); BigDecimal bd2 = new BigDecimal ("1,00"); assertFalse (bd1.egyenlő (bd2)); }
Számtani műveleteket hajtunk végre a megfelelő módszerek meghívásával:
@Test public void whenPerformingArithmetic_thenExpectedResult () {BigDecimal bd1 = new BigDecimal ("4.0"); BigDecimal bd2 = új BigDecimal ("2.0"); BigDecimal összeg = bd1.add (bd2); BigDecimal különbség = bd1.subtract (bd2); BigDecimal hányados = bd1.divide (bd2); BigDecimal szorzat = bd1.többszörözés (bd2); assertTrue (sum.compareTo (új BigDecimal ("6.0")) == 0); assertTrue (különbség.összehasonlítás (új BigDecimal ("2.0")) == 0); assertTrue (hányados.összehasonlításTo (új BigDecimal ("2.0")) == 0); assertTrue (product.compareTo (új BigDecimal ("8.0")) == 0); }
Mivel BigDecimal megváltoztathatatlan, ezek a műveletek nem módosítják a meglévő objektumokat. Inkább új tárgyakat adnak vissza.
4. Kerekítés és BigDecimal
Egy szám kerekítésével kicseréljük egy rövidebb, egyszerűbb és értelmesebb ábrázolású másikra. Például 24,784917 dollárt kerekítünk 24,78 dollárra, mivel nincsenek töredékes centjeink.
Az alkalmazott precíziós és kerekítési mód a számítástól függően változik. Például az Egyesült Államok szövetségi adóbevallásai megadják, hogy egész dollár összegekre kerekítsenek HALF_UP.
Két osztály szabályozza a kerekítési viselkedést - RoundingMode és MathContext.
A enum RoundingMode nyolc kerekítési módot kínál:
- Mennyezet - a pozitív végtelen felé fordul
- PADLÓ - negatív végtelen felé fordul
- FEL - kerekít a nullától
- LE - nulla felé fordul
- HALF_UP - a „legközelebbi szomszéd” felé fordul, kivéve, ha mindkét szomszéd egyenlő távolságra van, ebben az esetben felfelé kerekedik
- HALF_DOWN - a „legközelebbi szomszéd” felé fordul, kivéve, ha mindkét szomszéd egyenlő távolságra van, ebben az esetben lefelé fordul
- HALF_EVEN - a „legközelebbi szomszéd” felé fordul, hacsak mindkét szomszéd nem egyenlő távolságban van, ebben az esetben az egyenletes szomszéd felé fordul
- SZÜKSÉGES - nincs szükség kerekítésre és Számtani kivétel dobják, ha nem lehetséges pontos eredmény
HALF_EVEN a kerekítési mód minimalizálja a kerekítési műveletek miatti torzítást. Gyakran használják. Más néven bankár kerekítése.
MathContext mind a precíziós, mind a kerekítési módot magában foglalja. Kevés előre definiált MathContex van:
- DECIMAL32 - 7 számjegyű pontosság és HALF_EVEN kerekítési mód
- DECIMAL64 - 16 jegyű pontosság és HALF_EVEN kerekítési mód
- DECIMAL128 - 34 számjegyű pontosság és HALF_EVEN kerekítési mód
- KORLÁTLAN - korlátlan pontosságú számtan
Ennek az osztálynak a segítségével kerekíthetjük a BigDecimal szám a megadott pontossággal és kerekítési viselkedéssel:
@Test public void whenRoundingDecimal_thenExpectedResult () {BigDecimal bd = new BigDecimal ("2.5"); // 1 számjegyű kerekítés a HALF_EVEN segítségével BigDecimal kerekítve = bd .round (új MathContext (1, RoundingMode.HALF_EVEN)); assertEquals ("2", kerekítve.String ()); }
Most vizsgáljuk meg a kerekítési koncepciót egy minta számítás segítségével.
Írjunk egy módszert, amellyel kiszámíthatjuk a mennyiséget és egységárat megadó tételért fizetendő teljes összeget. Alkalmazzunk diszkontkamatot és forgalmi adókulcsot is. A végeredményt centekké kerekítjük a setScale módszer:
nyilvános statikus BigDecimal calcTotalAmount (BigDecimal mennyiség, BigDecimal unitPrice, BigDecimal discountRate, BigDecimal taxRate) {BigDecimal összeg = mennyiség.multiply (unitPrice); BigDecimal engedmény = összeg.többszörös (discountRate); BigDecimal discountedAmount = összeg.vonás (kedvezmény); BigDecimal adó = diszkontált összegMulttiply (taxRate); BigDecimal total = diszkontáltösszeg.add (adó); // kerekítés két tizedesjegyig a HALF_EVEN BigDecimal roundedTotal = total.setScale (2, RoundingMode.HALF_EVEN) használatával; return roundedTotal; }
Most írjunk egységtesztet ehhez a módszerhez:
@Test public void givenPurchaseTxn_whenCalculatingTotalAmount_thenExpectedResult () {BigDecimal quantum = new BigDecimal ("4.5"); BigDecimal unitPrice = új BigDecimal ("2,69"); BigDecimal discountRate = új BigDecimal ("0,10"); BigDecimal taxRate = új BigDecimal ("0,0725"); BigDecimal amountToBePaid = BigDecimalDemo .calculateTotalAmount (mennyiség, egységár, diszkontRáta, adókulcs); assertEquals ("11,68", összegToBePaid.toString ()); }
5. BigInteger
BigInteger változatlan tetszőleges pontosságú egész számokat jelöl. Hasonló a primitív egész típusúakhoz, de tetszőlegesen nagy értékeket tesz lehetővé.
Akkor használják, ha az érintett egész számok meghaladják a hosszú típus. Például az 50-es faktoriális az 30414093201713378043612608166064768844377641568960512000000000000. Ez az érték túl nagy egy int vagy hosszú kezelendő adattípus. Csak az a-ban tárolható BigInteger változó.
Széles körben használják biztonsági és kriptográfiai alkalmazásokban.
Alkothatunk BigInteger a-tól byte tömb vagy Húr:
@Test public void whenBigIntegerCreatedFromConstructor_thenExpectedResult () {BigInteger biFromString = new BigInteger ("1234567890987654321"); BigInteger biFromByteArray = new BigInteger (új bájt [] {64, 64, 64, 64, 64, 64}); BigInteger biFromSignMagnitude = new BigInteger (-1, új bájt [] {64, 64, 64, 64, 64, 64}); assertEquals ("1234567890987654321", biFromString.toString ()); assertEquals ("70644700037184", biFromByteArray.toString ()); assertEquals ("- 70644700037184", biFromSignMagnitude.toString ()); }
Továbbá, átalakíthatjuk a hosszú nak nek BigInteger statikus módszerrel értéke:
@Test public void whenLongConvertedToBigInteger_thenValueMatches () {BigInteger bi = BigInteger.valueOf (2305843009213693951L); assertEquals ("2305843009213693951", bi.toString ()); }
6. Műveletek BigInteger
Hasonló int és hosszú, BigInteger végrehajtja az összes számtani és logikai műveletet. De nem terheli túl az üzemeltetőket.
A megfelelő módszereket a Math osztály: abs, min, max, hadifogoly, signum.
Két BigInteger értékét hasonlítjuk össze a összehasonlítani módszer:
@Test public void givenBigIntegers_whentCompared_thenExpectedResult () {BigInteger i = new BigInteger ("123456789012345678901234567890"); BigInteger j = új BigInteger ("123456789012345678901234567891"); BigInteger k = new BigInteger ("123456789012345678901234567892"); assertTrue (i.compareTo (i) == 0); assertTrue (j.compareTo (i)> 0); assertTrue (j.compareTo (k) <0); }
Számtani műveleteket a megfelelő módszerek meghívásával hajtunk végre:
@Test public void givenBigIntegers_whenPerformingArithmetic_thenExpectedResult () {BigInteger i = new BigInteger ("4"); BigInteger j = új BigInteger ("2"); BigInteger összeg = i.add (j); BigInteger különbség = i.vonás (j); BigInteger hányados = i.divide (j); BigInteger szorzat = i. Sokszor (j); assertEquals (új BigInteger ("6"), összeg); assertEquals (új BigInteger ("2"), különbség); assertEquals (új BigInteger ("2"), hányados); assertEquals (új BigInteger ("8"), termék); }
Mint BigInteger megváltoztathatatlan, ezek a műveletek nem módosítják a meglévő objektumokat. Nem úgy mint, int és hosszú, ezek a műveletek nem túlcsordulnak.
BigInteger -hez hasonló bitműveletekkel rendelkezik int és hosszú. De az operátorok helyett a módszereket kell használnunk:
@Test public void givenBigIntegers_whenPerformingBitOperations_thenExpectedResult () {BigInteger i = new BigInteger ("17"); BigInteger j = új BigInteger ("7"); BigInteger és = i.és j); BigInteger vagy = i.vagy (j); BigInteger not = j.not (); BigInteger xor = i.xor (j); BigInteger ésNot = i.ésNot (j); BigInteger shiftLeft = i.shiftLeft (1); BigInteger shiftRight = i.shiftRight (1); assertEquals (új BigInteger ("1"), és); assertEquals (új BigInteger ("23") vagy); assertEquals (új BigInteger ("- 8"), nem); assertEquals (új BigInteger ("22"), xor); assertEquals (új BigInteger ("16"), ésNot); assertEquals (új BigInteger ("34"), shiftLeft); assertEquals (új BigInteger ("8"), shiftRight); }
További bitmanipulációs módszerekkel rendelkezik:
@Test public void givenBigIntegers_whenPerformingBitManipulations_thenExpectedResult () {BigInteger i = new BigInteger ("1018"); int bitCount = i.bitCount (); int bitLength = i.bitLength (); int getLowestSetBit = i.getLowestSetBit (); logikai tesztBit3 = 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 (új BigInteger ("5114"), setBit12); assertEquals (új BigInteger ("1019"), flipBit0); assertEquals (új BigInteger ("1010"), clearBit3); }
BigInteger módszereket nyújt a GCD számításához és a moduláris aritmetikához:
@Test public void givenBigIntegers_whenModularCalculation_thenExpectedResult () {BigInteger i = new BigInteger ("31"); BigInteger j = új BigInteger ("24"); BigInteger k = új BigInteger ("16"); BigInteger gcd = j.gcd (k); BigInteger multiplyAndmod = j.többszörözni (k) .mod (i); BigInteger modInverse = j.modInverse (i); BigInteger modPow = j.modPow (k, i); assertEquals (új BigInteger ("8"), gcd); assertEquals (új BigInteger ("12"), multiplyAndmod); assertEquals (új BigInteger ("22"), modInverse); assertEquals (új BigInteger ("7"), modPow); }
Rendelkezik az elsődleges generációval és az elsődleges teszteléssel kapcsolatos módszerekkel is:
@Test public void givenBigIntegers_whenPrimeOperations_thenExpectedResult () {BigInteger i = BigInteger.probablePrime (100, új Random ()); logikai isProbablePrime = i.isProbablePrime (1000); assertEquals (true, isProbablePrime); }
7. Következtetés
Ebben a gyors bemutatóban felfedeztük az osztályokat BigDecimal és BigInteger. Hasznosak olyan fejlett numerikus számításokhoz, ahol a primitív egész típusú típusok nem elegendőek.
Szokás szerint a teljes forráskód megtalálható a GitHubon.