15

I want to use BigDecimal to represent arbitrary precision numbers like prices and amounts in a low-latency trading application with thousands of orders and execution reports per second.

I won't be doing many math operations on them, so the question is not about performance of the BigDecimal per se, but rather about how large volumes of BigDecimal objects would affect performance of the application.

My concern is that huge amount of short-lived BigDecimal objects will put a strain on a GC and result in larger Stop-The-World pauses in CMS collector - and this is definitely what I would like to avoid.

Can you please confirm my concerns and suggest alternatives to using BigD? Also, if you think my concerns are wrong - please explain why.

Update:

Thanks for all who answered. I am now convinced that using BigDecimal will hurt latency of my application (even though I still plan to measure it).

For the time being we decided to stick with "very non-OOP" solution (but without accuracy hit) - use two ints, one for mantissa and another one for exponent. Rationale behind this is that primitives are placed on stack, not heap, and hence are not subject to garbage collection.

vtrubnikov
  • 2,045
  • 3
  • 14
  • 10

7 Answers7

15

If you are developing a low-latency trading program and you genuinely want to compete in latency terms, then BigDecimal is not for you, it is as simple as that. Where microseconds matter, object creation and any decimal math is just too expensive.

I would argue that for almost everyone else, using BigDecimal is a no-brainer because it will have little visible impact on application performance.

In latency-critical systems making trading decisions, any unpredictable garbage-collection pauses are completely out-of-the-question so whilst the current garbage-collection algos are fantastic in normal use, they are not necessarily appropriate when a delay of 5 milliseconds may cost you a lot of money. I would expect that large systems were written in a very non-OOP style, with little or no objects being used aside from some interned Strings (for codes and the like).

You'll certainly need to use double (or even float) and take the accuracy hit, or else use long and measure all amounts in cents, tenths of a cent or satoshis (whatever the smallest unit of account is).

Pr0methean
  • 303
  • 4
  • 14
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • If BidD is not for me, what is, then? I don't to use doubles (as it bring whole lot of new problems with floating point -numbers which I operate with are naturally decimals). – vtrubnikov Sep 04 '09 at 09:43
  • 2
    +1 for stating the key point about competing on performance. As in the joke about the tiger and the running shoes, absolute numbers rarely matters much, better than/worse than is what counts. – soru Sep 04 '09 at 09:53
  • @valery_la99 - I've added to my answer – oxbow_lakes Sep 04 '09 at 10:09
  • See https://github.com/subes/invesdwin-util#decimal for an alternative to working with Double directly by using a fluent API around it that is very fast since being designed for financial strategy backtesting. – subes Aug 03 '15 at 13:02
8

JVMs are pretty good nowadays in terms of handling the creation and destruction of short-lived objects, so that's not the worry it once was.

I would recommend building a mock-up of what you want to do, and measure it. That's going to be worth a lot more than any 'theoretical' answers that you may get :-)

Looking at your particular problem domain, similar systems I've worked on in the past work very well using doubles for the data you want to use BigDecimal for, and it may be worth re-examining your thinking in this area. A cursory glance at BigDecimal shows it has 5 or 6 fields, and the extra memory consumption over a single double may outweigh any functionality benefits you have.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • One of those fields is a `BigInteger` (and one of the fields of `BigInteger` is an `int[]`) (Sun implementation). – Tom Hawtin - tackline Sep 04 '09 at 09:16
  • 1
    Good point. I also noticed a String in there but I understand that's only populated during a toString() invocation – Brian Agnew Sep 04 '09 at 09:20
  • 2
    I find it hard to believe that a trading system based on doubles for amounts and prices could ever work at all, let alone very well. Correctness is hardly a "functionality benefit" that one should ever re-examine. – Michael Borgwardt Sep 04 '09 at 10:12
  • @Michael - most systems I've worked on will store notionals/quantities/cashflows etc. as doubles, without issues – Brian Agnew Sep 04 '09 at 10:14
  • I assume those systems analyse the data rather than actually performing the transactions. – Michael Borgwardt Sep 04 '09 at 10:23
  • 2
    +1 for "build and measure". Way too much gets written as though general tendencies apply to each and every situation. – CPerkins Sep 04 '09 at 12:43
  • 1
    Good comments. Doubles give you about 50 bits of precision (about 17 decimal places). If you need more than that, big integers probably work better than building it yourself. – Mike Dunlavey Sep 04 '09 at 13:44
5

BigDecimal does have performance very much lower than, say, long, double or even Long. Whether that will make a significant difference to your application's performance depends upon your application.

I suggest finding the slowest part of your application and doing a comparative test on that. Is it still fast enough? If not, you might want to write a small immutable class containing a single long, possibly checking for overflows.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
4

The big question is: do you actually need arbitrary precision decimal calculations? If the calculations are only done to analyze the data and make decisions based on that, then rounding and binary representation artifacts among the least significant bits are probably irrelevant to you; just go ahead and use double (and analyze your algorithms for numerical stability).

If you're actually doing transactions where the numbers have to add up and precision matters absolutely, then double is not an option. Perhaps you can separate these two parts of your app and use BigDecimal only in the transaction part.

If that is not possible, then you're pretty much out of luck. You'd need a BCD math library, and I don't think Java has one. You can try writing your own, but it will be a lot of work and the result may still not be competitive.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
2

why don't you use a long with an implied number of decimal cases? For example, let's say you have 8 decimal places implied, then 0.01 would be 1000000.

kms333
  • 3,147
  • 7
  • 31
  • 39
1

I'm not sure what are your requirements, but generally when doing financial calculation one cannot afford accuracy hit caused by floating point types. Usually accuracy and proper rounding is more important than efficiency when dealing with money.
If you don't have to deal with percentages and all of the amounts are integer, you can use integer types (int, long or even BigInteger) with one meaning 0.01 of your currency unit.
And even if you think you can afford accuracy hit with double type, it may be worth trying first with BigDecimal and checking if it's really to slow for you.

Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83
1

I work for a team that conducts performance assessments and optimizations on applications, had one application recently that was using Java Big Decimal. Significant performance issues were observed with memory utilization. We later switched to Newton Raphson which allowed us to keep up accuracy with calculations and shown significantly better performance to big decimal.

Just to add.. when we used doubles we saw a massive loss in accuracy as expected

DarkAjax
  • 15,955
  • 11
  • 53
  • 65
ryan
  • 11
  • 1