Win a copy of The Java Performance Companion this week in the Performance forum!

# Rounding Doubles to Two Decimal Places

David Dickinson
Ranch Hand
Posts: 66
Hi All,

I've searched the archive and found a few different posts regarding restricting the number of decimal places in doubles. However they all suggest different methods, BigDecimal, NumberFormat etc.

Which is the simplest method of rounding a number say 10.023445656 to 10.02?

Thanks

Mike Gershman
Ranch Hand
Posts: 1272

Joyce Lee
Ranch Hand
Posts: 1392
Hi David,

Joyce

Peter Chase
Ranch Hand
Posts: 1970
Originally posted by Joyce Lee:

No, that's not a good way to do it. The reason is that floating-point arithmetic ("double" is a floating-point type) is not exact. So you're quite likely to end up printing something like 10.020000000000001 or 10.0199999999999 .

NumberFormat is probably the way to go. Alternatively, you could switch to using integers, where arithmetic is exact. Obviously, that would involve rescaling your values, as you can't have fractions.

Currency calculations are an example. Beginners often do currency calculations in floating-point, because they work in dollars, pounds or euros, which have a fractional part - the number of cents or pence. Instead, such calculations should be done in cents or pence, by integers. When printing out, use the divide (/100) and modulus (%100) integer operations to get the number of dollars/pounds/euros and cents/pence respectively.

HTH

David Dickinson
Ranch Hand
Posts: 66
Hi,

Is there no way to round the double but keep the the value stored as a double?

I'm running JUnit tests and want to compare the computed result with the result I have calculated manually which is stored to two decimal points?

Thanks

Mike Gershman
Ranch Hand
Posts: 1272
why not "Math.abs( myValue - yourValue ) <= 0.005"?

David Dickinson
Ranch Hand
Posts: 66
If I can't find a more elegant solution to the problem then thats an option Mike.

This doesn't seem like a big problem to me surely Java has some function which automatically rounds a number when a precision of 2 is required?

Thanks all, hopefully i'll get a solution soon

Joyce Lee
Ranch Hand
Posts: 1392
Originally posted by Peter Chase:

No, that's not a good way to do it. The reason is that floating-point arithmetic ("double" is a floating-point type) is not exact. So you're quite likely to end up printing something like 10.020000000000001 or 10.0199999999999 .

Peter, I printed the output using the Math.round approach. But it didn't end up printing like 10.020000000000001 or 10.0199999999999. I may have missed out something. Could you give a value that would end up something like that? Thanks.

Mike Gershman
Ranch Hand
Posts: 1272
You could do this:

I should warn you that the result may be inexact by one or two low-order bits.

Layne Lund
Ranch Hand
Posts: 3061
Since you are using JUnit, there is no reason to round. Instead, you should use Assert.assertEquals(double expected, double actual, double precision) to compare the two numbers. The last parameter indicates the accuracy of your comparison. For example, you can do something like

To assert that your calculated value is within 1/100 th of the manually derived value.

For more details about the methods available in the Assert class (and other JUnit classes, you should consult the JUnit javadocs. They come with the JUnit distribution.

HTH

Layne
[ November 19, 2004: Message edited by: Layne Lund ]

Layne Lund
Ranch Hand
Posts: 3061
Originally posted by Joyce Lee:

Peter, I printed the output using the Math.round approach. But it didn't end up printing like 10.020000000000001 or 10.0199999999999. I may have missed out something. Could you give a value that would end up something like that? Thanks.

I think this was an illustrative example. Results can vary between machines. The point is that floating point arithmetic is not exact because of the limitations of storing fractions in a computer. This is very analogous to writing one-third (1/3) as a decimal. Depending on how accurate you want to be, this fraction can be written as 0.33 or 0.3333, but no matter what you do, there is no exact decimal equivalent to 1/3. Similar situations arise with floating point numbers stored in binary. I won't get into the details here because it has been discussed several times before. If you are interested in the details, you can use the Saloon's search tool or google for more information.

Layne

David Dickinson
Ranch Hand
Posts: 66
Layne,

Indeed your right I have always set my Delta (the allowable difference between the two numbers under evaluation) to 0 to ensure accuracy. But this would be the simplest way of doing things.

That old saying "I can't see for things for looking at them" springs to mind

Thank you!

Joyce Lee
Ranch Hand
Posts: 1392
I still don't get the idea why using Math.round approach would end up 10.020000000000001 or 10.0199999999999. I did a quick search in this forum. Here are the threads that recommended using Math.round approach to round off to 2 decimal places. Did I miss out anything?

Layne Lund
Ranch Hand
Posts: 3061
Originally posted by David Dickinson:
Layne,

Indeed your right I have always set my Delta (the allowable difference between the two numbers under evaluation) to 0 to ensure accuracy. But this would be the simplest way of doing things.

That old saying "I can't see for things for looking at them" springs to mind

Thank you!

As you probably see, you shouldn't rely on comparing doubles for equalit (which is essentially the same as setting your delta to 0.0 in this case). The reasons are related to another reply I will post next, so stay tuned.

Layne

Layne Lund
Ranch Hand
Posts: 3061
Originally posted by Joyce Lee:
I still don't get the idea why using Math.round approach would end up 10.020000000000001 or 10.0199999999999. I did a quick search in this forum. Here are the threads that recommended using Math.round approach to round off to 2 decimal places. Did I miss out anything?

The problem isn't with Math.round(); it's with doing arithmetic on the result that is returned from this method! The problem here stems from how most modern computers store floating point numbers (double is a floating-point number). This thread gives a basic explanation of the issues involved here. For more technical details, you need to look at the IEEE standard that is mentioned in the last message of the thread. (Take a look here for more information about IEEE 754 standard. Although it doesn't give details about the issues discussed here, the concpets discussed are necessary to understand the implications of floating-point arithmetic.)

HTH

Layne
[ November 19, 2004: Message edited by: Layne Lund ]

Joyce Lee
Ranch Hand
Posts: 1392
Originally posted by Layne Lund:

The problem isn't with Math.round(); it's with doing arithmetic on the result that is returned from this method!

I wasn't talking about Math.round(). I was referring to Math.round approach, meaning Math.round(100 * x) / 100d as a whole.

I would appreciate if someone could give a value of x that would result in something like this 10.020000000000001 instead of two decimal places using the formula above. I tested it on Window platform. I couldn't reproduce this problem as claimed. Thanks.
[ November 19, 2004: Message edited by: Joyce Lee ]