No matter how powerful a programming language is, due to the inherent problems in representing precision in a fixed number of bytes in computer memory, accurate calculations are not possible when using data types like 'double' in Java.
I am just summarizing the common mistakes people make when using doubles to do accurate calculations and of course a few solutions and/or things to keep in mind when coding with doubles.
Demonstrating the problem:
To aid with comparing using EPSILON, you might want to take a look at the MathUtils library from Apache instead of writing those utility methods yourself.
I am just summarizing the common mistakes people make when using doubles to do accurate calculations and of course a few solutions and/or things to keep in mind when coding with doubles.
Demonstrating the problem:
Let's take a simple usecase. Say you are writing an order management system, where you want to buy 10.6 shares of some product in total, and you need to check how many fills have already come in and place an order for the remaining quantity only if it is >= 0.1.. lame but.. simple problem..
A naive code will look like this..
A naive code will look like this..
double goal = 10.6; double fill1 = 3.3 + 7.2; double remaining = goal - fill1; System.out.println("Remaining Qty: " + remaining); if (remaining >= 0.1) { System.out.println("We have a problem, too many unfilled quantity"); } else { System.out.println("Incorrect Conclusion: Too few quantity remaining, so let's buy the remaining!"); }
If you run the above program, the output would be...
Problem is obvious from the output. The remaining quantity calculated is not exactly 0.1 as you might have guessed because of precision issues. So, the program ends up concluding that it doesn't have to do anything, but in fact it has to place more orders!
Some solutions and coding guidelines:
1. Use BigDecimal.
Remaining Qty: 0.09999999999999964
No Problem, too few quantity remaining
Problem is obvious from the output. The remaining quantity calculated is not exactly 0.1 as you might have guessed because of precision issues. So, the program ends up concluding that it doesn't have to do anything, but in fact it has to place more orders!
Some solutions and coding guidelines:
1. Use BigDecimal.
- Pros: Accurate
- Cons: Slow, may not be a great option in latency sensitive applications, depending on how many calculations you have.
3. Say, you still need a decimal point and cannot use integer or long for everything, then maintain a decimal point yourself. As of this writing, I don't know if there are any open source libraries that already do it for you.
4. Never compare decimal values directly, always...always use a EPSILON (a very small value that is relevant in your usecase)
E.g. Instead of remaining == 0.1, use Math.abs(remaining - 0.1) <= EPSILON
where EPSILON could be somethig like 10e-8
E.g. Instead of remaining == 0.1, use Math.abs(remaining - 0.1) <= EPSILON
where EPSILON could be somethig like 10e-8
To aid with comparing using EPSILON, you might want to take a look at the MathUtils library from Apache instead of writing those utility methods yourself.