Mathematics7 min readExamples run on PHP 8.5.10

floor()

Learn how PHP 8.4 floor() rounds numbers down to the next lowest whole value, why it returns a float, and how negative numbers behave.

Signature

floor(int|float $num): float

Purpose

floor() rounds a number down to the nearest whole value that is not greater than the input. Any fractional part is dropped in the direction of negative infinity. This makes it useful for bucketing values, computing whole units already completed, or snapping a coordinate to a grid cell.

Signature

Parameters and defaults

$num is the only parameter, and it has no default. It accepts an integer or a float. In PHP's default weak typing mode, a numeric string such as "4.7" is converted to a number first. Under declare(strict_types=1), a string argument is rejected.

Since PHP 8.0.0, floor() no longer accepts internal objects that support numeric conversion. Pass a real number instead.

Return value and failure cases

The function returns the next lowest whole number, and the result is always of type float, even when the input was an int. A call such as floor(5) gives 5.0, which echo prints as 5.

Failures follow the usual rules for internal functions:

  • A non-numeric string or an array raises a TypeError.
  • Passing null to this non-nullable parameter is deprecated, so avoid it.
  • NAN and infinite values are not meaningful to round, and they come back as they are.

Example 1: positive and negative inputs

The key point is that rounding goes toward negative infinity. Positive fractions lose their decimals, but negative fractions move to the more negative whole number.

Example
<?php
echo floor(4.3), PHP_EOL;
echo floor(9.999), PHP_EOL;
echo floor(-3.14), PHP_EOL;
Output
4
9
-4

The output is 4, 9 and -4. This differs from truncation, which would turn -3.14 into -3.

Example 2: the result is a float

Because the return type is float, you may need a cast if the next step expects an integer, for example an array index or a strictly typed parameter.

Example
<?php
$value = floor(7.9);
var_dump($value);
var_dump((int) $value);
Output
float(7)
int(7)

The first dump shows float(7) and the second shows int(7). Casting is safe here because the value is already whole and within the integer range.

Example 3: grouping values into buckets

Dividing by a bucket size, flooring and multiplying back gives the start of the bucket that contains a value. This works for age ranges, price bands or time slots measured in plain integers.

Example
<?php
function bucketStart(int $value, int $size): int {
    return (int) (floor($value / $size) * $size);
}
echo bucketStart(37, 10), PHP_EOL;
echo bucketStart(40, 10), PHP_EOL;
echo bucketStart(-3, 10), PHP_EOL;
Output
30
40
-10

The results are 30, 40 and -10. The negative case lands in the bucket that starts at -10 because floor() rounds toward negative infinity, which is usually what you want for consistent, gap-free buckets.

Edge cases

  • Already whole numbers are returned unchanged, only as a float.
  • Negative fractions move away from zero. For example, -0.5 becomes -1.
  • Very large floats are usually already whole numbers, since a float has limited precision. Flooring them changes nothing, and casting them to int may overflow the integer range.
  • Binary floating-point error can affect the input before floor() sees it. A calculation that should give exactly 8 may produce 7.999999999999999, and flooring it gives 7. When exact decimal results matter, use integers, such as cents instead of dollars, or round to a sensible precision first.

Common mistakes

  1. Expecting an integer type. The result is a float. Cast it, or use integer division with intdiv() when both operands are integers.
  2. Confusing floor with truncation. For negative numbers the two differ, so check which behavior your logic needs.
  3. Using floor when rounding to nearest is intended. floor(2.9) is 2, whereas round(2.9) is 3.
  4. Flooring money calculated with floats. Tiny representation errors can drop a whole unit unexpectedly.
  5. Passing unvalidated input. Text that is not numeric causes a TypeError, so validate user data before using it.
  • ceil() rounds fractions up to the next highest whole number.
  • round() rounds to the nearest value, with optional precision.
  • intdiv() performs integer division directly.

Recap

floor() takes an int or float and returns the largest whole number not above it, always typed as float. Remember that negative values move toward negative infinity, cast the result when an integer is required, and be careful with floating-point input that is slightly below the value you expect.

Tested examples

Rounding positive and negative numbers down
<?php
echo floor(4.3), PHP_EOL;
echo floor(9.999), PHP_EOL;
echo floor(-3.14), PHP_EOL;
Output
4
9
-4
floor() returns a float
<?php
$value = floor(7.9);
var_dump($value);
var_dump((int) $value);
Output
float(7)
int(7)
Grouping integers into buckets
<?php
function bucketStart(int $value, int $size): int {
    return (int) (floor($value / $size) * $size);
}
echo bucketStart(37, 10), PHP_EOL;
echo bucketStart(40, 10), PHP_EOL;
echo bucketStart(-3, 10), PHP_EOL;
Output
30
40
-10