Thursday, February 26, 2009

Use of Java BigDecimal Class


Java BigDecimal Class
If you're in the finance arena and just can't deal with any chance of round off error, consider using the BigDecimal class found in the java.math package. For numbers larger then can be represented by a double or float, the BigDecimal class never rounds off, offering infinite precision.
The first thing you need to know when working with BigInteger is that you can't use the standard math operators like plus (+) or minus (-). Any time you need to do something as simple as adding numbers together, you must call a method of the class.
This brings up the second point of using the class. Created instances are immutable. In other words, once created, you can't change it. So, methods like add or divide return new BigDecimal objects, instead of updating existing ones.
When using BigDecimal, you specify a scale, meaning the number of digits after the decimal point, and all numerical computations return that many significant digits. When rounding must occur, you must specify a rounding constant so the system can determine how you want the system to truncate the last digit.
BigDecimal Rounding Constants:
ROUND_CEILING Round up towards positive infinity
ROUND_DOWN Round towards zero
ROUND_FLOOR Round towards negative infinity
ROUND_HALF_DOWN Round towards nearest neighbor, or zero if equal
ROUND_HALF_EVEN Round towards nearest neighbor, or even if equal
ROUND_HALF_UP Round towards nearest neighbor, or away from zero if equal
ROUND_UNNECESSARY Value can be represented without rounding
ROUND_UP Round away from zero
You can specify the scale for a BigDecimal in one of three ways. When you call the BigDecimal constructor with a String, the number of digits after the decimal place determines the scale. When you call the constructor passing in a BigInteger, you also pass in a scale. And, you can always change it later with setScale.
To demonstrate, the following program calculates how much money you'll have after a year, investing $10,000 in an account with an annual rate of return at 2.25%.
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Locale;

public class BigDecSample {
public static void main(String args[]) {
BigDecimal rate =
new BigDecimal(".022500");
BigDecimal months =
new BigDecimal("12");
BigDecimal monthlyRate =
rate.divide(months, BigDecimal.ROUND_HALF_DOWN);
NumberFormat pf =
NumberFormat.getPercentInstance(Locale.US);
pf.setMinimumFractionDigits(4);
System.out.println("Annual rate : "
+ pf.format(rate.doubleValue()));
System.out.println("Monthly rate: "
+ pf.format(monthlyRate.doubleValue()));
BigDecimal balance =
new BigDecimal("10000.0000");
NumberFormat nf =
NumberFormat.getCurrencyInstance();
for (int i=0; i<12; i++) {
BigDecimal interest =
balance.multiply(monthlyRate);
balance = balance.add(interest);
System.out.println("Balance : "
+ nf.format(balance.doubleValue()));
}
}
}
And then running the program generates the following output:
Annual rate : 2.2500%
Monthly rate: 0.1875%
Balance : $10,018.75
Balance : $10,037.54
Balance : $10,056.36
Balance : $10,075.21
Balance : $10,094.10
Balance : $10,113.03
Balance : $10,131.99
Balance : $10,150.99
Balance : $10,170.02
Balance : $10,189.09
Balance : $10,208.19
Balance : $10,227.33
Meaning that you'll get $227.33 back in interest, not $225 as you might expect, since earned interest is compounded, giving you interest on your interest.