round BigDecimal to nearest 5 cents

Viewed 29662

I'm trying to figure out how to round a monetary amount upwards to the nearest 5 cents. The following shows my expected results

1.03     => 1.05
1.051    => 1.10
1.05     => 1.05
1.900001 => 1.10

I need the result to be have a precision of 2 (as shown above).

Update

Following the advice below, the best I could do is this

    BigDecimal amount = new BigDecimal(990.49)

    // To round to the nearest .05, multiply by 20, round to the nearest integer, then divide by 20
   def result =  new BigDecimal(Math.ceil(amount.doubleValue() * 20) / 20)
   result.setScale(2, RoundingMode.HALF_UP)

I'm not convinced this is 100% kosher - I'm concerned precision could be lost when converting to and from doubles. However, it's the best I've come up with so far and seems to work.

11 Answers

I'd try multiplying by 20, rounding to the nearest integer, then dividing by 20. It's a hack, but should get you the right answer.

Based on your edit, another possible solution would be:

BigDecimal twenty = new BigDecimal(20);
BigDecimal amount = new BigDecimal(990.49)

// To round to the nearest .05, multiply by 20, round to the nearest integer, then divide by 20
BigDecimal result =  new BigDecimal(amount.multiply(twenty)
                                          .add(new BigDecimal("0.5"))
                                          .toBigInteger()).divide(twenty);

This has the advantage, of being guaranteed not to lose precision, although it could potentially be slower of course...

And the scala test log:

scala> var twenty = new java.math.BigDecimal(20) 
twenty: java.math.BigDecimal = 20

scala> var amount = new java.math.BigDecimal("990.49");
amount: java.math.BigDecimal = 990.49

scala> new BigDecimal(amount.multiply(twenty).add(new BigDecimal("0.5")).toBigInteger()).divide(twenty)
res31: java.math.BigDecimal = 990.5
public static void roundUp()
{
    try
    {
        System.out.println("Enter the currency : $");
        Scanner keyboard = new Scanner(System.in);
        String myint = keyboard.next();
        if (!isEmptyOrBlank(myint).booleanValue())
        {
            BigDecimal d = new BigDecimal(myint);
            System.out.println("Enter the round up factor: $");
            String roundUpFactor = keyboard.next();
            if (!isEmptyOrBlank(roundUpFactor).booleanValue())
            {
                BigDecimal scale = new BigDecimal(roundUpFactor);
                BigDecimal y = d.divide(scale, MathContext.DECIMAL128);
                BigDecimal q = y.setScale(0, 0);
                BigDecimal z = q.multiply(scale);
                System.out.println("Final price after rounding up to " + roundUpFactor + " is : $" + z);
                System.out.println("Want to try with other price Y/N :");

                String exit = keyboard.next();
                if ((!isEmptyOrBlank(exit).booleanValue()) && ("y".equalsIgnoreCase(exit))) {
                    roundUp();
                } else {
                    System.out.println("See you take care");
                }
            }
        }
        else
        {
            System.out.println("Please be serious u r dealing with critical Tx Pricing");
        }
    }
    catch (Exception e)
    {
        System.out.println("Please be serious u r dealing with critical Tx Pricing enter correct rounding off value");
    }
}

Tom has the right idea, but you need to use BigDecimal methods, since you ostensibly are using BigDecimal because your values are not amenable to a primitive datatype. Something like:

BigDecimal num = new BigDecimal(0.23);
BigDecimal twenty = new BigDecimal(20);
//Might want to use RoundingMode.UP instead,
//depending on desired behavior for negative values of num.
BigDecimal numTimesTwenty = num.multiply(twenty, new MathContext(0, RoundingMode.CEILING)); 
BigDecimal numRoundedUpToNearestFiveCents
  = numTimesTwenty.divide(twenty, new MathContext(2, RoundingMode.UNNECESSARY));

You can use plain double to do this.

double amount = 990.49;
double rounded = ((double) (long) (amount * 20 + 0.5)) / 20;

EDIT: for negative numbers you need to subtract 0.5

Related