skip to content

Explain Math.round, Math.floor, and Math.ceil — their return types and rounding behavior, including how round handles ties and negatives.

level: middleimportance: must knowfreq 60%

answer

  1. floor = down (toward -∞), ceil = up (toward +∞)
  2. floor/ceil return double; round returns long (double arg) or int (float arg)
  3. round(x) = floor(x + 0.5) → half rounds UP toward +∞
  4. round(2.5)=3 but round(-2.5)=-2 (asymmetric, not away-from-zero)
  5. (int) cast = truncate toward zero, NOT rounding; money → BigDecimal

basics

~20 s

floor rounds down to the nearest whole number, ceil rounds up, and round goes to the nearest whole number (rounding .5 up). floor/ceil return double; round returns long (from a double) or int (from a float).

solid answer

~40 s

All three turn a fractional value into a whole one. Math.floor(x) returns the largest integer value not greater than x (rounds toward negative infinity); Math.ceil(x) returns the smallest integer not less than x (toward positive infinity). Both return a double, so floor(2.7) is 2.0, not 2. Math.round is nearest-integer and is defined as floor(x + 0.5): it returns a long for a double argument and an int for a float. The subtle bit is ties and negatives: because round adds 0.5 then floors, it rounds half *up* toward positive infinity — round(2.5)=3 but round(-2.5)=-2, not -3. That asymmetry surprises people expecting symmetric 'round half away from zero'. For controlled financial rounding you'd use BigDecimal with an explicit RoundingMode instead.

go deeper

for a junior

Knows floor rounds down, ceil rounds up, round goes to nearest with .5 going up; can use them for a display value.

for a middle

States the exact return types (floor/ceil→double, round→long/int) and the floor(x+0.5) definition; distinguishes round from a cast.

for a senior

Explains the negative-number asymmetry from floor(x+0.5) and why money needs BigDecimal + RoundingMode rather than Math.round.

for a principal

Sets rounding conventions across services (which RoundingMode for finance, locale/half-even rules) and flags double-based rounding as an audit/precision risk in calculations.

## The problem these solve Floating-point numbers like `2.7` have a fractional part. Sometimes you need a whole number instead — for an array index, a pixel count, a display value. `Math` gives three functions that each round differently. ## `Math.floor` — round down (toward negative infinity) `Math.floor(x)` returns the **largest integer value that is not greater than `x`**. Think "step down to the next whole number." - `Math.floor(2.7)` → `2.0` - `Math.floor(-2.1)` → `-3.0` (down means *more negative*) Important: it returns a **`double`**, not an `int`. The value `2.0` is a whole number stored as a double. You must cast `(int)` or `(long)` if you want an integer type. ## `Math.ceil` — round up (toward positive infinity) `Math.ceil(x)` (short for *ceiling*) returns the **smallest integer value not less than `x`** — "step up to the next whole number." - `Math.ceil(2.1)` → `3.0` - `Math.ceil(-2.7)` → `-2.0` (up means *less negative*) Also returns a `double`. ## `Math.round` — nearest integer, half up `Math.round(x)` returns the value **nearest** to `x`. Its return type differs from floor/ceil: - `Math.round(double)` returns a **`long`**. - `Math.round(float)` returns an **`int`**. Its exact definition is **`floor(x + 0.5)`** — add a half, then round down. This single rule explains its tie-breaking and negative behavior: **Ties (the `.5` case).** Because we add 0.5 and floor, a value sitting exactly halfway rounds **up toward positive infinity**: - `Math.round(2.5)` → `3` - `Math.round(3.5)` → `4` **Negatives are asymmetric.** Apply the same `floor(x+0.5)`: - `Math.round(-2.5)` = `floor(-2.5 + 0.5)` = `floor(-2.0)` = `-2` (NOT -3) - `Math.round(-2.6)` = `floor(-2.1)` = `-3` So `round(2.5)=3` but `round(-2.5)=-2`. This is *round half up*, which is **not** the same as "round half away from zero" — a very common interview trap. ## Casting vs rounding A plain cast `(int) 2.9` is **truncation toward zero**, giving `2` — it is *not* rounding. `(int) -2.9` gives `-2`. Don't confuse a cast with `Math.round`. ## When Math rounding isn't enough For money and reports you usually need a specific, auditable rule (round half even, half down, scale to 2 decimals). `Math` only offers the fixed half-up behavior on a `double`, which also carries floating-point error. Use `BigDecimal` with an explicit `RoundingMode` (e.g. `HALF_EVEN`) for that. ## Quick reference | Input | floor | ceil | round | (long)cast/truncate | |---|---|---|---|---| | 2.4 | 2.0 | 3.0 | 2 | 2 | | 2.5 | 2.0 | 3.0 | 3 | 2 | | -2.5 | -3.0 | -2.0 | -2 | -2 | | -2.6 | -3.0 | -2.0 | -3 | -2 |

  • Why is Math.round(-2.5) equal to -2 instead of -3?
    round is defined as floor(x + 0.5). For -2.5 that's floor(-2.0) = -2. Adding 0.5 first means ties always go toward positive infinity, so negatives round 'up' (less negative), which is round-half-up, not round-half-away-from-zero.
  • What's the difference between Math.round(2.7) and (int) 2.7?
    Math.round(2.7) gives 3 (nearest integer). (int) 2.7 gives 2 — a cast truncates the fractional part toward zero, it does not round.

saying these in an interview costs you the question

  • Saying floor/ceil return int (they return double).
  • Claiming Math.round is 'half away from zero' (it's half up toward +∞: round(-2.5) = -2).
  • Thinking (int) cast rounds (it truncates toward zero).
  • Forgetting round(double) returns long while round(float) returns int.

context