Java example

How to round to 2 decimal places in Java

8 min read Updated Sep 2026 Runs in an isolated runtime
Quick answer

Use BigDecimal: BigDecimal.valueOf(x).setScale(2, RoundingMode.HALF_UP) turns 3.14159 into 3.14 and 1.005 into 1.01. If you only need text, String.format(Locale.ROOT, "%.2f", x) returns the string "3.14". The shorter Math.round(x * 100.0) / 100.0 works for most values but gives 1.0 for 1.005.

Java has no round(x, 2). Math.round rounds to a whole long, and a double is a binary fraction that can't hold most two-decimal values exactly. So the answer depends on what you need back: an exact decimal you keep calculating with (BigDecimal), a double that is close enough (Math.round), or a string for a screen or a report (String.format and DecimalFormat). The other decision is the rounding rule, because Java's tools don't all agree on what happens to a 5. Each example runs on this page: hit Run, then edit the code and run it again.

1BigDecimal.setScale(2, RoundingMode.HALF_UP)Recommended

BigDecimal stores a number as decimal digits plus a scale (the count of digits after the point), so setScale(2, mode) means "exactly two decimals, rounded with this rule". RoundingMode.HALF_UP is the rule taught at school: a tie goes away from zero. How you build the BigDecimal matters as much as how you round it. Use BigDecimal.valueOf(double) or the String constructor, never new BigDecimal(double).

Main.java

Output

Prints 3.14, 1.01, 2.68, 7.00 and -1.01, then 20.00 for the string "19.995". setScale pads as well as rounds, so 7 comes back as 7.00. The trap lines show why the constructor matters: new BigDecimal(2.675) prints 2.67499999999999982236431605997495353221893310546875, the exact value of the stored double, so it rounds down to 2.67. BigDecimal.valueOf(2.675) goes through Double.toString and gets 2.675. The last line, 4.140000000000001, is what happens when you convert back to double and keep calculating: the binary error returns. Keep money in BigDecimal until you display it. And BigDecimal is immutable, so price.setScale(2, RoundingMode.HALF_UP); on its own line does nothing: use the returned value.

2Math.round(x * 100.0) / 100.0 and its trap

The classic one-liner scales the value so the two decimals you keep sit in front of the point, rounds to a whole number, and scales back. It returns a double and needs no imports, which is why it is the most copied answer. It also inherits every floating-point quirk of the value you pass in, and has two traps of its own.

Main.java

Output

Prints 3.14, 2.5 and 7.0: a double has no idea how many decimals you meant to show, so there is no padding. Then 1.0 where you wanted 1.01, and the next line shows why: 1.005 * 100.0 is 100.49999999999999, which Math.round correctly rounds down. -1.12 -2 shows that Math.round sends ties toward positive infinity, so -1.125 becomes -1.12 rather than -1.13. Dividing by the int 100 instead of 100.0 gives 3, because a long divided by an int is integer division. Finally, Math.round returns a long that stops at Long.MAX_VALUE, so 1e17 comes back as 9.223372036854776E16. It is fine for quick calculations on everyday values; use BigDecimal when exact ties matter.

3String.format("%.2f") for display

When the result is text, format it directly. %.2f rounds and pads to exactly two decimals and returns a String. Always pass a Locale as the first argument: without one, Java uses the machine's default locale, and in much of Europe that prints a comma as the decimal separator. Locale.ROOT gives the neutral format for files, logs and APIs; a user's locale is right for text shown to that user.

Main.java

Output

Prints 1234.57 with Locale.ROOT and 1234,57 with Locale.GERMANY; adding the , flag groups thousands as 1,234.57 or 1.234,57. 7.0 is padded to 7.00, and 7.001 is the usual string bug: + 1 on a String concatenates. The rounding line prints 1.01 2.68 0.13. The formatter rounds HALF_UP from the digits Double.toString would print, so it rounds 1.005 the way a person expects, unlike Math.round. "%.2f".formatted(x) (Java 15+) prints 3.14 but has no Locale parameter, so it follows the default locale. The printf line right-aligns 20.00 in 8 characters after Total:.

4DecimalFormat: "0.00" vs "#.##"

java.text.DecimalFormat formats with a pattern, and the pattern answers the "no unnecessary zeros" question. A 0 is a digit that is always shown, and a # is a digit shown only when it isn't a trailing zero. So "0.00" means exactly two decimals and "#.##" means at most two. Pass DecimalFormatSymbols for a fixed locale, and watch the default rounding mode: it is HALF_EVEN, not HALF_UP.

Main.java

Output

The loop prints 3.14 3.14, 2.50 2.5, 7.00 7 and 0.50 0.5: "0.00" on the left, "#.##" on the right. "#,##0.00" adds grouping, giving 1,234,567.89 with US symbols and 1.234.567,89 with German ones. 0.12 0.38 is HALF_EVEN at work: 0.125 and 0.375 are exact in binary, so they are real ties, and each goes to the even neighbour. After setRoundingMode(RoundingMode.HALF_UP) the first becomes 0.13. The last line is 1.00: DecimalFormat rounds the exact binary value of the double, which is just under 1.005, so it disagrees with String.format. A DecimalFormat is also not thread-safe, so don't share one instance between threads.

5RoundingMode: HALF_UP vs HALF_EVEN and the rest

java.math.RoundingMode has eight constants, and setScale, divide and DecimalFormat all take one. The three HALF_ modes differ only on an exact tie; the other four ignore ties and always go one way. Building the values from strings keeps 2.345 a genuine tie, so the table below shows each rule with no binary noise.

Main.java

Output

On the tie 2.345, HALF_UP gives 2.35 while HALF_EVEN and HALF_DOWN give 2.34. On 2.355, HALF_EVEN goes up to 2.36, because 6 is the even neighbour. That is banker's rounding: over many values the ups and downs cancel out, which is why accounting and DecimalFormat use it. UP and DOWN mean away from and toward zero, so DOWN truncates. CEILING and FLOOR mean toward positive and negative infinity, which is why they split on -2.345 (-2.34 and -2.35). UNNECESSARY passes 2.50 through and throws ArithmeticException: Rounding necessary for 2.345. So does setScale(2) with no mode at all.

6BigDecimal.divide and trailing zeros

Two BigDecimal follow-ups catch almost everyone. First, divide(other) with no scale must return the exact quotient, and 10 / 3 has no exact decimal form, so it throws. Give it a scale and a rounding mode, which also rounds the result to two decimals in one step. Second, stripTrailingZeros() removes zeros after the point, but its result can print in scientific notation unless you call toPlainString().

Main.java

Output

The first line is the famous error: ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. With a scale, divide(people, 2, RoundingMode.HALF_UP) gives 3.33; MathContext.DECIMAL64 asks for 16 significant digits instead and gives 3.333333333333333. An exact quotient needs no scale: 10.00 / 4 is 2.50. stripTrailingZeros turns 2.50 into 2.5, but 100.00 into 1E+2; toPlainString() gives 100. The same pair prints a double without the pointless .0: 232.0 -> 232, 0.18 -> 0.18 and 1.0E10 -> 10000000000. The last line, false true, is why you compare BigDecimal values with compareTo: equals also compares the scale, so 2.5 and 2.50 are not equal.

7Which should you use?

MethodReturns1.005 givesBest for
BigDecimal.valueOf(x).setScale(2, RoundingMode.HALF_UP)BigDecimal1.01Money and anything you keep calculating with
new BigDecimal(x).setScale(2, RoundingMode.HALF_UP)BigDecimal1.00Never with a double: use valueOf or a String
Math.round(x * 100.0) / 100.0double1.0Quick rounding where exact ties don’t matter
String.format(Locale.ROOT, "%.2f", x)String"1.01"Always two decimals, for display or output
new DecimalFormat("0.00") / "#.##"String"1.00" / "1"Patterns, grouping, no trailing zeros
stripTrailingZeros().toPlainString()Stringn/aPrinting a value without trailing zeros

Frequently asked questions

How do I round a double to 2 decimal places in Java?

Use BigDecimal.valueOf(x).setScale(2, RoundingMode.HALF_UP), which turns 1.005 into 1.01 and pads 7 to 7.00. Call .doubleValue() on the result if you need a double back. The one-liner Math.round(x * 100.0) / 100.0 is fine for most values, but because 1.005 * 100.0 is 100.49999999999999, it returns 1.0 for 1.005.

Why does new BigDecimal(0.1) print 0.1000000000000000055511151231257827021181583404541015625?

Because new BigDecimal(double) converts the exact binary value of the double, and 0.1 cannot be stored exactly in binary. BigDecimal.valueOf(0.1) goes through Double.toString first and gives 0.1, and new BigDecimal("0.1") is exact by construction. Use one of those two; with the double constructor, 2.675 rounds to 2.67 instead of 2.68.

How do I fix "ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result"?

Give BigDecimal.divide a scale and a rounding mode. new BigDecimal("10.00").divide(new BigDecimal("3")) throws because 10 / 3 has no exact decimal form, while divide(divisor, 2, RoundingMode.HALF_UP) returns 3.33. To keep a number of significant digits instead of decimal places, pass a MathContext such as MathContext.DECIMAL64, which gives 3.333333333333333.

How do I format a double without unnecessary trailing zeros?

Use BigDecimal.valueOf(d).stripTrailingZeros().toPlainString(): 232.0 prints as 232 and 1.0E10 as 10000000000. Skip toPlainString() and a value like 100.00 prints as 1E+2. If you also want to cap the decimals, new DecimalFormat("#.##") shows at most two and drops trailing zeros, so 2.5 stays 2.5 and 7 stays 7.

Why does String.format("%.2f") print a comma instead of a dot?

Because String.format without a Locale uses the default locale, and many locales use a comma as the decimal separator. Pass one explicitly: String.format(Locale.ROOT, "%.2f", 1234.5678) gives 1234.57, while Locale.GERMANY gives 1234,57. DecimalFormat has the same issue; construct it with DecimalFormatSymbols.getInstance(Locale.US) or another fixed locale.

What is the difference between setScale and round(MathContext) on a BigDecimal?

setScale counts decimal places and round(MathContext) counts significant digits. For 1234.5678, setScale(2, RoundingMode.HALF_UP) gives 1234.57, round(new MathContext(6)) gives the same 1234.57, but round(new MathContext(2)) gives 1.2E+3. To round to 2 decimal places, use setScale.

Run it yourself

Open any of these in the full Java editor to tweak, run and share.

Java playground