Working in the financial industry, I have become rather strict about avoiding doubles in Java. The trouble is that they are a floating point representation of a number, which is just an approximation of the real value. This can lead to some unusual results.
For instance, according to this, 0.34 + 0.01 is not equal to 0.35.
double x = 0.35;
double y = 0.34 + 0.01;
System.out.println(x + " : " + y + " : " + (x == y));
0.35 : 0.35000000000000003 : false
Those inaccuracies might seem very small, but it’s surprisingly easy for them to start impacting a real world application. Imagine you wanted to sell dollars and buy Iranian Rial. You would be getting almost 20,000 Rial for every dollar. At that rate, imprecise floating point values could easily impact the final amount being sent. Although with the current US trade sanctions against Iran, that could be the least of your problems.
If you are running reports on a history of transactions, then a large number of smaller transactions can add up to large enough values that the imprecise doubles start affecting your totals. Even if you’re not dealing in huge numbers, things can go wrong easily enough. If your process takes a number through a sequence of multiplications or divisions, errors can be magnified. If you have a business rule to always round up, then according to our calculation above, 0.34 + 0.01 = 0.36.
However, that’s enough about why doubles are bad for financial calculations. What caught me by surprise was running accumulate functions in Drools. I was writing code to react to currency exposures being at particular limits, which were all being added up from nice healthy BigDecimal values. However, the numbers I was getting from the ‘sum’ accumulate function were not equal to the numbers my unit tests were expecting. A little investigation showed that the sum accumulator was converting all my nice fixed precision BigDecimal numbers into doubles. Oh dear…
So after a little further investigation, I established that there are no BigDecimal accumulators for Drools, and a bug has been open since 2008. The only workaround mentioned was to write your own ‘sumBigDecimal’ accumulator function.
This didn’t seem like great progress, but I thought it seemed like a good opportunity to learn a new corner of Drools, so I knocked together this BigDecimalAccumulator implementation:
I am a bit puzzled that I’m not finding examples of this all over the place, as Drools has seen a lot of uptake in the financial industry, and it seems like an obvious thing that anybody using Drools for financial rules and calculations would need. Maybe there are loads of private repositories out there, each with their own implementations?
Anyway, in the absence of BigDecimal accumulator functionality in core Drools, feel free to grab this for your own applications.