Mastering Java BigDecimal: Precise Arithmetic, APIs, and Best Practices
This article explains why commercial calculations should use Java's BigDecimal for exact decimal arithmetic, details its structure, shows how to construct instances safely, covers common API methods, rounding modes, number formatting, and provides practical code examples.
1. Introduction
A junior developer discovered a price‑calculation error caused by floating‑point imprecision; the article stresses that commercial calculations must use BigDecimal because binary floating‑point cannot precisely represent decimal values. Effective Java also recommends BigDecimal for exact arithmetic.
2. BigDecimal Overview
BigDecimalis an immutable arbitrary‑precision signed decimal number composed of an unscaled integer ( BigInteger) and a scale (the number of digits to the right of the decimal point).
For example, BigDecimal 3.14 has an unscaled value of 314 and a scale of 2.
3. Constructing BigDecimal Instances
Instances can be created from String, char[], int, long, BigInteger, and double. Using the double constructor may yield unexpected results because it captures the exact binary representation of the double.
@Test
public void theValueMatches() {
BigDecimal bdFromString = new BigDecimal("0.12");
BigDecimal bdFromCharArray = new BigDecimal(new char[]{'3', '.', '1', '4', '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.12", bdFromString.toString());
assertEquals("3.1415", bdFromCharArray.toString());
assertEquals("42", bdlFromInt.toString());
assertEquals("123412345678901", bdFromLong.toString());
assertEquals(bigInteger.toString(), bdFromBigInteger.toString());
}Creating from double can produce a value that does not match the expected decimal representation:
@Test
public void whenBigDecimalCreatedFromDouble_thenValueMayNotMatch() {
BigDecimal bdFromDouble = new BigDecimal(0.1d);
assertNotEquals("0.1", bdFromDouble.toString());
}To obtain the correct decimal, use the String constructor or the static valueOf method:
@Test
public void whenBigDecimalCreatedUsingValueOf_thenValueMatches() {
BigDecimal bdFromDouble = BigDecimal.valueOf(0.1d);
BigDecimal bigFromLong = BigDecimal.valueOf(1, 1);
assertEquals("0.1", bdFromDouble.toString());
assertEquals("0.1", bigFromLong.toString());
}4. Common API Methods
abs() : absolute value, scale unchanged.
add(BigDecimal augend) : addition, result scale = max of operands.
subtract(BigDecimal augend) : subtraction, result scale = max of operands.
multiply(BigDecimal multiplicand) : multiplication, result scale = sum of operand scales.
divide(BigDecimal divisor) : division; throws ArithmeticException if non‑terminating unless a scale and rounding mode are specified.
divide(BigDecimal divisor, int roundingMode) : division with explicit rounding mode.
divide(BigDecimal divisor, int scale, int roundingMode) : division with both scale and rounding mode.
remainder(BigDecimal divisor) : remainder, scale unchanged.
divideAndRemainder(BigDecimal divisor) : returns an array {quotient, remainder}, e.g., 23/3 yields {7,2}.
divideToIntegralValue(BigDecimal divisor) : integer part of division, scale unchanged.
max(BigDecimal val) / min(BigDecimal val) : larger or smaller of two values, result scale = larger operand's scale.
movePointLeft(int n) / movePointRight(int n) : shift decimal point left or right, adjusting scale accordingly.
negate() : sign change, scale unchanged.
pow(int n) : exponentiation.
scaleByPowerOfTen(int n) : equivalent to moving the decimal point right by n places (multiply by 10^n).
5. Attribute Extraction
Methods such as precision(), scale(), and signum() retrieve a BigDecimal 's 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());
}5.2 Comparison
compareTocompares numeric values and ignores scale, while equals requires both value and scale to match.
@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);
} @Test
public void whenEqualsCalled_thenSizeAndScaleMatched() {
BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("1.00");
assertFalse(bd1.equals(bd2));
}5.3 Arithmetic Operations
Four basic operations are provided by add, subtract, multiply, and divide:
@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);
}5.4 Rounding
The RoundingMode enum defines eight strategies: UP , DOWN , FLOOR , CEILING , HALF_DOWN , HALF_UP , HALF_EVEN , and UNNECESSARY (throws an exception if rounding would be required).
6. Number Formatting
Java provides NumberFormat and its subclass DecimalFormat for formatting numbers, currencies, and percentages. NumberFormat offers locale‑specific factories such as getInstance, getCurrencyInstance, and getPercentInstance. DecimalFormat uses pattern strings where:
"0" forces a digit (pads with zeros if absent).
"#" displays an optional digit.
"." denotes the decimal point (only once per pattern).
"," inserts grouping separators (must appear before the decimal point).
7. Conclusion
The article summarizes essential knowledge about BigDecimal, recommending it as a reference for precise commercial calculations and encouraging readers to keep the guide handy.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
