BigDecimal represent immutable, arbitrary-precision signed decimal numbers. A BigDecimal
consists of an arbitrary precision integer unscaled value and a 32-bit integer scale.
The BigDecimal
class provides operations for arithmetic, scale manipulation, rounding, comparison, hashing, and format conversion. The toString()
method provides a canonical representation of a BigDecimal
.
Why we need BigDecimal? We already have double, float and their classes Double and Float. It is hard to represent many decimal numbers. If in mathematics it is easy to write 10/3 to actually show it is quite a challenge. Also humans work with decimal system but the computer work in binary system which mean that the computer will struggle to represent numbers which for us humans looks normal.
import java.math.BigDecimal; public class MainBigDecimalTest { public static void main(String[] args) { double d1 = 2.0; double d2 = 2.63; double result = d2 - d1; System.out.println("result: " + result); } }
Output:
result: 0.6299999999999999
Now there are ways to minimize this errors and one of them is to use BigDecimal
class.
Same calculation with BigDecimal:
import java.math.BigDecimal; public class MainBigDecimalTest { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("2.0"); BigDecimal d2 = new BigDecimal("2.63"); BigDecimal result = d2.subtract(d1); System.out.println("result: " + result); } }
Output:
result: 0.63
So why we have float and decimal at all? Because calculations done with them are fast and it is normal for certain calculation not to be precise.
Lets look again the previous value of decimal: 0.6299999999999999 The major problem here is the rounding, right? So we can write also the program like this:
public class MainBigDecimalTest { public static void main(String[] args) { double d1 = 2.0; double d2 = 2.63; double result = d2 - d1; System.out.printf("result: %.2f", result); } }
Output:
result: 0.63
Even with a small error if we round up to the two numbers after the decimal sign we get the value which we expect.
But there are calculations for example in the finance sector where we should not make even small error. There using BigDecimal is a must. Remember in such case do not change to Double or Float before or after calculations with BigDecimal because creating object from Double or Float already can introduce this loss of precision. One good way to create BigDecimal is with the constructors which accept String. There we can add the exact number that we want. For example BigDecimal d2 = new BigDecimal(“2.63”);
When we need to compare of BigDecimals never use equals because equals will consider also the scale and we don’t need the scale to be considered when check for number equality. Always use compareTo method instead.
import java.math.BigDecimal; public class MainBigDecimalTest { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("2.00"); BigDecimal d2 = new BigDecimal("2"); // equals also consider the scale System.out.println(d1.equals(d2)); // compare == 0 means that the two numbers are equal System.out.println(d1.compareTo(d2) == 0); } }
Output:
false
true
BigDecimal rounding. In some cases we need to round result. There is different rounding modes depending of our requirements.
import java.math.BigDecimal; import java.math.RoundingMode; public class MainBigDecimalTest { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("1.9534"); BigDecimal result1 = d1.setScale(2, RoundingMode.HALF_EVEN); System.out.println("result1: " + result1); BigDecimal d2 = new BigDecimal("1.9554"); BigDecimal result2 = d2.setScale(2, RoundingMode.HALF_EVEN); System.out.println("result2: " + result2); // There is different RoundingMode depending on our requirements. BigDecimal result3 = d2.setScale(2, RoundingMode.DOWN); System.out.println("result3: " + result3); } }
Output:
result1: 1.95
result2: 1.96
result2: 1.95