Question
How to Round to N Decimal Places in Java with Half-Up and No Trailing Zeros
Question
I want a Java method that converts a double to a String using half-up rounding. In other words, when the next digit is 5, it should always round up, which is the rounding behavior most people expect.
I also want the output to show only significant decimal digits, so there should be no trailing zeros.
For example, using String.format:
String.format("%.5f", 0.912385);
produces:
0.91239
That rounds correctly, but it always prints a fixed number of decimal places. For example:
String.format("%.5f", 0.912300);
produces:
0.91230
I also tried DecimalFormat:
DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);
which produces:
0.91238
This uses half-even rounding by default, but I want this behavior instead:
0.912385 -> 0.91239
0.912300 -> 0.9123
What is the best way to achieve this in Java?
Short Answer
By the end of this page, you will understand how Java rounds decimal numbers, why String.format and DecimalFormat behave differently, and how to produce output that uses HALF_UP rounding without unnecessary trailing zeros. You will also see why BigDecimal is often the safest choice for precise decimal formatting.
Concept
In Java, rounding a number and formatting a number are related, but they are not exactly the same task.
- Rounding decides what the numeric value becomes.
- Formatting decides how that value is displayed as text.
In this question, you need both:
- Round to a maximum number of decimal places.
- Use half-up rounding.
- Remove trailing zeros from the displayed result.
Half-up rounding
HALF_UP means:
- If the discarded part is less than 5, round down.
- If it is 5 or more, round up.
Examples:
1.2344to 3 decimal places ->1.2341.2345to 3 decimal places ->1.235
This is the style of rounding many people learn first.
Why DecimalFormat matters
DecimalFormat lets you control how a number is displayed.
For example:
0.#####means up to 5 decimal places- trailing zeros are not forced
That makes it a good fit for output like:
0.912390.9123
However, you must explicitly set the rounding mode if you want HALF_UP.
Why BigDecimal is often better than double
A double is a binary floating-point type. Many decimal values cannot be represented exactly in binary.
That means a value that looks like 0.912385 might internally be stored as something very close to it, not exactly it.
For display-only tasks, DecimalFormat can be enough. But for precise rounding logic, especially in financial or business code, developers often use BigDecimal because it gives predictable decimal behavior.
Best practical approach
If your goal is:
- half-up rounding
- up to
ndecimal places - no trailing zeros
then a common solution is:
DecimalFormat df = new DecimalFormat("0.#####");
df.setRoundingMode(RoundingMode.HALF_UP);
String result = df.format(0.912385);
This gives display-friendly output while using the rounding mode you want.
Mental Model
Think of rounding like cutting a rope at a marked point.
- The number of decimal places tells you where to cut.
- The next digit tells you whether to move the cut point slightly forward.
HALF_UPmeans if the next digit is5or more, you always push the value up.
Now think of formatting as deciding how to write the result on a label.
String.format("%.5f", ...)says: always print exactly 5 digits after the decimal point.DecimalFormat("0.#####")says: print up to 5 digits after the decimal point, but do not add extra zeros.
So:
- rounding decides the value
- formatting decides the appearance
Syntax and Examples
Using DecimalFormat with HALF_UP
import java.math.RoundingMode;
import java.text.DecimalFormat;
public class Main {
public static void main(String[] args) {
DecimalFormat df = new DecimalFormat("0.#####");
df.setRoundingMode(RoundingMode.HALF_UP);
System.out.println(df.format(0.912385)); // 0.91239
System.out.println(df.format(0.912300)); // 0.9123
System.out.println(df.format(2.0)); // 2
}
}
Why this works
0.#####means:- always show at least one digit before the decimal point
- show up to 5 digits after the decimal point
- do not show unnecessary trailing zeros
setRoundingMode(RoundingMode.HALF_UP)changes the default rounding behavior to the one you want
Reusable method
import java.math.RoundingMode;
import java.text.DecimalFormat;
public class Main {
public static String formatRounded(double value, int decimalPlaces) {
StringBuilder pattern = new StringBuilder("0");
if (decimalPlaces > 0) {
pattern.append(".");
for (int i = 0; i < decimalPlaces; i++) {
pattern.append("#");
}
}
DecimalFormat df = new DecimalFormat(pattern.toString());
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(value);
}
public static void main(String[] args) {
System.out.println(formatRounded(0.912385, 5)); // 0.91239
System.out.println(formatRounded(0.912300, 5)); // 0.9123
System.out.println(formatRounded(12.5, 0)); // 13
}
}
Using BigDecimal for precise decimal rounding
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Main {
public static String formatRounded(String value, int scale) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(scale, RoundingMode.HALF_UP);
bd = bd.stripTrailingZeros();
return bd.toPlainString();
}
public static void main(String[] args) {
System.out.println(formatRounded("0.912385", 5)); // 0.91239
System.out.println(formatRounded("0.912300", 5)); // 0.9123
}
}
This version is especially useful when exact decimal behavior matters.
Step by Step Execution
Consider this example:
DecimalFormat df = new DecimalFormat("0.#####");
df.setRoundingMode(RoundingMode.HALF_UP);
String result = df.format(0.912385);
System.out.println(result);
Step-by-step
1. Create the format pattern
new DecimalFormat("0.#####")
This means:
0before the decimal: show at least one digit#####after the decimal: show up to 5 decimal places
2. Set the rounding mode
df.setRoundingMode(RoundingMode.HALF_UP);
Now if the 6th decimal digit affects rounding, Java will round the 5th digit upward when appropriate.
3. Format the number
df.format(0.912385)
The number has 6 decimal places:
- keep first 5:
0.91238 - next digit is
5 - with
HALF_UP, round up - result becomes
0.91239
4. Store and print the string
String result = df.format(0.912385);
System.out.println(result);
Output:
0.91239
Another trace
df.format(0.912300)
- up to 5 decimal places are allowed
- trailing zeros are not required by
# - result becomes
0.9123
So the same formatter handles both rounding and clean display.
Real World Use Cases
This pattern appears often in real software whenever numbers must be shown clearly to users.
Common use cases
- Financial displays
- show tax, discount, or totals with a defined rounding rule
- Reports and dashboards
- display percentages or calculated values without visual clutter
- Scientific or measurement tools
- round values for readable output while keeping only meaningful digits
- APIs generating text output
- convert computed decimal values into strings for logs, exports, or CSV files
- UI forms and summaries
- show values like
3.5instead of3.50000
- show values like
Example scenarios
- A shopping cart displays
12.5instead of12.50000 - A grade calculator shows
91.235rounded to91.24 - A sensor reading displays
0.9123rather than0.91230
In all of these, users care about both correctness and readability.
Real Codebase Usage
In real projects, developers usually separate internal numeric calculations from final display formatting.
Common patterns
1. Compute first, format last
Do calculations using BigDecimal or numeric types, then format only when showing output.
BigDecimal total = new BigDecimal("12.3456");
String display = total.setScale(2, RoundingMode.HALF_UP).toPlainString();
2. Centralize formatting logic
Instead of repeating formatting code everywhere, create a utility method.
public static String formatAmount(double value) {
DecimalFormat df = new DecimalFormat("0.##");
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(value);
}
This avoids inconsistent output across the codebase.
3. Use BigDecimal for business rules
When precision matters, such as money, taxes, or invoice totals, teams prefer BigDecimal over double.
4. Use formatter patterns for optional digits
Developers often choose patterns like:
0.##0.######,##0.00
depending on whether trailing zeros should be kept or removed.
5. Validate the required precision
If a method accepts decimalPlaces, guard against invalid values.
if (decimalPlaces < 0) {
throw new IllegalArgumentException("decimalPlaces must be >= 0");
}
This is a common defensive programming pattern.
Common Mistakes
1. Using String.format when you do not want trailing zeros
Broken example:
System.out.println(String.format("%.5f", 0.912300));
Output:
0.91230
Why it happens:
%.5fmeans exactly 5 digits after the decimal point
Use this instead when trailing zeros should be optional:
DecimalFormat df = new DecimalFormat("0.#####");
df.setRoundingMode(RoundingMode.HALF_UP);
2. Forgetting to set the rounding mode
Broken example:
DecimalFormat df = new DecimalFormat("0.#####");
System.out.println(df.format(0.912385));
This may not use the rounding behavior you expect.
Fix:
df.setRoundingMode(RoundingMode.HALF_UP);
3. Assuming double stores exact decimal values
Broken assumption:
double value = 0.1;
This looks exact, but floating-point storage can introduce tiny representation differences.
Safer approach for precise decimal work:
BigDecimal bd = new BigDecimal("0.1");
4. Creating BigDecimal directly from a double
Problematic example:
BigDecimal bd = new BigDecimal(0.912385);
This may capture the inexact binary floating-point value.
Prefer:
BigDecimal bd = new BigDecimal("0.912385");
or:
BigDecimal bd = BigDecimal.valueOf(0.912385);
5. Confusing decimal places with significant figures
These are different ideas:
- decimal places: digits after the decimal point
- significant figures: meaningful digits overall
Your examples are really about up to N decimal places with no trailing zeros, not scientific significant-figure formatting.
Comparisons
| Approach | Rounding control | Trailing zeros | Best for | Notes |
|---|---|---|---|---|
String.format("%.5f", value) | Limited for this use case | Always shown | Fixed-width display | Good when you always want exact decimal places |
DecimalFormat("0.#####") | Yes, with setRoundingMode | Removed | User-facing display | Best fit for this question |
BigDecimal.setScale(..., HALF_UP) | Excellent | Can remove with stripTrailingZeros() | Precise decimal logic | Best when exact decimal behavior matters |
DecimalFormat vs String.format
- Use
String.formatwhen output must always have the same width or same number of decimals. - Use
DecimalFormatwhen you need custom display behavior such as optional digits.
double vs BigDecimal
| Type | Precision | Good for |
|---|---|---|
double | Binary floating-point, not exact for many decimals | General math, fast calculations |
BigDecimal | Exact decimal arithmetic | Money, business rules, controlled rounding |
If you only need display formatting, DecimalFormat is often enough. If the rounding result itself must be exact and reliable, prefer BigDecimal.
Cheat Sheet
Quick solution
DecimalFormat df = new DecimalFormat("0.#####");
df.setRoundingMode(RoundingMode.HALF_UP);
String result = df.format(0.912385); // 0.91239
Pattern rules
0= required digit#= optional digit0.#####= up to 5 decimal places, no forced trailing zeros0.00000= exactly 5 decimal places
Rounding mode
RoundingMode.HALF_UP
5rounds upward- common “schoolbook” rounding
Reusable method
public static String formatRounded(double value, int decimalPlaces) {
StringBuilder pattern = new StringBuilder("0");
if (decimalPlaces > 0) {
pattern.append(".");
for (int i = 0; i < decimalPlaces; i++) {
pattern.append("#");
}
}
DecimalFormat df = new DecimalFormat(pattern.toString());
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(value);
}
Precise alternative
BigDecimal bd = new BigDecimal("0.912385");
bd = bd.setScale(5, RoundingMode.HALF_UP);
String s = bd.stripTrailingZeros().toPlainString();
Watch out for
String.format("%.5f", ...)forces trailing zerosnew BigDecimal(double)can introduce precision surprisesdoublevalues are not exact decimal storage
FAQ
How do I round to 2 or 5 decimal places in Java?
Use DecimalFormat for display formatting or BigDecimal.setScale() for precise decimal rounding.
How do I remove trailing zeros after rounding in Java?
Use DecimalFormat with # placeholders, such as 0.#####, or use BigDecimal.stripTrailingZeros().
What is the difference between HALF_UP and HALF_EVEN?
HALF_UP rounds .5 upward. HALF_EVEN rounds toward the nearest even digit in tie cases. HALF_EVEN is often used to reduce rounding bias over many calculations.
Why does String.format keep extra zeros?
Because formats like %.5f mean exactly 5 digits after the decimal point.
Should I use double or BigDecimal for rounding?
Use double for general-purpose numeric work and formatting. Use BigDecimal when exact decimal precision matters, such as money or business calculations.
Why did DecimalFormat not round the way I expected?
Because its default rounding mode may not match your requirement. Set it explicitly with:
df.setRoundingMode(RoundingMode.HALF_UP);
Can I build the decimal format pattern dynamically?
Yes. This is common when the number of decimal places is provided at runtime.
Mini Project
Description
Build a small Java utility that formats decimal numbers for display. The tool should round using HALF_UP and print only meaningful decimal digits. This mirrors a common real-world need in dashboards, billing summaries, measurement displays, and exported reports.
Goal
Create a reusable formatter method that rounds to a chosen number of decimal places and removes unnecessary trailing zeros.
Requirements
- Create a method that accepts a numeric value and the maximum number of decimal places.
- Use half-up rounding.
- Return the formatted value as a string.
- Do not include trailing zeros after the decimal point.
- Demonstrate the method with several test values.
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.