JavaのBigDecimalとBigInteger

1。概要

このチュートリアルでは、BigDecimalクラスとBigIntegerクラスを示します。

2つのデータ型、それらの特性、およびそれらの使用シナリオについて説明します。また、2つのクラスを使用したさまざまな操作についても簡単に説明します。

2. BigDecimal

BigDecimalは、不変の任意精度の符号付き10進数を表します。これは2つの部分で構成されています。

  • スケーリングされていない値–任意精度の整数
  • スケール–小数点の右側の桁数を表す32ビット整数

たとえば、BigDecimal 3.14のスケーリングされていない値は314で、スケールは2です。

高精度の演算にはBigDecimalを使用します。また、スケールの制御と動作の丸めを必要とする計算にも使用します。そのような例の1つは、金融取引を含む計算です。

String、character array、intlong、およびBigIntegerからBigDecimalオブジェクトを作成できます

@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 = new BigDecimal(123412345678901L); BigInteger bigInteger = BigInteger.probablePrime(100, new Random()); BigDecimal bdFromBigInteger = new 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()); }

doubleからBigDecimalを作成することもできます:

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

ただし、この場合、結果は予想とは異なります(つまり、0.1)。それの訳は:

  • 二重のコンストラクタは正確な翻訳を行います
  • 0.1はdoubleで正確に表現されていません

したがって、doubleコンストラクターの代わりにStringコンストラクターを使用する必要があります

さらに、valueOf静的メソッドを使用してdoublelongBigIntegerに変換できます。

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

このメソッドは、BigDecimalに変換する前に、double文字列表現に変換します。さらに、オブジェクトインスタンスを再利用する場合があります。

したがって、コンストラクターよりvalueOfメソッドを使用する必要があります

3.BigDecimalでの操作

他のNumberクラス(IntegerLongDoubleなど)と同様に、BigDecimalは算術演算と比較演算の演算を提供します。また、スケール操作、丸め、およびフォーマット変換の操作も提供します。

算術(+、-、/、*)または論理(>。<など)演算子をオーバーロードしません。代わりに、対応するメソッド(加算減算乗算除算compareTo)を使用します。

BigDecimalには、精度、スケール、符号などのさまざまな属性を抽出するメソッドがあります

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

compareToメソッドを使用して2つのBigDecimalsの値を比較します

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

このメソッドは、比較中にスケールを無視します。

一方、等しい方法は、2つの考慮のBigDecimalは、としてそれらが値とスケールに等しい場合にのみ等しくオブジェクト。したがって、この方法で比較した場合、BigDecimals1.0と1.00は等しくありません。

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

対応するメソッドを呼び出すことにより、算術演算を実行します

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

BigDecimalは不変であるため、これらの操作は既存のオブジェクトを変更しません。むしろ、それらは新しいオブジェクトを返します。

4.丸めとBigDecimal

数値を四捨五入することにより、より短く、より単純で、より意味のある表現を持つ別の数値に置き換えます。たとえば、端数セントがないため、$ 24.784917を$ 24.78に丸めます。

使用する精度と丸めモードは、計算によって異なります。たとえば、米国連邦税の申告では、HALF_UPを使用してドルの金額を四捨五入するように指定しています

丸め動作を制御するクラスには、RoundingModeMathContextの2つがあります

列挙型RoundingModeは8つの丸めモードが用意されています。

  • 天井–正の無限大に向かって丸めます
  • FLOOR –負の無限大に向かって丸めます
  • UP –ゼロから四捨五入
  • DOWN –ゼロに向かって丸めます
  • HALF_UP –両方のネイバーが等距離にある場合を除き、「最も近いネイバー」に向かって丸めます。等距離の場合は切り上げます。
  • HALF_DOWN –両方のネイバーが等距離でない限り、「最も近いネイバー」に向かって丸められます。等距離の場合は、切り捨てられます。
  • HALF_EVEN –両方のネイバーが等距離にある場合を除き、「最も近いネイバー」に向かって丸めます。等距離の場合は、偶数のネイバーに向かって丸めます。
  • 不要–丸めは不要で、正確な結果が得られない場合はArithmeticExceptionがスローされます

HALF_EVEN丸めモードは、丸め操作によるバイアスを最小限に抑えます。よく使われます。銀行家の丸めとしても知られています。

MathContext encapsulates both precision and rounding mode. There are few predefined MathContexts:

  • DECIMAL32 – 7 digits precision and a rounding mode of HALF_EVEN
  • DECIMAL64 – 16 digits precision and a rounding mode of HALF_EVEN
  • DECIMAL128 – 34 digits precision and a rounding mode of HALF_EVEN
  • UNLIMITED – unlimited precision arithmetic

Using this class, we can round a BigDecimal number using specified precision and rounding behavior:

@Test public void whenRoundingDecimal_thenExpectedResult() { BigDecimal bd = new BigDecimal("2.5"); // Round to 1 digit using HALF_EVEN BigDecimal rounded = bd .round(new MathContext(1, RoundingMode.HALF_EVEN)); assertEquals("2", rounded.toString()); }

Now, let's examine the rounding concept using a sample calculation.

Let's write a method to calculate the total amount to be paid for an item given a quantity and unit price. Let's also apply a discount rate and sales tax rate. We round the final result to cents by using the setScale method:

public static BigDecimal calculateTotalAmount(BigDecimal quantity, BigDecimal unitPrice, BigDecimal discountRate, BigDecimal taxRate) { BigDecimal amount = quantity.multiply(unitPrice); BigDecimal discount = amount.multiply(discountRate); BigDecimal discountedAmount = amount.subtract(discount); BigDecimal tax = discountedAmount.multiply(taxRate); BigDecimal total = discountedAmount.add(tax); // round to 2 decimal places using HALF_EVEN BigDecimal roundedTotal = total.setScale(2, RoundingMode.HALF_EVEN); return roundedTotal; }

Now, let's write a unit test for this method:

@Test public void givenPurchaseTxn_whenCalculatingTotalAmount_thenExpectedResult() { BigDecimal quantity = new BigDecimal("4.5"); BigDecimal unitPrice = new BigDecimal("2.69"); BigDecimal discountRate = new BigDecimal("0.10"); BigDecimal taxRate = new BigDecimal("0.0725"); BigDecimal amountToBePaid = BigDecimalDemo .calculateTotalAmount(quantity, unitPrice, discountRate, taxRate); assertEquals("11.68", amountToBePaid.toString()); }

5. BigInteger

BigInteger represents immutable arbitrary-precision integers. It is similar to the primitive integer types but allows arbitrary large values.

It is used when integers involved are larger than the limit of long type. For example, the factorial of 50 is 30414093201713378043612608166064768844377641568960512000000000000. This value is too big for an int or long data type to handle. It can only be stored in a BigInteger variable.

It is widely used in security and cryptography applications.

We can create BigInteger from a byte array or String:

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

In addition, we can convert a long to BigInteger using the static method valueOf:

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

6. Operations on BigInteger

Similar to int and long, BigInteger implements all the arithmetic and logical operations. But, it does not overload the operators.

It also implements the corresponding methods from Math class: abs, min, max, pow, signum.

We compare the value of two BigIntegers using the compareTo method:

@Test public void givenBigIntegers_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 perform arithmetic operations by calling the corresponding methods:

@Test public void givenBigIntegers_whenPerformingArithmetic_thenExpectedResult() { BigInteger i = new BigInteger("4"); BigInteger j = new BigInteger("2"); BigInteger sum = i.add(j); BigInteger difference = i.subtract(j); BigInteger quotient = i.divide(j); BigInteger product = i.multiply(j); assertEquals(new BigInteger("6"), sum); assertEquals(new BigInteger("2"), difference); assertEquals(new BigInteger("2"), quotient); assertEquals(new BigInteger("8"), product); }

As BigInteger is immutable, these operations do not modify the existing objects. Unlike, int and long, these operations do not overflow.

BigIntegerには、intlong同様のビット演算があります。ただし、演​​算子の代わりにメソッドを使用する必要があります。

@Test public void givenBigIntegers_whenPerformingBitOperations_thenExpectedResult() { BigInteger i = new BigInteger("17"); BigInteger j = new BigInteger("7"); BigInteger and = i.and(j); BigInteger or = 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(new BigInteger("1"), and); assertEquals(new BigInteger("23"), or); assertEquals(new BigInteger("-8"), not); assertEquals(new BigInteger("22"), xor); assertEquals(new BigInteger("16"), andNot); assertEquals(new BigInteger("34"), shiftLeft); assertEquals(new BigInteger("8"), shiftRight); }

追加のビット操作メソッドがあります

@Test public void givenBigIntegers_whenPerformingBitManipulations_thenExpectedResult() { BigInteger i = new 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は、GCD計算とモジュラー演算のメソッドを提供します

@Test public void givenBigIntegers_whenModularCalculation_thenExpectedResult() { BigInteger i = new 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); }

また、素数生成と素数性テストに関連する方法もあります

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

7.結論

このクイックチュートリアルでは、BigDecimalクラスとBigIntegerクラスについて説明しましたこれらは、プリミティブ整数型では不十分な高度な数値計算に役立ちます。

いつものように、完全なソースコードはGitHubにあります。