Angelo Immediata
Angelo Immediata

Reputation: 6954

Commons-math rounding double

I'm using commons-math 3.6.1.

I need to round a double value to 2 decimal

Let's assume this is my double value:

double d = 400.54540997260267;

Now by rounding this number I was expecting as result 400.54

Instead if my number was double d1 = 400.54640997260267; I was expecting as result 400.55

Now I'm using this code:

Precision.round(d, 2, BigDecimal.ROUND_DOWN);

If I use as roundingMethod BigDecimal.ROUND_DOWN I always get the lowest rounding. Which kind of rounding method should I use in order to get what I was expecting?

I tried the following code:

public class TestCalcoli

    {
        private static final Logger logger = LoggerFactory.getLogger(TestCalcoli.class.getName());
        private void calc(double d)
        {
            double result = Precision.round(d, 2, BigDecimal.ROUND_HALF_DOWN);
            double result2 = Precision.round(d, 2, BigDecimal.ROUND_HALF_UP);
            logger.info("d--> "+d+" result --> "+result+" result2 --> "+result2);
        }
        @Test
        public void calcola()
        {
            try
            {
                double d = 400.54540997260267;
                double d1 = 400.54640997260267;
                calc(d1);
                calc(d);
            }
            catch (Exception e)
            {
                logger.error("errore", e);
            }
        }
    }

CONSOLE OUTPUT:

2017-07-31 09:29:44,608 317  [main] INFO  i.e.c.r.pwb.test.TestCalcoli - d--> 400.54640997260265 result --> 400.55 result2 --> 400.55
2017-07-31 09:29:44,612 321  [main] INFO  i.e.c.r.pwb.test.TestCalcoli - d--> 400.54540997260267 result --> 400.55 result2 --> 400.55

Upvotes: 6

Views: 3559

Answers (3)

Brent Worden
Brent Worden

Reputation: 10994

Here are the available rounding methods suitable for your problem and their respective output for the two values:

Method             400.54540997260267    400.54640997260267
---------------    ------------------    ------------------
ROUND_CEILING      400.55                400.55
ROUND_DOWN         400.54                400.54
ROUND_FLOOR        400.54                400.54
ROUND_HALF_DOWN    400.55                400.55
ROUND_HALF_EVEN    400.55                400.55
ROUND_HALF_UP      400.55                400.55
ROUND_UP           400.55                400.55

None of the methods provide the results you expect.

The reason for this is because the two neighbors of 400.54540997260267 and 400.54640997260267 are 400.54 and 400.55. These neighbors are not equidistant from 400.54540997260267 or 400.54640997260267. Therefore, the HALF rounding methods always round to the nearest neighbor which in both cases is 400.55.

Borrowing from xenteros' answer, the desired results can be achieved using two rounding operations in succession. First round down with an extra digit of precision and then do the desired rounding with the desired precision:

double truncated = Precision.round(input, 3, BigDecimal.ROUND_FLOOR);
double rounded = Precision.round(truncated, 2, BigDecimal.ROUND_HALF_DOWN);

Upvotes: 4

xenteros
xenteros

Reputation: 15862

The easiest way to achieve what you want is to perform the following operations:

double d = 400.54540997260267;
Double temp = 1000*d;
temp = 1.0*temp.intValue()/1000;
Precision.round(temp, 2, BigDecimal.HALF_DOWN);

It removes digits from 4th decimal and then performs your desired rounding.

Upvotes: 1

milbrandt
milbrandt

Reputation: 1486

You should use HALF_UP if you want to round up for same distance, i.e. digit 5.

Upvotes: 6

Related Questions