• Post Reply Bookmark Topic Watch Topic
  • New Topic

Best way to store money  RSS feed

 
Rick Beaver
Ranch Hand
Posts: 464
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi All

I know this topic is discussed in a lot of places but there are so many conflicting views I am not sure which method to go for.

I am working on an app that manages monthly credit repayments and need to find the best (most accurate) way to store monetary values.

The app will be carrying out a lot of calculations on the currency. For example, calculating monthly repayments from a total figure, converting values between currencies, working out interest, so the possibility of binary rounding errors when representing a decimal figure is quite high.

I am wondering what the current thinking / best practice is on storing monetary values. the most prevelant options, that I can see from previous topics, are:

1. Store as an int / long in the basic currency unit (pennies) and stick a dot in the right place purely for formatting purposes.
2. Store the value as a double and accept the rounding errors as they will be minor for most calculations.
3. Use the BigDecimal class to store the value - not sure what this does to rounding errors.

Any opinions on this? Or any other options that I have not considered?
 
Ben Wood
Ranch Hand
Posts: 342
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I personally like the sound of option 1. Seems the safest, and I wonder also if it will be faster when doing calculations as opposed to a double.
 
Jeroen Wenting
Ranch Hand
Posts: 5093
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You might want to roll your own currency class if you are concerned about rounding errors.
Use a long and a short to hold the integer and decimal parts.
Your operations on the data will probably be limited to addition, subtraction, multiplication, and division only so there's not all that much to implement there.

I've a feeling that BigDecimal may do something similar though so you might want to check the source for that one first

Whatever you do, NEVER round floating point numbers.
If you must display them use DecimalFormat to generate the string, but don't modify the number itself.
NEVER work with the rounded numbers as they polute the real ones which will increase rounding errors.
 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

Welcome to JavaRanch!

Do not do #2! An error of even a penny can be a disaster.

The best thing to do would be to write a Money class, and use instances of that class. Your initial implementation might do #1, but that would limit you to dealing with amounts less than about 20 million dollars. Better to go with #3. BigDecimal can represent decimal amounts exactly. Alternatively, you can do a modified #1 using longs, which gets you all the range you'll ever need. If you hide everything inside a Money class, you have the freedom to change your mind over time.
 
Rick Beaver
Ranch Hand
Posts: 464
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi All

Thanks for your replies.

So, 2 is out.

I think to start with I will try BigDecimal. It allows me to set the rounding mode which is very useful.

I will post here again when I have tried it out and let you know how it worked.

Thanks again
 
Julia Reynolds
Ranch Hand
Posts: 123
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Martin Fowler handles this very problem in his book
Patterns of Enterprise Architecture. On page 488 he includes a Money
pattern with a great Java class for handling currency.
It deals with rounding issues as well as incrementing and
allocating left over cents if money is distributed to various
destinations. Great book in general, also.

http://www.martinfowler.com/books.html#eaa

Julia
 
marc weber
Sheriff
Posts: 11343
Java Mac Safari
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
When using BigDecimal, be careful which constructors you use. For example, BigDecimal(double) can introduce error from the double. See the API for details.
 
Greg T Robertson
Ranch Hand
Posts: 91
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Speaking from experience in working with dollar amounts and currencies you want to either 1) roll your own or 2) use the BigDecimal. We are using BigDecimal with no problems but be sure you do not do conversions to/from double anywhere in your app or you are going to have issues.
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Never use a floating-point type (IEEE754 "an inexact representation of a real number") for monetary values.

Use an integral type.
http://www.xdweb.net/~dibblego/java/faq/answers.html#q41
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm reminded of a former math major and instructor who was confused about why

a / b * c != a * c / b

Of course in math the order doesn't matter, but in computers you lose precision (round) in division and the left expression multiplies the error. And the right one risks overflow. I guess my lesson from this is don't blindly trust the answers you get. Double check (through Test First unit tests!) that you get exactly what you expect.
 
David Harkness
Ranch Hand
Posts: 1646
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Nick Leaver:
Use the BigDecimal class to store the value - not sure what this does to rounding errors.
As you've already found in the JavaDocs, it has several methods for handling rounding. For a cooler method of handling rounding, I highly recommend the movie Office Space.

Joking aside, I'd stick your usage of BigDecimal behind a Money class that also encapsulates the handling of currency conversion and possibly split allocations as mentioned by Julia.
[ December 29, 2004: Message edited by: David Harkness ]
 
Rick Beaver
Ranch Hand
Posts: 464
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi All

Thanks for all your advice.

I am currently playing with the BigDecimal class using the String constructor to ensure I get the exact representation of the number.

Everything seems to work OK for simple calculations.

When I get on to the currency conversions, which will see the app attempting calculations on two BigDecimal values, I will post an update on how the app responded.

I can see potential exceptions with inexact amounts in the currency conversion, but I will cross that bridge when I come to it

Thanks again for all the advice.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!