If you are doing some calculation in your Java application where precise value is required such as in financial operations you should not be using float or double primitive type. Same way if you want to store a very large number, for example if you are calculating factorial then again long or double may fall short. What you should use instead in such scenarios is the Java BigDecimal class which provides operations for arithmetic, scale manipulation, rounding, comparison, hashing, and format conversion. Since it is a class so its object can store a very large value limited only by the computer memory so you can store vary large numbers in BigDecimal class objects.
BigDecimal class in Java also gives its user complete control over rounding behavior which is another common requirement when doing financial calculations.
Let’s see it with an example how use of float or double may give you wrong value-
double d1 = 78.95; double d2 = 67.55; System.out.println("d1 - d2= " + (d1-d2));
You would expect the output as 11.40 but what you get as output is- d1 - d2= 11.400000000000006
So you can see rather than getting a precise value there is some approximation. If you do the same calculation using BigDecimals then you get correct value.
BigDecimal b1 = new BigDecimal("78.95"); BigDecimal b2 = new BigDecimal("67.55"); System.out.println("b1 - b2= " + b1.subtract(b2)); // b1 - b2= 11.40
Java BigDecimal Constructors
In Java BigDecimal class there are many constructors where a BigDecimal object can be initialized using char[], int, double, long, String, BigDecimal. Here are some of the constructors where specific type is passed-
- BigDecimal(char[] in)
- BigDecimal(int val)
- BigDecimal(String val)
There are constructors to pass a MathContext instance as a second argument along with the value. Here are some of the constructors-
- BigDecimal(char[] in, MathContext mc)
- BigDecimal(int val, MathContext mc)
- BigDecimal(long val, MathContext mc)
MathContext instance encapsulates the context settings which describe certain rules for numerical operators like precision setting, rounding mode
- DECIMAL32- A MathContext object with a precision setting of 7 digits (matching the IEEE 754R Decimal32 format) and a rounding mode of HALF_EVEN (IEEE 754R default).
- DECIMAL64- A MathContext object with a precision setting of 16 digits (matching the IEEE 754R Decimal64 format) and a rounding mode of HALF_EVEN (IEEE 754R default).
- DECIMAL128- A MathContext object with a precision setting of 34 digits (matching the IEEE 754R Decimal128 format) and a rounding mode of HALF_EVEN (IEEE 754R default).
- UNLIMITED- A MathContext object whose settings have the values required for unlimited precision arithmetic.
Example of creating BigDecimal instance passing an int and a MathContext.
BigDecimal b1 = new BigDecimal(6, MathContext.DECIMAL64);
There are also constructors to pass scale as an argument and to pass both scale and a MathContext instance.
- BigDecimal(BigInteger unscaledVal, int scale)
- BigDecimal(BigInteger unscaledVal, int scale, MathContext mc)
Here is an example where BigInteger instance and scale is passed to create a BigDecimal instance.
BigInteger bi = new BigInteger("4567898"); int scale = 2; BigDecimal bd = new BigDecimal(bi, scale); System.out.println(bd); // 45678.98
Rounding modes in BigDecimal
One of the convenient feature in Java BigDecimal class is to pass the rounding mode specifying a rounding behavior for numerical operations. RoundingMode is an Enum provided in the package java.math which provides the following Enum constants.
- CEILING- Rounding mode to round towards positive infinity.
- DOWN- Rounding mode to round towards zero.
- FLOOR- Rounding mode to round towards negative infinity.
- HALF_DOWN- Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
- HALF_EVEN- Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
- HALF_UP- Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
- UNNECESSARY- Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
- UP- Rounding mode to round away from zero.
Here is a summary table showing the results of these rounding operations for all rounding modes.
Result of rounding input to one digit with the given rounding mode | ||||||||
---|---|---|---|---|---|---|---|---|
Input Number | UP | DOWN | CEILING | FLOOR | HALF_UP | HALF_DOWN | HALF_EVEN | UNNECESSARY |
5.5 | 6 | 5 | 6 | 5 | 6 | 5 | 6 | throw ArithmeticException |
2.5 | 3 | 2 | 3 | 2 | 3 | 2 | 2 | throw ArithmeticException |
1.6 | 2 | 1 | 2 | 1 | 2 | 2 | 2 | throw ArithmeticException |
1.1 | 2 | 1 | 2 | 1 | 1 | 1 | 1 | throw ArithmeticException |
1.0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
-1.0 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1.1 | -2 | -1 | -1 | -2 | -1 | -1 | -1 | throw ArithmeticException |
-1.6 | -2 | -1 | -1 | -2 | -2 | -2 | -2 | throw ArithmeticException |
-2.5 | -3 | -2 | -2 | -3 | -3 | -2 | -2 | throw ArithmeticException |
-5.5 | -6 | -5 | -5 | -6 | -6 | -5 | -6 | throw ArithmeticException |
Scaling methods in Java BigDecimal
The method to provide scale (number of digits after the decimal) and rounding mode will probably the most used method by you of the BigDecimal class.
- setScale(int newScale)- Returns a BigDecimal whose scale is the specified value, and whose value is numerically equal to this BigDecimal's.
- setScale(int newScale, RoundingMode roundingMode)- Method to set both scale and rounding mode.
BigDecimal bd = new BigDecimal("4567.876"); System.out.println("BigDecimal- " + bd); System.out.println("BigDecimal(RoundingMode.DOWN)- " + bd.setScale(2, RoundingMode.DOWN)); System.out.println("BigDecimal(RoundingMode.CEILING)- " + bd.setScale(2, RoundingMode.CEILING)); System.out.println("BigDecimal(RoundingMode.FLOOR)- " + bd.setScale(2, RoundingMode.FLOOR)); System.out.println("BigDecimal(RoundingMode.HALF_DOWN)- " + bd.setScale(2, RoundingMode.HALF_DOWN)); System.out.println("BigDecimal(RoundingMode.HALF_EVEN)- " + bd.setScale(2, RoundingMode.HALF_EVEN));Output
BigDecimal- 4567.876 BigDecimal(RoundingMode.DOWN)- 4567.87 BigDecimal(RoundingMode.CEILING)- 4567.88 BigDecimal(RoundingMode.FLOOR)- 4567.87 BigDecimal(RoundingMode.HALF_DOWN)- 4567.88 BigDecimal(RoundingMode.HALF_EVEN)- 4567.88
BigDecimal method examples
Let’s see examples of some of the other methods in Java BigDecimal class for performing arithmetic operations.
1. Arithmetic operators (+, -, *, /) are not permitted with objects in Java so these operators can not be used with BigDecimal instances too. There are methods add, subtract, multiply and divide in BigDecimal class to perform these arithmetic operations.
- add(BigDecimal bd2)- Returns a BigDecimal whose value is (this + bd2).
- divide(BigDecimal divisor)- Returns a BigDecimal whose value is (this / divisor).
- divide(BigDecimal divisor, int scale, RoundingMode roundingMode)- Returns a BigDecimal whose value is (this / divisor), and whose scale is as specified.
- multiply(BigDecimal bd2)- Returns a BigDecimal whose value is (this × bd2)
- subtract(BigDecimal bd2)- Returns a BigDecimal whose value is (this - bd2).
public class BDDemo { public static void main(String[] args) throws IOException { BigDecimal bd1 = new BigDecimal("4567.876"); BigDecimal bd2 = new BigDecimal(4000.676); System.out.println("BigDecimal addition- " + bd1.add(bd2).setScale(2, RoundingMode.HALF_EVEN)); System.out.println("BigDecimal subtraction- " + bd1.subtract(bd2).setScale(2, RoundingMode.HALF_EVEN)); System.out.println("BigDecimal multiplication)- " + bd1.multiply(bd2).setScale(2, RoundingMode.HALF_EVEN)); System.out.println("BigDecimal division- " + bd1.divide(bd2, 2, RoundingMode.HALF_EVEN)); } }Output
BigDecimal addition- 8568.55 BigDecimal subtraction- 567.20 BigDecimal multiplication)- 18274591.88 BigDecimal division- 1.14
2. Max and min methods in BigDecimal
- max(BigDecimal val)- Returns the maximum of this BigDecimal and val.
- min(BigDecimal val)- Returns the minimum of this BigDecimal and val.
BigDecimal bd1 = new BigDecimal("4567.876"); BigDecimal bd2 = new BigDecimal("4000.676"); System.out.println("Max BigDecimal- " + bd1.max(bd2)); System.out.println("Min BigDecimal- " + bd1.min(bd2));Output
Max BigDecimal- 4567.876 Min BigDecimal- 4000.676
3. Pow method in BigDecimal
- pow(int n)- Returns a BigDecimal whose value is (this n).
BigDecimal bd = new BigDecimal("45"); System.out.println("45^4- " + bd.pow(4)); // 4100625
Comparing two BigDecimals
Though for checking object equality you will use equals method but this method doesn't work properly with BigDecimal numbers as this method considers two BigDecimal objects equal only if they are equal both in value and scale thus 5.0 is not equal to 5.00 if equals method is used.
For comparing BigDecimals, compareTo() method is used.
- compareTo(BigDecimal val)- Compares this BigDecimal with the specified BigDecimal. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. Returns- -1 if this is less than val. 0 if both are equal. 1 if this is greater than val.
BigDecimal bd1 = new BigDecimal("5.00"); BigDecimal bd2 = new BigDecimal("5.0"); System.out.println("bd1 equals bd2 - " + bd1.equals(bd2)); System.out.println("bd1 compare to bd2 - " + bd1.compareTo(bd2));Output
bd1 equals bd2 - false bd1 compare to bd2 - 0Reference:
https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/math/BigDecimal.html
https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/math/RoundingMode.html
That's all for the topic Java BigDecimal Class With Examples. If something is missing or you have something to share about the topic please write a comment.
You may also like
No comments:
Post a Comment