BigDecimal og BigInteger i Java

1. Oversigt

I denne vejledning vil vi demonstrere BigDecimal og BigInteger klasser.

Vi beskriver de to datatyper, deres karakteristika og deres brugsscenarier. Vi vil også kort dække de forskellige operationer ved hjælp af de to klasser.

2. BigDecimal

BigDecimal repræsenterer et uforanderligt vilkårligt præcision underskrevet decimaltal. Den består af to dele:

  • Uskaleret værdi - et vilkårligt præcisions heltal
  • Skala - et 32-bit heltal, der repræsenterer antallet af cifre til højre for decimaltegnet

F.eks BigDecimal 3.14 har den ikke-skalerede værdi på 314 og skalaen på 2.

Vi bruger BigDecimal til aritmetik med høj præcision. Vi bruger det også til beregninger, der kræver kontrol over skala og afrundingsadfærd. Et sådant eksempel er beregninger, der involverer finansielle transaktioner.

Vi kan oprette en BigDecimal objekt fra Snor, tegn array int, langog BigInteger:

@Test offentlig ugyldig nårBigDecimalCreated_thenValueMatches () {BigDecimal bdFromString = ny BigDecimal ("0.1"); BigDecimal bdFromCharArray = ny BigDecimal (ny tegn [] {'3', '.', '1', '6', '1', '5'}); BigDecimal bdlFromInt = ny BigDecimal (42); BigDecimal bdFromLong = ny BigDecimal (123412345678901L); BigInteger bigInteger = BigInteger.probablePrime (100, nyt tilfældigt ()); BigDecimal bdFromBigInteger = ny 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 ()); }

Vi kan også skabe BigDecimal fra dobbelt:

@Test offentlig ugyldig nårBigDecimalCreatedFromDouble_thenValueMayNotMatch () {BigDecimal bdFromDouble = ny BigDecimal (0.1d); assertNotEquals ("0.1", bdFromDouble.toString ()); }

Imidlertid er resultatet i dette tilfælde forskelligt fra forventet (det vil sige 0,1). Dette er fordi:

  • det dobbelt konstruktør foretager en nøjagtig oversættelse
  • 0,1 har ikke en nøjagtig repræsentation i dobbelt

Derfor, vi skal bruge String konstruktør i stedet for dobbelt konstruktør.

Derudover kan vi konvertere dobbelt og lang til BigInteger bruger Værdi af statisk metode:

@Test offentlig ugyldig nårBigDecimalCreatedUsingValueOf_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 ()); }

Denne metode konverterer dobbelt til dens Snor repræsentation inden konvertering til BigDecimal. Derudover kan det genbruge objektforekomster.

Derfor, vi skal bruge Værdi af metode frem for konstruktørerne.

3. Funktioner på BigDecimal

Ligesom den anden Nummer klasser (Heltal, Lang, Dobbelt etc.), BigDecimal giver operationer til aritmetiske og sammenligningsoperationer. Det giver også operationer til skala manipulation, afrunding og formatkonvertering.

Det overbelaster ikke de aritmetiske (+, -, /, *) eller logiske (>. <Osv) operatorer. I stedet bruger vi de tilsvarende metoder - tilføje, trække fra, formere sig, dele og sammenligne med.

BigDecimal har metoder til at udtrække forskellige attributter, såsom præcision, skala og tegn:

@Test offentlig ugyldig nårGettingAttributes_thenExpectedResult () {BigDecimal bd = ny BigDecimal ("- 12345.6789"); assertEquals (9, bd.precision ()); assertEquals (4, bd.scale ()); assertEquals (-1, bd.signum ()); }

Vi sammenligner værdien af ​​to BigDecimals ved hjælp af sammenligne med metode:

@Test offentlig ugyldig nårComparingBigDecimals_thenExpectedResult () {BigDecimal bd1 = ny BigDecimal ("1.0"); BigDecimal bd2 = ny BigDecimal ("1.00"); BigDecimal bd3 = ny BigDecimal ("2.0"); assertTrue (bd1.compareTo (bd3) 0); assertTrue (bd1.compareTo (bd2) == 0); assertTrue (bd1.compareTo (bd3) = 0); assertTrue (bd1.compareTo (bd3)! = 0); }

Denne metode ignorerer skalaen under sammenligning.

På den anden side, det lige med metode betragter to BigDecimal objekter kun er lige, hvis de er ens i værdi og skala. Dermed, BigDecimals 1.0 og 1.00 er ikke ens sammenlignet med denne metode.

@Test offentlig ugyldig nårEqualsCalled_thenSizeAndScaleMatched () {BigDecimal bd1 = ny BigDecimal ("1.0"); BigDecimal bd2 = ny BigDecimal ("1.00"); assertFalse (bd1.equals (bd2)); }

Vi udfører aritmetiske operationer ved at kalde de tilsvarende metoder:

@Test offentlig ugyldig nårPerformingArithmetic_thenExpectedResult () {BigDecimal bd1 = ny BigDecimal ("4.0"); BigDecimal bd2 = ny BigDecimal ("2.0"); BigDecimal sum = bd1.add (bd2); BigDecimal forskel = bd1.subtract (bd2); BigDecimal kvotient = bd1.divide (bd2); BigDecimal produkt = bd1.multiply (bd2); assertTrue (sum.compareTo (ny BigDecimal ("6.0")) == 0); assertTrue (difference.compareTo (ny BigDecimal ("2.0")) == 0); assertTrue (quotient.compareTo (ny BigDecimal ("2.0")) == 0); assertTrue (product.compareTo (ny BigDecimal ("8.0")) == 0); }

Siden BigDecimal er uforanderlig, ændrer disse operationer ikke de eksisterende objekter. Snarere returnerer de nye objekter.

4. Afrunding og BigDecimal

Ved at afrunde et nummer erstatter vi det med et andet, der har kortere, enklere og mere meningsfuld gengivelse. For eksempel afrunder vi $ 24,784917 til $ 24,78, da vi ikke har brøkdele.

Den præcision og afrundingstilstand, der skal bruges, varierer afhængigt af beregningen. For eksempel angiver amerikanske føderale selvangivelser at afrunde til hele dollarbeløb ved hjælp af HALF_UP.

Der er to klasser, der styrer afrundingsadfærd - Afrundingstilstand og MathContext.

Det enum RoundingMode giver otte afrundingstilstande:

  • Lofter - runder mod positiv uendelighed
  • GULV - runder mod negativ uendelighed
  • OP - runder væk fra nul
  • NED - runder mod nul
  • HALF_UP - runder mod "nærmeste nabo", medmindre begge naboer er lige langt fra hinanden, i hvilket tilfælde runder op
  • HALF_DOWN - runder mod "nærmeste nabo", medmindre begge naboer er lige langt fra hinanden, i hvilket tilfælde runder ned
  • HALF_EVEN - runder mod den “nærmeste nabo”, medmindre begge naboer er lige langt fra hinanden, i hvilket tilfælde runder mod den lige nabo
  • UNØDVENDIG - ingen afrunding er nødvendig og Aritmetisk undtagelse kastes, hvis intet nøjagtigt resultat er muligt

HALV_EVEN afrundingstilstand minimerer bias på grund af afrundingsoperationer. Det bruges ofte. Det er også kendt som bankers afrunding.

MathContext indkapsler både præcision og afrundingstilstand. Der er få foruddefinerede MathContexts:

  • AFGØRELSE32 - 7 cifret præcision og en afrundingstilstand på HALF_EVEN
  • DECIMAL64 - 16 cifre præcision og en afrundingstilstand på HALF_EVEN
  • DECIMAL128 - 34 cifre præcision og en afrundingstilstand på HALF_EVEN
  • UBEGRÆNSET - ubegrænset præcision aritmetik

Ved hjælp af denne klasse kan vi afrunde a BigDecimal nummer ved hjælp af specificeret præcision og afrundingsadfærd:

@Test offentlig ugyldig nårRoundingDecimal_thenExpectedResult () {BigDecimal bd = ny BigDecimal ("2.5"); // Runde til 1 ciffer ved hjælp af HALF_EVEN BigDecimal afrundet = bd .round (ny MathContext (1, RoundingMode.HALF_EVEN)); assertEquals ("2", afrundet.toString ()); }

Lad os nu undersøge afrundingskonceptet ved hjælp af en prøveberegning.

Lad os skrive en metode til at beregne det samlede beløb, der skal betales for en vare givet en mængde og enhedspris. Lad os også anvende en diskonteringssats og moms. Vi afrunder det endelige resultat til cent ved hjælp af setScale metode:

offentlig statisk BigDecimal calcTotalAmount (BigDecimal mængde, BigDecimal unitPrice, BigDecimal discountRate, BigDecimal taxRate) {BigDecimal beløb = antal.multiply (unitPrice); BigDecimal rabat = beløb.multiply (discountRate); BigDecimal discountedAmount = amount.subtract (rabat); BigDecimal skat = discountedAmount.multiply (taxRate); BigDecimal total = discountedAmount.add (skat); // runde til 2 decimaler ved hjælp af HALF_EVEN BigDecimal afrundet total = total.setScale (2, RoundingMode.HALF_EVEN); retur afrundetTotal; }

Lad os nu skrive en enhedstest til denne metode:

@Test offentlig ugyldighed givenPurchaseTxn_whenCalculatingTotalAmount_thenExpectedResult () {BigDecimal mængde = ny BigDecimal ("4,5"); BigDecimal unitPrice = ny BigDecimal ("2.69"); BigDecimal discountRate = ny BigDecimal ("0,10"); BigDecimal taxRate = ny BigDecimal ("0,0725"); BigDecimal amountToBePaid = BigDecimalDemo .calculateTotalAmount (mængde, unitPrice, discountRate, taxRate); assertEquals ("11.68", amountToBePaid.toString ()); }

5. BigInteger

BigInteger repræsenterer uforanderlige heltal med vilkårlig præcision. Det svarer til de primitive heltalstyper, men tillader vilkårlige store værdier.

Det bruges når involverede heltal er større end grænsen på lang type. For eksempel er faktoren på 50 30414093201713378043612608166064768844377641568960512000000000000. Denne værdi er for stor til en int eller lang datatype, der skal håndteres. Det kan kun opbevares i en BigInteger variabel.

Det bruges i vid udstrækning i sikkerheds- og kryptografiapplikationer.

Vi kan skabe BigInteger fra en byte array eller Snor:

@Test offentlig ugyldigt nårBigIntegerCreatedFromConstructor_thenExpectedResult () {BigInteger biFromString = nyt BigInteger ("1234567890987654321"); BigInteger biFromByteArray = nyt BigInteger (ny byte [] {64, 64, 64, 64, 64, 64}); BigInteger biFromSignMagnitude = nyt BigInteger (-1, ny byte [] {64, 64, 64, 64, 64, 64}); assertEquals ("1234567890987654321", biFromString.toString ()); assertEquals ("70644700037184", biFromByteArray.toString ()); assertEquals ("- 70644700037184", biFromSignMagnitude.toString ()); }

Ud over, vi kan konvertere en lang til BigInteger ved hjælp af den statiske metode Værdi af:

@Test offentlig ugyldig nårLongConvertedToBigInteger_thenValueMatches () {BigInteger bi = BigInteger.valueOf (2305843009213693951L); assertEquals ("2305843009213693951", bi.toString ()); }

6. Drift på BigInteger

Svarende til int og lang, BigInteger implementerer alle de aritmetiske og logiske operationer. Men det overbelaster ikke operatørerne.

Det implementerer også de tilsvarende metoder fra Matematik klasse: abs, min, maks, pow, signum.

Vi sammenligner værdien af ​​to BigIntegers ved hjælp af sammenligne med metode:

@Test offentlig ugyldighed givenBigIntegers_whentCompared_thenExpectedResult () {BigInteger i = new BigInteger ("123456789012345678901234567890"); BigInteger j = nyt BigInteger ("123456789012345678901234567891"); BigInteger k = nyt BigInteger ("123456789012345678901234567892"); assertTrue (i.compareTo (i) == 0); assertTrue (j.compareTo (i)> 0); assertTrue (j.compareTo (k) <0); }

Vi udfører aritmetiske operationer ved at kalde de tilsvarende metoder:

@Test offentligt ugyldigt givenBigIntegers_whenPerformingArithmetic_thenExpectedResult () {BigInteger i = nyt BigInteger ("4"); BigInteger j = nyt BigInteger ("2"); BigInteger sum = i.add (j); BigInteger forskel = i.subtract (j); BigInteger kvotient = i.divide (j); BigInteger-produkt = i.multiply (j); assertEquals (nyt BigInteger ("6"), sum); assertEquals (nyt BigInteger ("2"), forskel); assertEquals (nyt BigInteger ("2"), kvotient); assertEquals (nyt BigInteger ("8"), produkt); }

Som BigInteger er uforanderlig, disse handlinger ændrer ikke de eksisterende objekter. I modsætning til, int og lang, disse operationer overløber ikke.

BigInteger har bitoperationer svarende til int og lang. Men vi skal bruge metoderne i stedet for operatører:

@Test offentlig ugyldighed givenBigIntegers_whenPerformingBitOperations_thenExpectedResult () {BigInteger i = new BigInteger ("17"); BigInteger j = nyt BigInteger ("7"); BigInteger og = i.and (j); BigInteger eller = i.or (j); BigInteger ikke = j.not (); BigInteger xor = i.xor (j); BigInteger andNot = i.andNot (j); BigInteger shiftLeft = i.shiftLeft (1); BigInteger shiftRight = i.shiftRight (1); assertEquals (nyt BigInteger ("1") og); assertEquals (nyt BigInteger ("23") eller); assertEquals (nyt BigInteger ("- 8"), ikke); assertEquals (nyt BigInteger ("22"), xor); assertEquals (nyt BigInteger ("16"), og ikke); assertEquals (nyt BigInteger ("34"), shiftLeft); assertEquals (nyt BigInteger ("8"), shiftRight); }

Det har yderligere bitmanipulationsmetoder:

@Test offentlig ugyldighed givenBigIntegers_whenPerformingBitManipulations_thenExpectedResult () {BigInteger i = nyt BigInteger ("1018"); int bitCount = i.bitCount (); int bitLength = i.bitLength (); int getLowestSetBit = i.getLowestSetBit (); boolsk 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 (nyt BigInteger ("5114"), setBit12); assertEquals (nyt BigInteger ("1019"), flipBit0); assertEquals (nyt BigInteger ("1010"), clearBit3); }

BigInteger giver metoder til GCD-beregning og modulær aritmetik:

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

Det har også metoder relateret til prime generation og primality test:

@Test offentlig ugyldighed givenBigIntegers_whenPrimeOperations_thenExpectedResult () {BigInteger i = BigInteger.probablePrime (100, new Random ()); boolsk isProbablePrime = i.isProbablePrime (1000); assertEquals (true, isProbablePrime); }

7. Konklusion

I denne hurtige vejledning udforskede vi klasserne BigDecimal og BigInteger. De er nyttige til avancerede numeriske beregninger, hvor de primitive heltalstyper ikke er tilstrækkelige.

Som sædvanlig kan den fulde kildekode findes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found