JavaのBigDecimalとBigInteger

JavaのBigDecimalおよびBigInteger

1. 概要

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

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

2. BigDecimal

BigDecimal represents an immutable arbitrary-precision signed decimal number。 2つの部分から構成されています。

  • スケールなしの値-任意精度の整数

  • スケール-小数点の右側の桁数を表す32ビット整数

たとえば、BigDecimal 3.14のスケールなしの値は314で、スケールは2です。

We use BigDecimal for high-precision arithmetic. We also use it for calculations requiring control over scale and rounding off behavior。 そのような例の1つは、金融取引を含む計算です。

We can create a BigDecimal object from String, character array, int, long, and 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 = 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)。 それの訳は:

  • doubleコンストラクターは正確な変換を行います

  • 0.1 does not have an exact representation in double

したがって、we should use the String constructor instead of the double constructor

さらに、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をそのString表現に変換します。 さらに、オブジェクトインスタンスを再利用できます。

したがって、we should use the valueOf method in preference to the constructors

3. BigDecimalの操作

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

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

BigDecimal has methods to extract various attributes, such as precision, scale, and sign

@Test
public void whenGettingAttributes_thenExpectedResult() {
    BigDecimal bd = new BigDecimal("-12345.6789");

    assertEquals(9, bd.precision());
    assertEquals(4, bd.scale());
    assertEquals(-1, bd.signum());
}

We compare the value of two BigDecimals using the compareTo method

@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(bd3.compareTo(bd1) > 0);
    assertTrue(bd1.compareTo(bd2) == 0);
    assertTrue(bd1.compareTo(bd3) <= 0);
    assertTrue(bd1.compareTo(bd2) >= 0);
    assertTrue(bd1.compareTo(bd3) != 0);
}

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

一方、the equals method considers two BigDecimal objects as equal only if they are equal in value and scale。 したがって、この方法で比較した場合、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));
}

We perform arithmetic operations by calling the corresponding methods

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

Since BigDecimal is immutable, these operations do not modify the existing objects.むしろ、新しいオブジェクトを返す。

4. 丸めとBigDecimal

By rounding a number, we replace it with another having shorter, simpler and more meaningful representation。 たとえば、小数セントがないため、24.784917ドルを24.78ドルに丸めます。

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

There are two classes which control rounding behavior – RoundingMode and MathContext

enum RoundingModeは、次の8つの丸めモードを提供します。

  • CEILING –は正の無限大に向かって丸められます

  • FLOOR –は負の無限大に向かって丸められます

  • UP –はゼロから四捨五入します

  • DOWN –はゼロに向かって丸められます

  • HALF_UP –は、両方のネイバーが等距離でない限り、「最も近いネイバー」に向かって丸められます。等距離の場合は、切り上げられます。

  • HALF_DOWN –は、両方のネイバーが等距離にある場合を除き、「最も近いネイバー」に向かって丸められます。

  • HALF_EVEN – は、両方のネイバーが等距離にある場合を除き、「最も近いネイバー」に向かって丸められます。等距離にある場合は、偶数のネイバーに向かって丸められます。

  • UNNECESSARY –は丸める必要はなく、正確な結果が得られない場合はArithmeticExceptionがスローされます

HALF_EVEN丸めモードは、丸め操作によるバイアスを最小限に抑えます。 頻繁に使用されます。 banker’s roundingとも呼ばれます。

MathContext encapsulates both precision and rounding mode。 定義済みのMathContextはほとんどありません。

  • DECIMAL32 –7桁の精度とHALF_EVENの丸めモード

  • DECIMAL64 –16桁の精度とHALF_EVENの丸めモード

  • DECIMAL128 –34桁の精度とHALF_EVENの丸めモード

  • UNLIMITED –無制限の高精度演算

このクラスを使用すると、指定された精度と丸め動作を使用して、BigDecimalの数値を丸めることができます。

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

それでは、サンプル計算を使用して丸めの概念を調べてみましょう。

数量と単価を指定して、アイテムに支払われる合計金額を計算するメソッドを作成しましょう。 割引率と消費税率も適用しましょう。 setScaleメソッドを使用して、最終結果をセントに丸めます。

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;
}

それでは、このメソッドの単体テストを書いてみましょう。

@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 used when integers involved are larger than the limit of long type. たとえば、50の階乗は30414093201713378043612608166064768844377641568960512000000000000.です。この値は、int or longデータ型では処理するには大きすぎます。 BigInteger変数にのみ格納できます。

セキュリティおよび暗号化アプリケーションで広く使用されています。

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

さらに、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. BigIntegerの操作

intおよびlongと同様に、BigIntegerはすべての算術演算および論理演算を実装します。 ただし、演​​算子が過負荷になることはありません。

また、Mathクラスの対応するメソッド(absminmaxpowsignum)も実装します。

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

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

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

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

BigIntegerは不変であるため、these operations do not modify the existing objects.とは異なり、intおよびlongthese operations do not overflow.

BigInteger has the bit operations similar to int and long。 ただし、演​​算子の代わりにメソッドを使用する必要があります。

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

It has additional bit manipulation methods

@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 provides methods for GCD computation and modular arithmetic

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

It also has methods related to prime generation and primality testing

@Test
public void givenBigIntegers_whenPrimeOperations_thenExpectedResult() {
    BigInteger i = BigInteger.probablePrime(100, new Random());

    boolean isProbablePrime = i.isProbablePrime(1000);
    assertEquals(true, isProbablePrime);
}

7. 結論

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

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