Math.floor()

ES1+

Returns the largest integer less than or equal to the given number, rounding toward negative infinity. For positive numbers it simply drops the fraction, but for negatives it moves away from zero: Math.floor(-4.2) is -5. The result is still a double, so it can exceed 32-bit integer range safely.

Syntax

Math.floor(x)

Parameters

x number

A number

Return Value

number

The largest integer less than or equal to the given number

Examples

JavaScript
console.log(Math.floor(4.7));
console.log(Math.floor(4.2));
console.log(Math.floor(-4.7));
Output:
// 4 4 -5

📌 When to Use

Use Math.floor() when partial units do not count: converting a continuous value into a discrete index or bucket. Classic cases include mapping Math.random() output onto integer ranges (Math.floor(Math.random() * n) yields 0 to n-1 uniformly), computing which page, row, or grid cell a position falls into (index = Math.floor(offset / itemSize)), turning elapsed milliseconds into whole seconds or days, quantizing coordinates to pixels or tiles in games and canvas work, and answering "how many complete units fit" questions like full boxes filled or whole years of age. Its defining property, rounding toward negative infinity, is exactly what bucketing requires even for negative inputs: a point at -0.5 on a tile map belongs to tile -1, not tile 0, which is why floor (not trunc) is correct for coordinate systems that extend below zero. Choose deliberately among the four rounding functions: floor for "which bucket am I in", ceil for "how many containers do I need", round for "nearest value", and trunc for "drop the decimals toward zero". If you find yourself flooring currency, stop and reconsider: financial rounding rules are policy, usually requiring integer minor units and explicit rounding modes rather than a silent floor.

⚠️ Common Mistakes

Expecting truncation on negatives: Math.floor(-4.7) is -5, not -4. Code that uses floor to "drop decimals" works in every test with positive data, then misbehaves the first time a delta, temperature, or coordinate goes negative; Math.trunc() is the drop-decimals function.

Flooring the artifacts of binary floating point: 0.1 + 0.2 is 0.30000000000000004, and (0.1 + 0.2) * 10 floors to 3 as expected, but 4.35 * 100 is 434.99999999999994, so Math.floor(4.35 * 100) is 434, off by one for money. Round at the final step, or better, compute prices in integer cents.

The opposite float trap in literals: Math.floor(4.999999999999999999) is 5, because the literal itself rounds to 5.0 before floor ever runs, doubles only carry about 15-17 significant decimal digits. Floor cannot rescue precision already lost upstream.

Using the (x | 0) bitwise "fast floor": it truncates rather than floors negatives, and it wraps catastrophically outside 32-bit range, (2147483648.5 | 0) is -2147483648. It also does not floor at all for values beyond 2^31; reserve bitwise tricks for values proven to fit int32.

Dividing then flooring in integer-overflow-prone ways when a modulo was the real question, or flooring an index without clamping: Math.floor(scroll / rowHeight) can exceed the last row index at the extreme bottom edge, so pair bucket math with Math.min(maxIndex, ...) clamps.

✅ Best Practices

Encode the intent in the function choice, floor for bucket/index math, ceil for capacity, trunc for decimal-stripping, round for nearest, and leave a comment when negatives make the distinction load-bearing.

Generate random integers with the canonical pattern: Math.floor(Math.random() * (max - min + 1)) + min. Using Math.round here skews the distribution, giving the endpoints half the probability of interior values.

For money and quantities with fixed decimals, work in scaled integers (cents, basis points) so floor/ceil/round operate on exact values; convert to display units only at the formatting edge with Intl.NumberFormat.

Clamp derived indexes at boundaries: const row = Math.min(rows - 1, Math.max(0, Math.floor(y / rowHeight))). Floating-point edge inputs (exactly at the far edge, or -0) otherwise generate off-by-one array accesses.

When flooring to a multiple rather than to 1, use Math.floor(x / step) * step, and be aware the multiplication can reintroduce float error for decimal steps (0.1, 0.05); with decimal steps, compute in scaled integers instead.

⚡ Performance Notes

Math.floor() maps to a single rounding instruction on modern CPUs and is inlined by all major engines, so it costs roughly as much as an addition; it is fully safe in per-frame and per-element hot loops. The folklore alternative (x | 0) is no longer meaningfully faster in optimized code and carries 32-bit wraparound and negative-truncation hazards, so it survives mainly in asm.js-era code and int32-proven inner kernels. One engine-level nuance: results that fit in the small-integer range let the JIT keep values in integer registers, so flooring array indexes early can actually help downstream code stay on fast integer paths. As always, the arithmetic is never the bottleneck, memory access and allocation around it are; flooring into a typed array index inside a tight loop is essentially free compared to the array access itself.

🌍 Real World Example

Pagination Calculator

Pagination is bucket math end to end: which page an item sits on is a floor question (Math.floor(index / pageSize)), while how many pages exist is a ceiling question, and this example shows the two working together with the boundary cases, exact multiples, the final partial page, and empty lists, handled explicitly. Getting these right by construction beats patching off-by-one bugs found in QA. The identical index arithmetic drives virtualized scrolling (which rows are visible), image-sprite atlases, and chunked API fetching.

function calculatePagination(totalItems, itemsPerPage) {
  const totalPages = Math.ceil(totalItems / itemsPerPage);
  const currentPage = 1;
  const startIndex = Math.floor((currentPage - 1) * itemsPerPage);

  return {
    totalPages,
    startIndex,
    endIndex: Math.min(startIndex + itemsPerPage, totalItems)
  };
}

console.log(calculatePagination(95, 10));
// { totalPages: 10, startIndex: 0, endIndex: 10 }

Related Methods