fmod
Returns the floating point remainder of dividing one number by another.
fmod(float $num1, float $num2): float- Added in PHP 4.2.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$num1 | float | The dividend. |
$num2 | float | The divisor. |
Return value
floatThe floating point remainder of $num1 / $num2, carrying the sign of $num1. Returns NAN if $num2 is zero.
Errors
Never throws DivisionByZeroError; a zero divisor returns NAN. A TypeError is raised only if an argument cannot be coerced to float.
fmod() returns the remainder r such that $num1 = i * $num2 + r for some integer i. When $num2 is nonzero, r takes the sign of $num1 and its magnitude is smaller than that of $num2.
When to reach for it
Use it whenever either operand has a fractional part. The % operator converts both sides to int first, so 7.5 % 3 silently becomes 7 % 3 — and since PHP 8.1 that lossy conversion also emits a deprecation notice. Typical jobs: wrapping an angle into 0-360, checking whether a measurement divides evenly into a step size, positioning something on a repeating grid, and splitting a decimal quantity into whole parts plus a remainder.
What trips people up
The sign follows the dividend, so fmod(-10.5, 3) is -1.5, not 1.5. That is correct C behaviour, but it breaks angle wrapping and array indexing, where you want a non-negative result. The fix is fmod(fmod($a, $b) + $b, $b).
Exact-zero tests are unreliable because the operands rarely have exact binary representations: fmod(0.3, 0.1) is not 0.0 but roughly 0.09999999999999998. Compare against a tolerance instead of using == 0. A zero divisor gives NAN rather than an exception, and NAN never compares equal to anything, so test it with is_nan().
Example
When to use it
- Wrap a compass bearing or rotation angle back into the 0-360 degree range.
- Check whether a decimal measurement is an exact multiple of a step size.
- Split a decimal quantity into whole units plus a fractional leftover.
Frequently asked questions
What is the difference between fmod and the % operator?
% casts both operands to int before dividing, so 7.5 % 3 is really 7 % 3 and emits a deprecation notice in PHP 8.1+. fmod() keeps the fractional parts and returns a float.
Why does fmod return a negative number?
The result carries the sign of the dividend, so fmod(-10.5, 3) is -1.5. Use fmod(fmod($a, $b) + $b, $b) when you need a result in the range 0 to $b.
Why is fmod(0.3, 0.1) not zero?
Neither 0.3 nor 0.1 is exactly representable in binary floating point, so the true remainder is about 0.09999999999999998. Compare the result against a small tolerance rather than testing == 0.
More examples
Wrapping angles safely in both directions
The naive call returns -45 and -90 for the negative inputs because fmod keeps the dividend's sign. Adding the modulus and taking the remainder again pushes everything into 0-360, giving 315 and 270 — the values you actually want for a bearing.
<?php
$wrap = fn(float $a, float $m): float => fmod(fmod($a, $m) + $m, $m);
foreach ([45.0, 450.0, -45.0, -450.0] as $deg) {
printf("%8.1f -> naive %8.1f | wrapped %6.1f\n",
$deg, fmod($deg, 360.0), $wrap($deg, 360.0));
}Testing divisibility with a tolerance
fmod(0.3, 0.1) returns about 0.09999999999999998 rather than 0, because neither operand is exact in binary. The helper accepts a remainder that is close to either 0 or the full step, so 0.3 counts as divisible by 0.1 while 0.35 correctly does not.
<?php
function divides(float $value, float $step, float $eps = 1e-9): bool {
$r = abs(fmod($value, $step));
return $r < $eps || abs($r - abs($step)) < $eps;
}
var_dump(fmod(0.3, 0.1)); // not 0.0
var_dump(fmod(0.3, 0.1) == 0.0); // bool(false)
var_dump(divides(0.3, 0.1)); // bool(true)
var_dump(divides(0.35, 0.1)); // bool(false)Splitting a decimal quantity
18 full shifts account for 135 hours, leaving 2.75. The final line reassembles the original 137.75, confirming the identity num1 = i * num2 + r that defines fmod.
<?php
$totalHours = 137.75;
$perShift = 7.5;
$shifts = floor($totalHours / $perShift);
$left = fmod($totalHours, $perShift);
printf("%d full shifts, %.2f hours left over\n", $shifts, $left);
printf("check: %.2f\n", $shifts * $perShift + $left);
Discussion