1.概要

このチュートリアルでは、https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html[

BigDecimal

]およびhttps://docs.oracle.com/javase/8について説明します。/docs/api/java/math/BigInteger.html[

BigInteger

]クラス。

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

2.

BigDecimal


  • BigDecimal

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

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

  • スケール – 桁数を表す32ビット整数

小数点の右側

たとえば、

BigDecimal

3.14のスケールなしの値は314、スケールは2です。

  • 高精度演算には

    BigDecimal

    を使用しています。スケールの制御や四捨五入** を必要とする計算にも使用します。そのような例の1つは、金融取引を含む計算です。


  • String

    、文字配列、

    int



    long

    、および

    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)。それの訳は:


  • double

    コンストラクタは正確な翻訳を行います

  • 0.1は

    double

    に正確な表現はありません

したがって、


double

コンストラクタ

の代わりにS

__tring

__コンストラクタを使うべきです。

さらに、

valueOf

静的メソッドを使用して、

double



long



BigInteger

に変換できます。

@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

表現に変換します。さらに、オブジェクトインスタンスを再利用することもあります。

したがって、** コンストラクタよりも

valueOf

メソッドを使用する必要があります。

3.

BigDecimal

に対する操作

他の

Number

クラス(

Integer



Long



Double

など)と同様に、

BigDecimal

は算術演算と比較演算のための演算を提供します。また、スケール操作、丸め、およびフォーマット変換のための操作も提供します。

算術演算子(+、 – 、/、** )または論理演算子(>。<etc)はオーバーロードしません。代わりに、対応するメソッド(

add



subtract



multiply



divide

、および

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

  • 2つのBigDecimalの値を

    compareTo

    メソッドを使って比較します。

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

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

一方、

equals

メソッドは、2つの

BigDecimal

オブジェクトが、値とスケールが等しい場合にのみ等しいと見なします。

したがって、この方法で比較すると、

BigDecimals

1.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__を使用して全ドル金額に四捨五入することを指定しています。

  • 丸め動作を制御するクラスが2つあります –

    RoundingMode



    MathContext

    ** 。


enum

RoundingMode


には、8つの丸めモードがあります。


  • CEILING –

    は正の無限大に向かって丸めます


  • FLOOR –

    は負の無限大に丸めます


  • UP –

    はゼロから切り捨てます


  • DOWN –

    ゼロ方向に丸めます


  • HALF

    UP –__は、両方の隣人以外は「最近隣」に丸めます

等距離にある場合、切り上げます
**

HALF

DOWN – 両方の隣人を除いて、「最近隣」に丸めます

等距離の場合は切り捨てます
**

__HALF

EVEN – 両方の場合を除き、____は「最近傍」に向かって回ります

隣人は等距離であり、その場合、偶数に向かって丸めます
隣人
**

UNNECESSARY –

丸めは不要で

ArithmeticException

正確な結果が得られない場合にスローされます


HALF

EVEN__丸めモードは、丸め操作によるバイアスを最小限に抑えます。

よく使われます。それは

銀行家の丸め

としても知られています。



  • MathContext


    は、精度モードと丸めモードの両方をカプセル化しています** 。定義済みの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

    は不変の任意精度の整数** を表します。これは基本整数型と似ていますが、任意の大きな値を使用できます。


  • 関係する整数が

    long

    typeの制限よりも大きい場合に使用されます。

    ** たとえば、50の階乗は

    30414093201713378043612608166064768844377641568960512000000000000.

    です。

    intまたはlong

    データ型が処理するには大きすぎます。これは

    BigInteger

    変数にのみ格納できます。

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


  • byte

    配列または

    String

    ** から

    BigInteger

    を作成できます。

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

さらに、

静的メソッド



valueOf

を使用して

long



BigInteger__に変換できます。

@Test
public void whenLongConvertedToBigInteger__thenValueMatches() {
    BigInteger bi =  BigInteger.valueOf(2305843009213693951L);

    assertEquals("2305843009213693951", bi.toString());
}

6.

BigInteger

に対する操作


int

および

long

と同様に、

BigInteger

はすべての算術演算および論理演算を実装します。しかし、それは演算子をオーバーロードしません。

また、

Math

クラスの対応するメソッド、

abs



min



max



pow



signum

も実装しています。

  • 2つのBigIntegerの値を

    compareTo

    メソッドを使って比較します。

@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

は不変であるため、これらの操作は既存のオブジェクトを変更しません。**

int



long

とは​​異なり、これらの操作はオーバーフローしません。


  • BigInteger

    は、

    int

    および

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

  • 追加のビット操作方法があります** :

@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クラスについて説明しました。プリミティブ整数型では十分ではない高度な数値計算に役立ちます。

いつものように、完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/java-numbers[GitHubについて]で見つけることができます。