What rounding method should you use in Java for money?

10,108

Solution 1

Most applications that calculate money don't use floating point (double, float); they use integer amounts representing a smaller unit. For example in $USD, money can be represented in pennies which is 1/100 of a dollar.

For better accuracy, you may want to have an integer represent 1E-03 ("milli-dollars") or 1E-06. This depends on issues such as interest calculations and your level of precision.

Solution 2

I agree with @Laurent Pireyn that you should round according to the contract. For example, the IRS has you round to the nearest dollar. They say

You can round off cents to whole dollars on your return. If you do round to whole dollars, you must round all amounts. To round, drop amounts under 50 cents and increase amounts from 50 to 99 cents to the next dollar. For example, $1.39 becomes $1 and $2.50 becomes $3

Nice use of RoundingMode.HALF_EVEN. That eliminates the need for you to write and test an function.

If this actually is a tax rate for the IRS, I think that RoundingMode.HALF_UP would be correct.

Solution 3

Money is usually rounded using the "round half to even" rule (also called "banker's rounding). It says that ties are broken by choosing the closest even digit. This can be shown to eliminate bias in rounding for both positive and negative values. (It's not the only rounding rule that has this property, but it's a nice property to have when dealing with money.)

I don't think that this rule is available in the standard API, although it isn't hard to code it up.

Solution 4

You're already using BigDecimal for the rounding, you're already using a rounding mode that is well-suited for financial applications unless there are specific requirements or regulations that proscribe a different one.

The only thing you absolutely MUST do is take the last step and use BigDecimal to represent the money values throughout your application. That's exactly what it's for, and it's much better suited to that task than double since it can represent decimal fractions exactly as expected.

Share:
10,108
Tom Currency
Author by

Tom Currency

Updated on June 04, 2022

Comments

  • Tom Currency
    Tom Currency almost 2 years

    Suppose I have a decimal value in Java that represents money.

    What's the best way to round these values?

    For example, if I have a value that's calculated based on a tax rate and I end up with a result of, say, 5.3999999999999995 as the tax amount, should I round it to 2 decimal places simply by doing this:

    double d = 5.3999999999999995
    BigDecimal bd = new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN);
    d = bd.doubleValue();
    

    to produce the currency value:

    5.40
    
    • Laurent Pireyn
      Laurent Pireyn almost 13 years
      The exact formula used to round values is typically specified in a contract that has some legal authority. Nevertheless, you should never use doubles to represent amounts of money.
    • Tom Currency
      Tom Currency almost 13 years
      I see. Why should you not use doubles? Floats are better? I thought it's better to have more precision rather than less - and therefore to use doubles as much as possible. But I'm happy to be corrected.
    • Woot4Moo
      Woot4Moo almost 13 years
      float is not the way to go either
    • Tom Currency
      Tom Currency almost 13 years
      @Woot4Moo: Any particular reason?
    • Woot4Moo
      Woot4Moo almost 13 years
      @Tom float is inherently inaccurate. this article may be of help. support.microsoft.com/kb/125056 the basic gist is a computer doesn't know how to represent a fraction of an integer.
    • Tom Currency
      Tom Currency almost 13 years
      Thanks for the link. Didn't know that. Good thing I found this out in time.
    • biziclop
      biziclop almost 13 years
      Rounding rules are also currency-specific.
    • Michael Borgwardt
      Michael Borgwardt almost 13 years
      @Tom: No, binary floats are absolutely not meant or fit to be used for money. They were designed mainly for numerical application (engineering and science). Read more here: floating-point-gui.de
    • Michael Borgwardt
      Michael Borgwardt almost 13 years
      @Woot4Moo: computers can represent fractions just fine, and floats do exactly that. Problems only appear when people expect the behaviour of decimal fractions while using a binary format. Nobody is suprised when there's problems representing 1/3 exactly.
  • Michael Borgwardt
    Michael Borgwardt almost 13 years
    The rule is very much available in the standard API - twice, actually: download.oracle.com/javase/6/docs/api/java/math/… and download.oracle.com/javase/6/docs/api/java/math/…
  • Tom Currency
    Tom Currency almost 13 years
    Am I correct that the "round half to even" rule is what I am using in the example above and can simply stick with the above code to do "banker's rounding"?
  • Tom Currency
    Tom Currency almost 13 years
    Is it bad to use floating point for money? I thought that's exactly what floating point is for? Feel free to correct me - I really don't know.
  • duffymo
    duffymo almost 13 years
    yes, it's bad to use floating point for money. No, floating point numbers were not developed to represent money. I think scientific computing had far more to do with it.
  • bwawok
    bwawok almost 13 years
    Floating points give you 3.4444444444 dollars, hard to cash that
  • hooknc
    hooknc almost 13 years
    +1 for not using float or double for currency. Much better to use an integer and think of dollars as cents instead.
  • Ted Hopp
    Ted Hopp almost 13 years
    @Michael - Thanks. I should have dug through the docs a little deeper.
  • Michael Borgwardt
    Michael Borgwardt almost 13 years
    Integers are only a nasty hack for when you don't have something like BigDecimal - which Tom is ironically already using, just not completely.