Search code examples
javadoublebigdecimal

Which Data Type should I use for Handling an ERP: BigDecimal or Double in Java?


I am currently developing an ERP (Enterprise Resource Planning) system and need to make decisions regarding the type of data to use for handling calculations and other numerical values within the application.

I know that Java offers several options for handling decimal numbers, such as BigDecimal and Double. I understand that each has its own advantages and disadvantages, but I want to ensure that I choose the most appropriate one to maintain precision and efficiency in my system.

Here are some specific contexts where I need to apply calculations:

  • Billing and Payments: handle prices, taxes, discounts, etc.
  • Payroll and Accounting:
  • Inventory Management: Including unit prices and product costs.

I am inclined to use BigDecimal for financial operations due to the precision it offers, but I am concerned about the impact on performance. On the other hand, Double might be more efficient in terms of speed but could introduce rounding errors.

What recommendations do you have for handling these cases in an ERP? In which situations would it be preferable to use BigDecimal and when Double? Are there any patterns or best practices I should follow?


Solution

  • Avoid floating-point for money

    Floating-point technology trades away accuracy for speed of execution.

    In Java, the primitive types float and double are floating point types. So are their wrapper classes, Float and Double. Never use these where accuracy matters. That means never for money.

    Use either BigDecimal or whole integers

    Instead, fractional money amounts must be handled in one of these approaches:

    • Use BigDecimal objects. This type is much slower than floating-point, but accurate. The syntax is clumsier than numeric literals, of course. But on the up-side, besides accuracy, you get handy methods such as Banker’s Rounding.
    • Move the decimal point by multiplication to get a whole number. For example, to track USD to the penny, multiply by 100 to get cents (¢) as whole integer values (long). To track USD to the tenth of a cent, multiply by a thousand to represent mills (₥).
    • Use a library with classes that represent money. One such library is Joda-Money, another is JavaMoney. Adding such a framework to Java itself has been considered, and may be considered again.

    Table of types for fractional money

    Type Example Notes Pros Cons
    Floating-point
    float & double
    1.23d Never use for money Fast execution. Convenient use as literals. Inaccurate.
    BigDecimal new BigDecimal( "1.23" ) Accurately represents fractional amounts. Handy methods, such as Banker’s Rounding. Slow. Clumsy syntax.
    Whole integer
    int & long
    long cents = new Double( 1.23d * 100 ).longValue() ; Requires that you multiply fractional inputs, and divide to get fractional outputs. Fast execution. Simple type, with direct matching types in database. May be confusing to naïve programmer & user. (Be sure to label clearly and consistently such as cents or mills.)
    Joda-Money library Money money = Money.parse("USD 23.87") ; Explicitly built for the problem of handling money amounts and math. Handles both fixed-precision and variable-precision Not standardized.