106

I need the following results

100.12 -> 100.00
100.44 -> 100.00
100.50 -> 101.00
100.75 -> 101.00

.round() or .setScale() ? How do I go about this?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
n a
  • 2,692
  • 8
  • 29
  • 39

7 Answers7

188

You can use setScale() to reduce the number of fractional digits to zero. Assuming value holds the value to be rounded:

BigDecimal scaled = value.setScale(0, RoundingMode.HALF_UP);
System.out.println(value + " -> " + scaled);

Using round() is a bit more involved as it requires you to specify the number of digits to be retained. In your examples this would be 3, but this is not valid for all values:

BigDecimal rounded = value.round(new MathContext(3, RoundingMode.HALF_UP));
System.out.println(value + " -> " + rounded);

(Note that BigDecimal objects are immutable; both setScale and round will return a new object.)

Grodriguez
  • 21,501
  • 10
  • 63
  • 107
  • 1
    It's not working: 100.12 : 100.12, 100.44 : 100.44, 100.50 : 100.5, 100.75 : 100.75 – Boris Pavlović Nov 09 '10 at 13:30
  • 3
    No, setting scale returns a new decimal that isn't same as the first. For example:`BigDecimal bd1 = new BigDecimal(100.12); BigDecimal bd2 = bd1.setScale(0, RoundingMode.HALF_UP); System.out.println(bd1.equals(bd2));` prints false – Daniel Fath Nov 09 '10 at 13:44
  • 6
    @Daniel: That was already implied in the code snippet I posted in my answer. I've now made it explicit. – Grodriguez Nov 09 '10 at 14:00
  • `RoundingMode` what is that? It's `BigDecimal` – trilogy Nov 09 '18 at 14:44
  • https://docs.oracle.com/javase/9/docs/api/java/math/BigDecimal.html#setScale-int-java.math.RoundingMode- – Grodriguez Nov 12 '18 at 09:27
16

If i go by Grodriguez's answer

System.out.println("" + value);
value = value.setScale(0, BigDecimal.ROUND_HALF_UP);
System.out.println("" + value);

This is the output

100.23 -> 100
100.77 -> 101

Which isn't quite what i want, so i ended up doing this..

System.out.println("" + value);
value = value.setScale(0, BigDecimal.ROUND_HALF_UP);
value = value.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("" + value);

This is what i get

100.23 -> 100.00
100.77 -> 101.00

This solves my problem for now .. : ) Thank you all.

n a
  • 2,692
  • 8
  • 29
  • 39
  • 9
    I am curious about the statement that the first result "isn't quite what I want...". If you are actually concerned about output formatting, you can use `DecimalFormat` (as in `new DecimalFormat("###.00")` ) to manage the conversion of a `BigDecimal` back to string. It gives `"101.00"` as the result for both values that the snippets from @Grodriquez and you created. – joel.neely Apr 19 '16 at 11:35
  • 4
    The second time you are rounding here is unnecessary as you know you have an integer already, so I would use BigDecimal.ROUND_UNNECESSARY instead, a bit more clear in my opinion. – kosmoplan Apr 05 '17 at 12:39
5

Here's an awfully complicated solution, but it works:

public static BigDecimal roundBigDecimal(final BigDecimal input){
    return input.round(
        new MathContext(
            input.toBigInteger().toString().length(),
            RoundingMode.HALF_UP
        )
    );
}

Test Code:

List<BigDecimal> bigDecimals =
    Arrays.asList(new BigDecimal("100.12"),
        new BigDecimal("100.44"),
        new BigDecimal("100.50"),
        new BigDecimal("100.75"));
for(final BigDecimal bd : bigDecimals){
    System.out.println(roundBigDecimal(bd).toPlainString());
}

Output:

100
100
101
101

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • Not to endorse this solution or anything, but the `input.toBigInteger().toString().length()` part would be much more efficient by using a logarithm, some thing like `round_up(log(input)) + (1 if input is a power of ten, else 0)` – Addison May 21 '19 at 16:27
  • BigDecimal seems like a steaming heap. – MarkHu Sep 17 '21 at 20:50
3

Simply look at:

http://download.oracle.com/javase/6/docs/api/java/math/BigDecimal.html#ROUND_HALF_UP

and:

setScale(int precision, int roundingMode)

Or if using Java 6, then

http://download.oracle.com/javase/6/docs/api/java/math/RoundingMode.html#HALF_UP

http://download.oracle.com/javase/6/docs/api/java/math/MathContext.html

and either:

setScale(int precision, RoundingMode mode);
round(MathContext mc);
toolkit
  • 49,809
  • 17
  • 109
  • 135
0

I don't think you can round it like that in a single command. Try

    ArrayList<BigDecimal> list = new ArrayList<BigDecimal>();
    list.add(new BigDecimal("100.12"));
    list.add(new BigDecimal("100.44"));
    list.add(new BigDecimal("100.50"));
    list.add(new BigDecimal("100.75"));

    for (BigDecimal bd : list){
        System.out.println(bd+" -> "+bd.setScale(0,RoundingMode.HALF_UP).setScale(2));
    }

Output:
100.12 -> 100.00
100.44 -> 100.00
100.50 -> 101.00
100.75 -> 101.00

I tested for the rest of your examples and it returns the wanted values, but I don't guarantee its correctness.

Daniel Fath
  • 16,453
  • 7
  • 47
  • 82
0

If neither .round() nor .setScale() seem intuitive to you, you can use this code to round to any integer steps of precision (e.g. round in 10s, 25s, 50s, 100s, ...).

Usage:

int distance = roundN(_distance, 5);

Declaration:

public static BigDecimal roundN(BigDecimal num, int precision){
    BigDecimal remainder = num.remainder(BigDecimal.valueOf(precision));
    System.out.println("remainder: " + remainder);

    if (remainder.compareTo(BigDecimal.valueOf((precision / 2))) < 0 ){
        System.out.println("round down");
        return num.subtract(remainder);
    } else {
        BigDecimal neg = remainder.negate().add(BigDecimal.valueOf(precision));
        System.out.println("round up");
        return num.add(neg);
    }
}

Trailing .00 can be appended to the result on demand.

kaiya
  • 271
  • 1
  • 3
  • 16
-2

You want

round(new MathContext(0));  // or perhaps another math context with rounding mode HALF_UP
jacobm
  • 13,790
  • 1
  • 25
  • 27
  • 3
    This does nothing. From the documentation of `round`: "If the precision setting is 0 then no rounding takes place." – Grodriguez Nov 09 '10 at 13:57