Mathematics7 min readExamples run on PHP 8.5.10

round()

Learn how PHP 8.4 round() rounds floats to a decimal precision, how negative precision and rounding modes work, and which mistakes to avoid.

Signature

round(int|float $num, int $precision = 0, int|RoundingMode $mode = RoundingMode::HalfAwayFromZero): float

Purpose

round() rounds a number to a chosen number of decimal digits. By default it rounds to a whole number, but the precision argument lets you keep decimals or round to tens, hundreds and beyond. It is the standard tool for tidying up a calculated value before you store or show it.

Signature

Parameters and defaults

  • $num: the value to round, either an int or a float.
  • $precision: how many digits after the decimal point to keep. The default is 0. A positive value keeps decimals. A negative value rounds to the left of the decimal point, so -1 rounds to tens, -2 to hundreds and so on.
  • $mode: what to do when the value sits exactly halfway between two candidates. The default is RoundingMode::HalfAwayFromZero, which is the same behaviour as the classic PHP_ROUND_HALF_UP constant: 2.5 becomes 3 and -2.5 becomes -3. You may pass the older constants (PHP_ROUND_HALF_UP, PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD) or a RoundingMode case.

Return value and failures

The function always returns a float, even when you pass an integer and the result looks whole. round(345, -2) gives float(300), not int(300). If you need an integer type, cast the result, for example with (int).

An invalid $mode throws a ValueError. In PHP 8.4.0 the manual lists this as a change: before that release an invalid mode silently behaved like PHP_ROUND_HALF_UP. The 8.4.0 changelog also lists four new rounding modes, which exist only as RoundingMode cases.

Example 1: precision, including negative precision

The first example shows the default mode, a positive precision, a negative number and a negative precision. var_dump() makes the float type visible.

Example
<?php
var_dump(round(3.5));
var_dump(round(5.055, 2));
var_dump(round(345, -2));
var_dump(round(-2.5));
Output
float(4)
float(5.06)
float(300)
float(-3)

Example 2: choosing a rounding mode

The mode only matters for exact halves. Banker's rounding (HalfEven) sends 8.5 to 8 and 9.5 to 10, so ties are spread evenly between up and down. HalfTowardsZero pulls ties toward zero, and PositiveInfinity always pushes upward.

Example
<?php
var_dump(round(8.5, 0, PHP_ROUND_HALF_EVEN));
var_dump(round(9.5, 0, PHP_ROUND_HALF_EVEN));
var_dump(round(-3.5, 0, RoundingMode::HalfTowardsZero));
var_dump(round(8.5, 0, RoundingMode::PositiveInfinity));
Output
float(8)
float(10)
float(-3)
float(9)

Example 3: practical calculations

A typical use is rounding a tax amount to cents, then formatting it. Rounding to tens with a negative precision is useful for rough estimates. Remember to cast when you need an int.

Example
<?php
$subtotal = 59.97;
$tax = round($subtotal * 0.0825, 2);
echo number_format($tax, 2), PHP_EOL;
echo (int) round(1234, -1), PHP_EOL;
echo round(1234.5678, 2), PHP_EOL;
Output
4.95
1230
1234.57

Edge cases

  • Rounding more coarsely than the value allows can produce zero. round(345, -3) returns float(0) and round(678, -3) returns float(1000).
  • Asking for more precision than the number has changes nothing: round(135.79, 3) is still 135.79.
  • Results close to zero from negative inputs may be negative zero, which can display as -0. Add a check if you print values directly to users.
  • Negative numbers are handled symmetrically by the default mode: -1.55 at precision 1 becomes -1.6, mirroring 1.6.
  • Since PHP 8.0.0, $num no longer accepts internal objects that support numeric conversion.

Common mistakes

  1. Expecting an integer. The return type is always float. Cast the result, or use number_format() for display.
  2. Rounding too early. If you round every intermediate step, small errors add up. Round once, at the end of a calculation.
  3. Treating floats as exact decimals. Values such as 5.055 cannot be stored exactly in binary. PHP's result for round(5.055, 2) is 5.06, but you should not build logic around values that only look like ties. For money, consider storing integer cents.
  4. Confusing precision direction. A positive $precision counts digits after the decimal point. A negative one counts places to the left. They are not interchangeable.
  5. Using round() for formatting. round(5, 2) returns float(5), not a string with two decimals. Use number_format() when you need a fixed number of decimals in output.
  6. Passing an invalid mode. In PHP 8.4 this throws a ValueError instead of quietly falling back to the default.
  • ceil() always rounds fractions up.
  • floor() always rounds fractions down.
  • number_format() formats a number with grouped thousands and a fixed number of decimals, returning a string.

Recap

round() takes a number, an optional precision and an optional mode, and returns a float. Positive precision keeps decimals, negative precision rounds to tens, hundreds and higher, and the mode controls how exact halves are resolved. Cast to int when you need an integer, format with number_format() for display, and be careful with floating point representation when values look like ties.

Tested examples

Precision, including negative precision
<?php
var_dump(round(3.5));
var_dump(round(5.055, 2));
var_dump(round(345, -2));
var_dump(round(-2.5));
Output
float(4)
float(5.06)
float(300)
float(-3)
Choosing a rounding mode
<?php
var_dump(round(8.5, 0, PHP_ROUND_HALF_EVEN));
var_dump(round(9.5, 0, PHP_ROUND_HALF_EVEN));
var_dump(round(-3.5, 0, RoundingMode::HalfTowardsZero));
var_dump(round(8.5, 0, RoundingMode::PositiveInfinity));
Output
float(8)
float(10)
float(-3)
float(9)
Practical calculations
<?php
$subtotal = 59.97;
$tax = round($subtotal * 0.0825, 2);
echo number_format($tax, 2), PHP_EOL;
echo (int) round(1234, -1), PHP_EOL;
echo round(1234.5678, 2), PHP_EOL;
Output
4.95
1230
1234.57