Saturday, April 6, 2013

Best way for storing currency values in Java

Question : Which data type would you choose for storing currency values like Trading Price ? What's your opinion about Float, Double and BigDecimal ?

Solution
Float & Double are Bad for financial world, never use them for monetary calculations.

There are two main reasons supporting this statement -

1.) All floating point values that can represent a currency amount (in dollars and cents) can not be stored exactly as it is in the memory. So if we want to store 0.1 dollar (10 cents), float/double can not store it as it is. Let's try to understand this fact by taking this simple example

public class DoubleForCurrency {

public static void main(String[] args) {
 double total = 0.2;
 for(int i=0;i<100;i++){
  total+=0.2;
 }
 System.out.println("total = " + total);
 }
 
}

OUTPUT : total = 20.19999999999996
The output should have been 20.20 (20 dollars and 20 cents), but floating point calculation made it 20.1999999999..

2.) There is not much flexibility provided by Math.round() method for rounding the given calculation result compared to functionality offered by MathContext. RoundingMode provides options such as ROUND_UP, ROUND_DOWN, ROUND_CEILING, ROUND_FLOOR, ROUND_UNNECESSARY, etc


BigDecimal For the Rescue
BigDecimal represents a signed decimal number of arbitrary precision with an associated scale. BigDecimal provides full control over the precision and rounding of the number value. Virtually its possible to calculate value of pi to 2 billion decimal places using BigDecimal.

That's the reason we should always prefer BigDecimal or BigInteger for financial calculations.

Notes

Primitive type - int and long are also useful for monetary calculations if decimal precision is not required

We should really avoid using BigDecimal(double value) constructor instead prefer BigDecimal(String) because BigDecimal (0.1) results in 0.100000...5..3 being stored in BigDecimal instance. In contrast BigDecimal ("0.1") stores exactly 0.1

Question : What is Precision and Scale ?
Precision is the total number of digits (or significant digits) of a real number
Scale specifies number of digits after decimal place

For example, 12.345 has precision of 5 and scale of 3

How to format BigDecimal Value without getting exponentiation in the result & Strip the trailing zeros?

We might get exponentiations in the calculation result if we do not follow some best practices while using Bigdecimal. Below is the code snippet which shows a good usage example of handling the calculation result using Bigdecimal.

public class BigDecimalForCurrency {
    public static void main(String[] args) {
        int scale = 4;
        double value = 0.11111;
        BigDecimal tempBig = new BigDecimal(Double.toString(value));
        tempBig = tempBig.setScale(scale, BigDecimal.ROUND_HALF_EVEN);
        String strValue = tempBig.stripTrailingZeros().toPlainString();
        System.out.println("tempBig = " + strValue);
    }
}

No comments:

Post a Comment

Your comment will be published after review from moderator