Representing Money In Java :

  • use BigDecimal, int, or long (BigDecimal is the recommended default)
  • the int and long forms represent pennies (or the equivalent, of course)
  • BigDecimal is a little more inconvenient to use, but has built-in rounding modes
  • double or float are not recommended, since they always carry small rounding differences
  • the Currency class encapsulates standard identifiers for the world's currencies

 Number of digits :

  • <=9 : use int, long , or BigDecimal
  • <=18 : use long or BigDecimal
  • >18 : use BigDecimal

Reminders for BigDecimal :

  • the recommended constructor is BigDecimal(String), not BigDecimal(double) - see javadoc
  • BigDecimal objects are immutable - operations always return new objects, and never modify the state of existing objects
  • the ROUND_HALF_EVEN style of rounding introduces the least bias. It is also called bankers' rounding, or round-to-even.

Why can't my computer add?

Sooner or later, everyone trying to calculate money in Java discovers that computers can't add. Doesn't Java know how to add two numbers together? Actually, the problem is much older than Java and can be found in the IEEE 754 specification that defines how floating-point numbers work. As at least one software engineer has commented, "floating-point is designed to give you the wrong answer very quickly." This is not far from the truth.

So how do I calculate the VC's stock options?

We now know that unless we need to work with less than one million dollars that float is not going to work for us. So what do we do for large monetary calculations? There are at least two solutions that are commonly used. The first is to do everything using integral types. You will need to remember that "590" is really "$5.90" or your payroll system will be giving everyone big raises. You may, however, run into problems if you need to do percent calculations rounding to the nearest penny since ints don't support this type of calculation. You may want to write a class or two to help you out with this.

There is, however, a better solution. Douglas Dunn ("Java Rules", p.235) has suggested that Java may be the first programming language where using a class instead of primitives to do monetary calculations may become the norm for mainstream business applications. That class is what the rest of this article will discuss.

BigDecimal to the Rescue!


import java.text.*;
import java.math.*;

public class CanAdd {
   public static void main(String[] args) {
      BigDecimal a1 = new BigDecimal("8250325.12");
      BigDecimal b1 = new BigDecimal("4321456.31");
      BigDecimal c1 = a1.add(b1);
      System.out.println(NumberFormat.getCurrencyInstance().format(c1));
   }
}

This program prints out the correct answer, #12,571,781.43. In fact, the BigDecimal class can handle any number no matter how large it is (within the limitations of your computer's memory). How does it do it? BigDecimal stores numbers in an array. Each entry in the array represents a digit. The larger the number required, the larger the array that BigDecimal creates to hold the number. The scale (number of digits to the right of the decimal) is stored in an int.

BigDecimal has four constructors but the one you will want to use most is the one that takes a String. If we ran our test program using the constructor that takes a double, we would still get the wrong answer if we used float constants: The reason this doesn't work correctly is that the float constants will undergo loss of precision before they are sent to the constructor of the BigDecimal. Using the String constructor will always allow the BigDecimal to represent exactly the number you want.