1

It's been awhile since I've wrote applications that dealt with money. Many years ago, I would make a money object that dealt with Integers behind the scenes. Whenever the amount was printed somewhere, it would simply put the decimal place in the correct spot. This was to prevent decimal problems.

Do I still need to do this, or can I just use BigDecimal? What is considered the best practice right now?

egervari
  • 21,108
  • 30
  • 115
  • 171
  • 1
    Side note, but I've always been curious about this (never really had to deal with it yet): is `double` *actually unsafe* for money? I can't believe roundoff errors would ever happen at the cent level... would anyone mind sharing an example of a calculation in which `double`s would be dangerous? – user541686 Apr 24 '11 at 04:47
  • @Mehrdad Consider a situation where you have a decimal that can't be exactly represented with floating point. If this decimal was represented as the highest value less than the desired value, a comparison (`balance <= spendingCost` for instance) would fail when it should succeed,. – corsiKa Apr 24 '11 at 04:51
  • http://stackoverflow.com/questions/316727/is-a-double-really-unsuitable-for-money – sjr Apr 24 '11 at 04:51
  • 1
    @glowcoder: But then can't you just say `Math.abs(balance - spendingCost) <= EPSILON` or something like that? Or even better, for languages with operator overloading, just create a struct that holds a `double` and then overload all the comparison operators; then you wouldn't even have to worry about this outside of the `struct`. Do we really need a decimal-based number? – user541686 Apr 24 '11 at 04:51
  • @Mehrdad: I've only "popped" a double once... that was the total of the unimproved capital value column on a report, which overflowed when run on the whole state... Thank god the result was OBVIOUSLY wrong. – corlettk Apr 24 '11 at 04:54
  • @corlettk: Interesting, but an example of a situation that can't be alleviated with basic operator overloading (like I mentioned above) would be even better. :-) – user541686 Apr 24 '11 at 04:56
  • @Mehrdad You can, but over time those small errors will continue to grow. It is inevitable that it will eventually grow beyond whatever error you're accounting for. – corsiKa Apr 24 '11 at 04:57
  • @Mehrdad You could get around that by incorporating rounding into your assignment operators, but at that point it's the same as the BigDecimal class. – corsiKa Apr 24 '11 at 04:58
  • With enough money, double can't accurately represent whole dollars let alone cents. – MeBigFatGuy Apr 24 '11 at 04:58
  • @glowcoder: Why would the errors grow? If you round to 2 decimal places each time before storing the data, nothing will "grow" over time, right? Also, no, that wouldn't be a BigDecimal because it's not big, it's still only the size of a double. :) – user541686 Apr 24 '11 at 04:59
  • @Mehrdad: Using double is extremely unsafe for money. Even adding a bunch of numbers that contain decimals will result in the wrong value. This is not good :( I was curious if BigDecimal had the same problems or not. – egervari Apr 24 '11 at 04:59
  • @MeBigFatGuy: Huh? Mind giving an example? – user541686 Apr 24 '11 at 04:59
  • @Mehrdad You're right. It's not exactly the same. It has the same functionality with the same overhead but limitations of what you can do with it. That's not really a good tradeoff imo. – corsiKa Apr 24 '11 at 05:01
  • @glowcoder: So if you overload the comparison operators then there's no problems? Is that all there is to it? – user541686 Apr 24 '11 at 05:04
  • @Mehrdad No, there definitely are problems. You've limited your input range. You've limited your allowed precision. It does nothing but remove functionality from something that was created for the sole purpose of getting around those problems. By overloading these, you're essentially doing nothing but providing a BigDecimal class with a different implementation and more limitations. – corsiKa Apr 24 '11 at 05:11
  • @glowcoder: I think I'll post this as another question soon, I think it'll be an interesting discussion. Thanks for the info! :) – user541686 Apr 24 '11 at 05:12
  • 3
    @Mehrdad: I work in finance. Double is OK for a calculation like "what's the average price of this stock over the past month". But if we used double for accounting, we'd flunk any client due diligence test. Adding is bad, but subtracting is worse. Your idea of always rounding to two decimal places (except, of course, you forgot that mutual fund positions are rounded to 4 places, etc.) is really using a clumsy representation of a BigInteger shifted two places. This is a solved problem. Don't do accounting in floating point. – Andrew Lazarus Apr 24 '11 at 05:35
  • @Andrew: Please feel free to comment on/answer [my question](http://stackoverflow.com/questions/5768792/why-is-using-a-non-decimal-data-type-bad-for-money) if you have any *actual real-world examples*, I'd be happy to see some. :) – user541686 Apr 24 '11 at 05:37

1 Answers1

1

It depends on your requirements. You may only have a need for resolution to the nearest K (for example, salary requirements on a job posting website.)

Assuming you mean you need granularity, BigDecimal seems perfectly suited for the job. It seems certainly "safe" to use, but without knowing exactly what you plan to do with it, it's hard to say for certain.

corsiKa
  • 76,904
  • 22
  • 148
  • 194
  • Well, it's common knowledge that using a plain double will have simple math problems even with adding. This not acceptable. I was curious if you ran into the same problems with BigDecimal. It's not a big deal to use an int - I can. I don't care that much. But if I can simplify my code by just using a BigDecimal, I would actually like that. Saves time. – egervari Apr 24 '11 at 04:57
  • 1
    BigDecimal is provided for the sole purpose of avoiding "those problems" So like I said, in the general case yes I'd say it's fine. But it's possible you're doing something that BigDecimal isn't ready to handle. BigDecimal is fine for every money application I can think of off the top of my head. – corsiKa Apr 24 '11 at 04:59