7

I've researched and found that when dealing with currency, the best way to go about doing calculations is by the BigDecimal class.

With that in mind, I'm working on a code that converts various types of foreign currency into US currency and vice-versa (specifically, a cashregister that takes foreign currency and converts it into US money, computes the change and returns this amount to the customer in foreign currency).

As of now, many of the methods use double and two of them take in int as a parameter to be used in computing the US currency.

Question:

Since I want to use the BigDecimal class in my calculations, should I change all my methods that make calculations involving doubles to a BigDecimal?

Wormhole99
  • 105
  • 1
  • 4
  • 9
  • 2
    Yes, this sounds like a great idea. 1+ for wanting to avoid use of floating-point numbers for this. – Hovercraft Full Of Eels Mar 31 '12 at 20:14
  • Another practical approach for calculating with money is rationals. They have 'unlimited' precision, are stable and also faster than BigDecimal. – Neet Mar 31 '12 at 20:20

2 Answers2

4

Yes, you should change all floats or doubles to take either ints, longs or BigDecimals.

Floats and doubles are not precise for financial calculations. It's a very good idea to use the Money pattern to deal with amounts and currencies (it's a special type of Quantity). To maintain a list of moneys possibly in multiple currencies, what you're effectively doing is a MoneyBag, a collection of Money that can then sum all values given a target currency and a CurrencyExchangeService (currency conversion rates should also be stored as BigDecimals).

Rounding should be done after every operation according to the number of desired decimal places and the rounding algorithm. The number of decimal places is normally a property of the Currency (look, e.g., at ISO 4217); unless a different number is desired (like when pricing gasoline, for example).

You should definitely look at Fowler's examples; but I've also created a very simple uni-currency Money class for an exercise. It uses dollars only and rounds to 2 decimal places; but it's still a good base for future extensions.

Jordão
  • 55,340
  • 13
  • 112
  • 144
  • Sometimes financial calculations take even more sophisticated approaches. E.g. a typical case is separating a an amount into n% and (100-n)% parts so that the sum of the parts is penny-perfect, despite rounding. – 9000 Mar 31 '12 at 20:38
  • @9000: Yes, Fowler described an allocation algorithm for that, look at PoEAA; I've also used it before with great success... – Jordão Mar 31 '12 at 20:42
  • @9000: I found the algorithm [here](http://books.google.ca/books?id=Jl5rkQnbfAIC&lpg=PA489&ots=gut4bQs6FR&dq=fowler%20money%20conundrum&pg=PA494#v=onepage&q&f=false) – Jordão Mar 31 '12 at 20:56
  • ^^Thats Jordao and 9000, I figured I would need to use just BigDecimal. – Wormhole99 Mar 31 '12 at 20:57
  • @Wormhole99: so, you have multiple currencies but still won't create a `Money` class? You should _strongly_ consider it. The abstraction will make your program easier to understand and maintain. – Jordão Mar 31 '12 at 20:59
  • ^^Okay I'll look into it. And thanks for posting up that algorithm. – Wormhole99 Mar 31 '12 at 22:13
1

Yes, BigDecimal is certainly the correct way (floating point almost never). Also in JDBC.

But having said that, there is an issue with rounding. In some cases 6 decimals are legally required in european software. In general you will want to round on 2 places in every step. If you have a quantity with 2 decimals and a price, you'll get 4 decimals, and have to round. So to make the ugly BigDecimal interface even uglier, you probably need some help functions (multiplyRounded?).

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138