## 1. Overview

In this tutorial, we will demonstrate *BigDecimal* and the *BigInteger* classes.

We'll describe the two data types, their characteristics, and their usage scenarios. We'll also briefly cover the various operations using the two classes.

## 2. *BigDecimal*

*BigDecimal* represents an immutable arbitrary-precision signed decimal number. It consists of two parts:

- Unscaled value – an arbitrary precision integer
- Scale – a 32-bit integer representing the number of digits to the right of the decimal point

For example, the *BigDecimal* 3.14 has the unscaled value of 314 and the scale of 2.

**We use ***BigDecimal* for high-precision arithmetic. We also use it for calculations requiring control over scale and rounding off behavior. One such example is calculations involving financial transactions.

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

We can also create *BigDecimal* from *double*:

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

However, the result, in this case, is different from expected (that is 0.1). This is because:

- the
*double* constructor does an exact translation
- 0.1 does not have an exact representation in
*double*

Therefore, **we should use the S***tring* constructor instead of the *double* constructor.

In addition, we can convert *double* and *long* to *BigDecimal* using the *valueOf* static method:

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

This method converts *double* to its *String* representation before converting to *BigDecimal*. In addition, it may reuse object instances.

Hence, **we should use the ***valueOf* method in preference to the constructors.

## 3. Operations on *BigDecimal*

Just like the other *Number* classes (*Integer*, *Long*, *Double* etc.), *BigDecimal* provides operations for arithmetic and comparison operations. It also provides operations for scale manipulation, rounding and format conversion.

It does not overload the the arithmetic (+, -, /, *) or logical (>. < etc) operators. Instead, we use the corresponding methods – *add*, *subtract*, *multiply*, *divide* and *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);
}
```

This method ignores the scale while comparing.

On the other hand,** the ***equals* method considers two *BigDecimal* objects as equal only if they are equal in value and scale. Thus, *BigDecimals* 1.0 and 1.00 are not equal when compared by this method.

```
@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. Rather, they return new objects.

## 4. Rounding and *BigDecimal*

**By rounding a number, we replace it with another having shorter, simpler and more meaningful representation**. For example, we round $24.784917 to $24.78 as we do not have fractional cents.

The precision and rounding mode to be used varies depending on the calculation. For example, U.S. Federal Tax returns specify to round off to whole dollar amounts using *HALF_UP*.

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

The *enum RoundingMode *provides eight rounding modes:

*CEILING –* rounds towards positive infinity
*FLOOR –* rounds towards negative infinity
*UP –* rounds away from zero
*DOWN –* rounds towards zero
*HALF_UP –* rounds towards “nearest neighbor” unless both neighbors are equidistant, in which case rounds up
*HALF_DOWN –* rounds towards “nearest neighbor” unless both neighbors are equidistant, in which case rounds down
*HALF_EVEN – *rounds towards the “nearest neighbor” unless both neighbors are equidistant, in which case, rounds towards the even neighbor
*UNNECESSARY –* no rounding is necessary and *ArithmeticException* is thrown if no exact result is possible

*HALF_EVEN* rounding mode minimizes the bias due to rounding operations. It is frequently used. It is also known as the **banker's rounding**.

*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* has the bit operations similar to *int* and *long*. But, we need to use the methods instead of operators:

```
@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. Conclusion

In this quick tutorial, we explored the classes *BigDecimal* and *BigInteger. *They are useful for advanced numerical computations where the primitive integer types do not suffice.

As usual, the full source code can be found over on GitHub.

res – REST with Spring (eBook) (everywhere)