Eric Bruno

Dr. Dobb's Bloggers

Java's Floating-Point (Im)Precision

July 24, 2014

Java doesn't store, calculate, or return the exact representation of the actual floating-point value in some cases.

I was working with someone recently who told me he was having intermittent issues dealing with double floating-point values in Java. When he added and subtracted dollar amounts in this financial application, using the Java primitive type double, he would sometimes get unexpected results. For example, the following code shows a sample of some calculations he found troubling (other combinations of values worked fine):

At the end of this operation, he expected the value 3139.62, but instead was getting 3139.6200000000536. When formatted for display as a dollar amount, it was appearing as expected: "$3139.62." However, when he later inspected the database where he stored results, he noticed the issue. The trouble only came to light when he started seeing "$-0.00" after formatting for currency display. A quick look at the database showed the actual value as -0.000000000053518078857450746. What was going on to cause this, and how could it be fixed?

The problem derives from how float and double floating-point values are stored internally by the JVM. Unlike int and long (and other fixed-point types) that are stored as exact binary representations of the numbers they're assigned to, shortcuts are taken with float and double. Internally, Java stores values for these types with an inexact representation, using only a portion of the 64 bits for the significant digits. As a result, Java doesn't store, calculate, or return the exact representation of the actual floating-point value in some cases. This seemingly intermittent behavior can be annoying, as it only becomes apparent with specific combinations of numbers and operations.

BigDecimal to the Rescue

Fortunately, Java provides a math package, java.math.*, which includes the BigDecimal class. BigDecimal can be used to alleviate the rounding and loss of precision issues that are often seen with double floating-point arithmetic. BigDecimal allows you to specify precisely how the rounding behavior should work using the java.math.MathContext class. The number of digits to be returned can be specified with this object as well. Let's look at some examples:

Above, you see how the constructor allows you to specify the precision used to store and work with the floating-point value. Let's look at how to specify rounding, which must occur when the exact value cannot be represented with the precision used. First, note that the scale of the BigDecimal floating-point value indicates the number of digits to the right of the right of the decimal point.

Remember that the BigDecimal class is immutable, and simply calling a method on a BigDecimal object will have no affect, so you need to reassign it after every call. Let's revisit the first example showing the set of floating-point operations that yielded unexpected results, but modified to use BigDecimal properly:

In this case, the precision is set to 64 bits, and the scale is set to 2 to adequately represent currency values. Additionally, the results of calls to add and subtract are reassigned to the original BigDecimal object because it's immutable. I avoid the verbose code (and the typing required) to set the precision and scale, and instead use helper methods, such as:

Although there are many, many more details involved and other options when using BigDecimal and MathContext (and the java.math package for that matter), I hope this quick overview helps if you ever get bit by Java's binary representation of floating-point and double floating-point numbers and arithmetic operations.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!