Java: Common class resolution 4 (BigInteger and BigDecimal classes)

Keywords: Java

BigInteger class

Basic Definitions

In Java, the maximum range of integers natively provided by the CPU is 64-bit long integers. Long integers can be computed directly from CPU instructions, and they are very fast. When we use integers that extend beyond the long type, only software can be used to simulate a large integer. java.math.BigInteger is an integer of any size, with an int[]inside itArray to simulate a very large integer:

BigInteger bi = new BigInteger("1234567890"); 
System.out.println(bi.pow(5)); // 2867971860299718107233761438093672048294900000

Example operations for BigInteger

Only instance methods can be used when performing operations on BigInteger. For example, addition operations:

BigInteger i1 = new BigInteger("1234567890"); 
BigInteger i2 = new BigInteger("12345678901234567890"); 
BigInteger sum = i1.add(i2); // 12345678902469135780

BigInteger has no range limitations compared to long integer operations, but the disadvantage is that it is slower. You can also convert BigInteger to long:

BigInteger i = new BigInteger("123456789000"); 
System.out.println(i.longValue()); // 123456789000 
System.out.println(i.multiply(i).longValueExact()); //java.lang.ArithmeticException: BigInteger out of long range

BigInteger converted to base type

As shown in the code above, when using the longValueExact() method, an ArithmeticException is thrown if it exceeds the range of the long type.
BigInteger, like Integer and Long, is also an immutable class and inherits from the Number class. Number defines several methods for converting to a basic type:

Convert to byte:byteValue()
Convert to short:shortValue()
Convert to int:intValue()
Convert to long:longValue()
Convert to float:floatValue()
Convert to double:doubleValue()

By doing this, you can convert BigInteger to a base type. If BigInteger represents a range that exceeds
If you need to convert to a base type accurately, you can use methods such as intValueExact(), longValueExact(), etc. and throw an ArithmeticException exception if it is out of range.

If the BigInteger value exceeds the maximum range of floats (3.4x1038), the returned floats are as follows:

public class Main { 
	public static void main(String[] args) { 
		BigInteger n = new BigInteger("999999").pow(99);
		float f = n.floatValue(); 
		System.out.println(f); 
	} 
}

Summary:

  • BigInteger is used to represent integers of any size;
  • BigInteger is an immutable class and inherits from Number;
  • When converting BigInteger to a basic type, methods such as longValueExact() can be used to ensure accurate results.

BigDecimal class

Basic Definitions

Like BigInteger, BigDecimal can represent a floating point number of any size and with complete accuracy.

BigDecimal bd = new BigDecimal("123.4567");
System.out.println(bd.multiply(bd)); // 15241.55677489

Basic methods

  1. The scale() method represents the number of decimal places, for example:
BigDecimal d1 = new BigDecimal("123.45"); 
BigDecimal d2 = new BigDecimal("123.4500"); 
BigDecimal d3 = new BigDecimal("1234500"); 
System.out.println(d1.scale()); // 2, two decimal places 
System.out.println(d2.scale()); // 4 
System.out.println(d3.scale()); // 0
  1. The stripTrailingZeros() method formats a BigDecimal as an equal one, but removes the BigDecimal at the end of 0:
BigDecimal d1 = new BigDecimal("123.4500"); 
BigDecimal d2 = d1.stripTrailingZeros(); 
System.out.println(d1.scale()); // 4 
System.out.println(d2.scale()); // 2, because 00 is removed 
BigDecimal d3 = new BigDecimal("1234500"); 
BigDecimal d4 = d3.stripTrailingZeros(); 
System.out.println(d3.scale()); // 0 
System.out.println(d4.scale()); // -2
  1. If a BigDecimal's scale() returns a negative number, it means that the number is an integer and there are two zeros at the end (refer to the appeal code). You can set its scale for a BigDecimal, and if the precision is lower than the original value, rounding (RoundingMode.HALF_UP) or truncating (RoundingMode.DOWN) as specified:
public class Main { 
	public static void main(String[] args) { 
		BigDecimal d1 = new BigDecimal("123.456789"); 
		BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // Rounding, 123.4568 
		BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN); // Direct truncation, 123.4567 
		System.out.println(d2); 
		System.out.println(d3); 
	}
}

When you add, subtract, and multiply a BigDecimal, the precision will not be lost, but when you divide it, there will be situations where you cannot eliminate it, and then you must specify the precision and how to truncate it. An example is as follows:

BigDecimal d1 = new BigDecimal("123.456"); 
BigDecimal d2 = new BigDecimal("23.456789"); 
BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // Keep 10 decimal places and round them 
BigDecimal d4 = d1.divide(d2); // Error: ArithmeticException, because there is no end to it
  1. Divide BigDecimal and find the remainder as follows:
public class Main { 
	public static void main(String[] args) { 
		BigDecimal n = new BigDecimal("12.345"); 
		BigDecimal m = new BigDecimal("0.12"); 
		BigDecimal[] dr = n.divideAndRemainder(m); 
		System.out.println(dr[0]); //  102 
		System.out.println(dr[1]); // 0.875 
	} 
}

When the divideAndRemainder() method is called, the returned array contains two BigDecimals, quotient and remainder, where quotient is always an integer and the remainder is not greater than the divisor. This method can be used to determine whether two BigDecimals are integer multiples:

BigDecimal n = new BigDecimal("12.75"); 
BigDecimal m = new BigDecimal("0.15"); 
BigDecimal[] dr = n.divideAndRemainder(m); 
if (dr[1].signum() == 0) { 
	// n is an integer multiple of m 
}
  1. When comparing whether two BigDecimals have equal values, it is important to note that using the equals() method requires not only that the two BigDecimals have equal values, but also that their scales () are equal:
BigDecimal d1 = new BigDecimal("123.456"); 
BigDecimal d2 = new BigDecimal("123.45600"); 
System.out.println(d1.equals(d2)); // false because scale s are different 
System.out.println(d1.equals(d2.stripTrailingZeros())); // true, because scale becomes 2 after d2 removes tail 0 
System.out.println(d1.compareTo(d2)); // 0

You must use the compareTo() method to compare, which returns negative, positive, and 0 values based on the size of the two values, indicating less than, greater than, and equal, respectively.

Always use compareTo() to compare two BigDecimal values, not equals()!

The relationship between the BigInteger class and the BigDecimal class

If you look at the source code for a BigDecimal, you can see that a BigDecimal is actually represented by a BigInteger and a scale, that is, a BigInteger represents a complete integer, and a scale represents a number of decimal places:

public class BigDecimal extends Number implements Comparable<BigDecimal> { 		
	private final BigInteger intVal; 
	private final int scale; 
}

BigDecimal is also inherited from Number and is an immutable object.

Summary:

  • BigDecimal is used to represent exact decimals and is often used in financial calculations.
  • To compare whether the values of BigDecimal are equal, you must use compareTo() instead of equals().

Posted by mhodgson on Thu, 07 Oct 2021 17:28:35 -0700