Explain Math.round, Math.floor, and Math.ceil — their return types and rounding behavior, including how round handles ties and negatives.
answer
- floor = down (toward -∞), ceil = up (toward +∞)
- floor/ceil return double; round returns long (double arg) or int (float arg)
- round(x) = floor(x + 0.5) → half rounds UP toward +∞
- round(2.5)=3 but round(-2.5)=-2 (asymmetric, not away-from-zero)
- (int) cast = truncate toward zero, NOT rounding; money → BigDecimal
basics
~20 sfloor 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 sAll 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
Knows floor rounds down, ceil rounds up, round goes to nearest with .5 going up; can use them for a display value.
States the exact return types (floor/ceil→double, round→long/int) and the floor(x+0.5) definition; distinguishes round from a cast.
Explains the negative-number asymmetry from floor(x+0.5) and why money needs BigDecimal + RoundingMode rather than Math.round.
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.