6

I'm tinkering with BigDecimal and currency formatting in Android, and was wondering if it was possible to do the following using BigDecimal:

What I desire:

  64.99 --> 65.00 (Rounded Up)
  64.99 --> 60.00 (Rounded Down)
  65.01 --> 70.00 (Rounded Up)
  65.01 --> 65.00 (Rounded Down)

At present, with my code below, I'm only able to round to zeros. For example:

What I get:

  64.99 --> 70.00 (Rounded Up)
  64.99 --> 60.00 (Rounded Down)
  65.01 --> 70.00 (Rounded Up)
  65.01 --> 60.00 (Rounded Down)

Is there a way using BigDecimal to achieve what I desire?

My code:

private static void printRoundedValues() {
    NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
    BigDecimal valueUp = new BigDecimal(64.50, new MathContext(1,RoundingMode.UP));
    BigDecimal valueDown = new BigDecimal(64.50, new MathContext(1,RoundingMode.DOWN)); 

    System.out.println("Value Up: " +  currencyFormat.format(valueUp));
    System.out.println("Value Down: " +  currencyFormat.format(valueDown));
}
TN888
  • 7,659
  • 9
  • 48
  • 84
TEK
  • 1,265
  • 1
  • 15
  • 30

3 Answers3

4

You can multiply by 2, then round to the nearest 10, then divide by 2. The precision is 2 for these BigDecimals; it may need to be different for BigDecimals of different scale.

BigDecimal[] bds = {new BigDecimal("64.99"), new BigDecimal("65.01")};
BigDecimal two = new BigDecimal("2");
MathContext mcUp = new MathContext(2, RoundingMode.UP);
MathContext mcDown = new MathContext(2, RoundingMode.DOWN);
NumberFormat currency = NumberFormat.getCurrencyInstance();
for (BigDecimal bd : bds)
{
    System.out.println("Test: " + bd);
    BigDecimal roundUp5 = bd.multiply(two).round(mcUp).divide(two);
    System.out.println("Round up: " + currency.format(roundUp5));
    BigDecimal roundDown5 = bd.multiply(two).round(mcDown).divide(two);
    System.out.println("Round down: " + currency.format(roundDown5));
}

Output:

Test: 64.99
Round up: $65.00
Round down: $60.00
Test: 65.01
Round up: $70.00
Round down: $65.00
rgettman
  • 176,041
  • 30
  • 275
  • 357
  • 2
    And never use a `new BigDecimal(65.99)` but `new BigDecimal("65.99")`. Doubles are an approximation, a sum of (negative) powers of 2. And with a String the precision is known for BigDecimal. – Joop Eggen Feb 19 '14 at 17:20
  • This is a nice solution plus it gives sensible values. Thank you. @JoopEggen thank you for the tip, that actually saves me some cycles as I was parsing to float then creating a BigDecimal, now I can just pass in the string. – TEK Feb 19 '14 at 17:27
0
    NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
    BigDecimal valueUp = new BigDecimal(64.50, new MathContext(2, RoundingMode.UP));
    BigDecimal valueDown = new BigDecimal(64.50, new MathContext(2, RoundingMode.DOWN));

    System.out.println("Value Up: " +  currencyFormat.format(valueUp));
    System.out.println("Value Down: " +  currencyFormat.format(valueDown));

Here is how MathContext precision works:

  • creates a value (64.5)
  • set the precision to given value (2) which results in 64.5
  • round this value using given RoundingMode (UP), which gives you the value of 65

You probably need to set scale rather than precision:

    BigDecimal valueUp = new BigDecimal(64.50).setScale(0, RoundingMode.UP);
    BigDecimal valueDown = new BigDecimal(64.50).setScale(0, RoundingMode.DOWN);
0

The function you are looking for is setScale and is part of BigDecimal.

Here is a good answer to the same question: Java BigDecimal: Round to the nearest whole value

Community
  • 1
  • 1
Raanan
  • 4,777
  • 27
  • 47