What are the BigDecimal RoundingModes, and why is HALF_EVEN (banker's rounding) often preferred for money?
answer
- UP/DOWN = away/toward zero; CEILING/FLOOR = toward +/- infinity
- HALF_UP = ties away from zero (schoolbook)
- HALF_EVEN = banker's, ties to nearest even, no upward bias
- UNNECESSARY throws if any rounding needed
- Must pass a mode to setScale and rounding-divide
basics
~20 sRoundingMode defines how to drop digits: HALF_UP rounds .5 away from zero (the schoolbook way), HALF_DOWN toward zero, and HALF_EVEN rounds .5 to the nearest even digit. HALF_EVEN is preferred for money because it removes the upward bias of always rounding .5 up.
solid answer
~50 sRoundingMode is an enum telling BigDecimal how to discard excess digits. The main ones: UP (away from zero), DOWN (toward zero, i.e. truncate), CEILING (toward positive infinity), FLOOR (toward negative infinity), and the three 'half' modes for the exactly-.5 tie case — HALF_UP (.5 rounds away from zero, the everyday rule), HALF_DOWN (.5 rounds toward zero), and HALF_EVEN, 'banker's rounding', where .5 rounds to whichever neighbor is even. UNNECESSARY asserts no rounding is needed and throws ArithmeticException if any would occur. HALF_EVEN is favored for monetary and statistical work because consistently rounding .5 upward (HALF_UP) introduces a systematic upward bias; over many values the over- and under-roundings of HALF_EVEN cancel out, keeping sums unbiased. It's the IEEE-754 default and used by setScale and MathContext when you choose it. You always pass a RoundingMode to setScale or divide when a result must be shortened.
code
java · 6 linesBigDecimal v = new BigDecimal("2.5");
System.out.println(v.setScale(0, RoundingMode.HALF_UP)); // 3
System.out.println(v.setScale(0, RoundingMode.HALF_EVEN)); // 2 (even neighbor)
System.out.println(new BigDecimal("3.5").setScale(0, RoundingMode.HALF_EVEN)); // 4
System.out.println(new BigDecimal("-2.1").setScale(0, RoundingMode.FLOOR)); // -3
System.out.println(new BigDecimal("-2.1").setScale(0, RoundingMode.CEILING)); // -2go deeper
Knows RoundingMode controls how rounding works and that HALF_UP is the familiar 'round .5 up' rule; knows you must pass one to setScale.
Distinguishes the directed modes (UP/DOWN/CEILING/FLOOR) from the half modes and explains HALF_EVEN as banker's rounding.
Explains the upward-bias rationale for preferring HALF_EVEN in money/stats, knows it's the IEEE-754 default, and respects domain rules that mandate HALF_UP.
Sets and enforces the rounding policy across services and persistence, considers regulatory requirements, and prevents inconsistent rounding across teams/locales.
## What rounding means here When a BigDecimal has more digits than you want (e.g. a division result, or you call `setScale(2, …)` on `1.005`), some digits must be **discarded**, and the kept digits may need to change. A **RoundingMode** is an enum (`java.math.RoundingMode`) that specifies exactly *how* to do that. You must supply one to `setScale(scale, mode)` and to the rounding overloads of `divide`. ## The directed (non-tie) modes These decide direction regardless of the discarded fraction: - **UP** — round **away from zero**. 2.1 → 3, -2.1 → -3. Increases magnitude. - **DOWN** — round **toward zero** (plain truncation). 2.9 → 2, -2.9 → -2. - **CEILING** — round toward **+∞**. 2.1 → 3, -2.9 → -2. - **FLOOR** — round toward **−∞**. 2.9 → 2, -2.1 → -3. Note CEILING/FLOOR are sign-aware (toward an infinity), while UP/DOWN are magnitude-aware (away/toward zero). ## The half (tie-breaking) modes These only differ when the discarded part is **exactly half** (e.g. rounding 2.5 to an integer): - **HALF_UP** — ties round **away from zero**. 2.5 → 3, -2.5 → -3. This is the rounding you learned in school. - **HALF_DOWN** — ties round **toward zero**. 2.5 → 2, -2.5 → -2. - **HALF_EVEN** — ties round to the **nearest even** digit (a.k.a. **banker's rounding**). 2.5 → 2, 3.5 → 4, 2.45 (at scale 1) → 2.4. Non-tie cases behave like normal nearest rounding. ## UNNECESSARY - **UNNECESSARY** — asserts the operation needs **no** rounding; if rounding *would* be required it throws `ArithmeticException`. Use it as a guard when you believe the scale already fits. ## Why HALF_EVEN for money/statistics With **HALF_UP**, every exact-.5 tie rounds **up**. Across a large population of values, the half-cent ties are not symmetric — they all push the sum **upward**, creating a small but real **systematic bias**. Over millions of rows this skews totals. **HALF_EVEN** breaks ties toward the even neighbor, so roughly half the ties round up and half round down (because consecutive integers alternate even/odd). The biases **cancel**, leaving sums unbiased on average. That's why it's the **IEEE-754 default** and the standard choice for accounting and statistics. The tradeoff: it's less intuitive to humans (2.5 → 2 surprises people), so some regulated domains *mandate* HALF_UP — always follow the domain/regulatory rule. ## How you apply it ```java BigDecimal price = new BigDecimal("2.345"); price.setScale(2, RoundingMode.HALF_EVEN); // 2.34 price.setScale(2, RoundingMode.HALF_UP); // 2.35 ``` The same modes drive `divide(divisor, scale, mode)` and the rounding inside a `MathContext`. ## stripTrailingZeros Separate from rounding, `stripTrailingZeros()` removes insignificant trailing zeros without changing value (`2.500` → `2.5`); combine with `setScale` for a clean fixed display.
- Round 2.5 and 3.5 to integers with HALF_EVEN.2.5 → 2 (nearest even is 2) and 3.5 → 4 (nearest even is 4). HALF_UP would give 3 and 4.
- What's the difference between CEILING and UP for -2.1?CEILING rounds toward +infinity → -2. UP rounds away from zero → -3. They agree for positive numbers but differ in sign handling for negatives.
- When would you use RoundingMode.UNNECESSARY?As an assertion: when you believe a value already fits the target scale and want a fast failure (ArithmeticException) if that assumption is wrong, rather than silently rounding.
saying these in an interview costs you the question
- Saying HALF_EVEN always rounds .5 down (it rounds to the even neighbor)
- Confusing CEILING with UP and FLOOR with DOWN (they differ for negatives)
- Claiming HALF_UP is unbiased
- Calling setScale(2) without a RoundingMode when rounding is needed (throws)