Master Precise Calculations in Java: A Deep Dive into BigDecimal
This article explains why Java's BigDecimal class is essential for exact arithmetic beyond double's 16‑digit limit, details its constructors, common methods, formatting techniques, handling of division exceptions, and provides a utility class with high‑precision operations, all illustrated with clear code examples.
Java provides the BigDecimal class in the java.math package for precise calculations that exceed the 16‑digit effective range of double. While float and double handle many cases, they lose precision when converting from strings or performing arithmetic on very large or very small numbers.
BigDecimal Overview
BigDecimal objects cannot be manipulated with the traditional arithmetic operators (+, -, *, /); instead, you must call the corresponding methods, each accepting another BigDecimal as a parameter. Constructors create immutable objects.
Common Constructors
BigDecimal(int) – creates an instance from an integer value.
BigDecimal(double) – creates an instance from a double value (may introduce unexpected precision errors).
BigDecimal(long) – creates an instance from a long value.
BigDecimal(String) – creates an instance from a string representation (recommended for exact values).
Example demonstrating the difference between the double and String constructors:
BigDecimal a = new BigDecimal(0.1);
System.out.println("a values is:" + a);
BigDecimal b = new BigDecimal("0.1");
System.out.println("b values is:" + b);Output:
a values is:0.1000000000000000055511151231257827021181583404541015625
=====================
b values is:0.1Analysis:
The BigDecimal(double) constructor inherits the inexact binary representation of the double, producing a long decimal expansion.
The BigDecimal(String) constructor yields the exact decimal value, so it is generally preferred.
If a double must be used, call BigDecimal.valueOf(double) to obtain a predictable conversion.
Common Methods
add(BigDecimal) – returns the sum.
subtract(BigDecimal) – returns the difference.
multiply(BigDecimal) – returns the product.
divide(BigDecimal) – returns the quotient (may require a scale to avoid non‑terminating decimals).
toString() – converts the value to a string.
doubleValue() , floatValue() , longValue() , intValue() – convert to primitive types.
Comparison
Use compareTo(BigDecimal) to compare two values. It returns -1, 0, or 1 for less than, equal, or greater than respectively.
int result = bigDecimal1.compareTo(bigDecimal2);
// result = -1 if bigDecimal1 < bigDecimal2, 0 if equal, 1 if greaterFormatting
Combine NumberFormat with BigDecimal to format currency, percentages, or generic numbers with controlled precision.
NumberFormat currency = NumberFormat.getCurrencyInstance();
NumberFormat percent = NumberFormat.getPercentInstance();
percent.setMaximumFractionDigits(3);
BigDecimal loanAmount = new BigDecimal("15000.48");
BigDecimal interestRate = new BigDecimal("0.008");
BigDecimal interest = loanAmount.multiply(interestRate);
System.out.println("贷款金额:\t" + currency.format(loanAmount));
System.out.println("利率:\t" + percent.format(interestRate));
System.out.println("利息:\t" + currency.format(interest));Result example:
贷款金额: ¥15,000.48 利率: 0.8% 利息: ¥120.00Common Exception
Dividing with divide() may throw
java.lang.ArithmeticException: Non-terminating decimal expansionwhen the result is a repeating decimal. Specify a scale to avoid the exception:
Use divide(divisor, scale) or divide(divisor, scale, RoundingMode.HALF_UP) .
Summary
Use BigDecimal for calculations requiring exact decimal precision. It is slower than double and should be reserved for high‑precision scenarios. Prefer the String constructor to avoid hidden binary errors, and remember that each arithmetic operation creates a new immutable instance.
Utility Class Example
package com.vivo.ars.util;
import java.math.BigDecimal;
public class ArithmeticUtils {
private static final int DEF_DIV_SCALE = 10;
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
public static BigDecimal add(String v1, String v2) {
return new BigDecimal(v1).add(new BigDecimal(v2));
}
public static String add(String v1, String v2, int scale) {
if (scale < 0) throw new IllegalArgumentException("The scale must be a positive integer or zero");
return new BigDecimal(v1).add(new BigDecimal(v2)).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
// Similar methods for sub, mul, div, round, remainder, compare, etc.
}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.
