Arithmetic operators
PHP has the arithmetic operators you know from school, plus two more:
| Operator | Meaning | Example | Result |
|---|---|---|---|
+ |
add | 7 + 2 |
9 |
- |
subtract | 7 - 2 |
5 |
* |
multiply | 7 * 2 |
14 |
/ |
divide | 7 / 2 |
3.5 |
% |
remainder (modulo) | 7 % 2 |
1 |
** |
power | 7 ** 2 |
49 |
<?php
$price = 24.99;
$quantity = 3;
echo $price * $quantity . "\n";
echo 100 - 37 . "\n";
echo 2 ** 8 . "\n";
echo 17 % 5 . "\n";74.97
63
256
2The usual order of operations applies: ** first, then *, / and %, then + and -. Use brackets whenever the order is not obvious to a reader: ($price + $shipping) * $quantity.
Division, intdiv and the remainder
/ always gives the exact answer, so it returns a float unless the division comes out even. When you want only the whole-number part, use intdiv(). Together with % it splits a quantity into groups:
<?php
$minutes = 135;
$hours = intdiv($minutes, 60);
$rest = $minutes % 60;
echo "$minutes minutes is $hours h $rest min\n";
var_dump(10 / 5);
var_dump(10 / 4);135 minutes is 2 h 15 min
int(2)
float(2.5)The two var_dump() lines show the rule: 10 / 5 divides exactly, so the result is the integer 2, while 10 / 4 does not, so it is the float 2.5.
Dividing by zero is an error in PHP 8. It throws a DivisionByZeroError that stops the script unless you catch it, so check divisors that come from user input.
<?php
$visits = 0;
$sales = 12;
echo $sales / $visits;Fatal error: Uncaught DivisionByZeroError: Division by zero in /path/to/script.php:4
Stack trace:
#0 {main}
thrown in /path/to/script.php on line 4Rounding
Three functions round in different ways:
<?php
echo round(4.567, 2) . "\n";
echo round(2.5) . "\n";
echo round(-2.5) . "\n";
echo floor(4.9) . "\n";
echo ceil(4.1) . "\n";
echo round(1234.5678, -2) . "\n";4.57
3
-3
4
5
1200round() goes to the nearest value, and halves go away from zero. The second argument is the number of decimal places, and a negative number rounds to tens, hundreds and so on. floor() always rounds down and ceil() always rounds up, which is what you want for "how many boxes do I need?" questions: ceil(25 / 6) boxes of six hold 25 items.
Formatting numbers for display
Rounding changes the value; formatting only changes how it is shown. number_format() adds a fixed number of decimals and thousands separators:
<?php
$revenue = 1234567.891;
echo number_format($revenue) . "\n";
echo number_format($revenue, 2) . "\n";
echo number_format($revenue, 2, ',', '.') . "\n";
echo number_format(89.5, 2) . "\n";1,234,568
1,234,567.89
1.234.567,89
89.50The third and fourth arguments set the decimal point and thousands separator, for countries that write numbers differently. For the Indian lakh and crore grouping, PHP's intl extension has NumberFormatter with the en_IN locale.
Floats are approximate
Computers store floats in binary, and most decimal fractions, such as 0.1, have no exact binary form. Tiny errors appear:
<?php
$sum = 0.1 + 0.2;
var_dump($sum);
var_dump($sum == 0.3);
var_dump(abs($sum - 0.3) < 0.00001);float(0.30000000000000004)
bool(false)
bool(true)Never compare floats with ==. Compare the difference with a small tolerance, as in the last line, or round both sides first.
For money, the safest habit is to avoid floats altogether: store amounts as whole numbers of the smallest unit (paise or cents) and only divide by 100 when you display them. For heavy financial maths, PHP's BCMath extension calculates with decimal strings at any precision.
<?php
$pricePaise = 8950; // 89.50
$quantity = 3;
$totalPaise = $pricePaise * $quantity;
echo "Total: " . number_format($totalPaise / 100, 2) . "\n";
echo bcadd('0.1', '0.2', 2) . "\n";Total: 268.50
0.30Useful maths functions
abs() (absolute value), max() and min() (largest and smallest), sqrt() (square root), pi() and random_int() cover most needs:
<?php
echo max(12, 89.5, 24.99) . "\n";
echo min([5, 3, 9]) . "\n";
echo abs(-15) . "\n";
echo sqrt(144) . "\n";89.5
3
15
12random_int($min, $max) returns a cryptographically secure random integer, suitable for codes and tokens. Prefer it to the older rand().
Common mistakes
- Comparing floats with ==, which fails on tiny rounding errors.
- Storing money as floats and adding many of them, which lets errors build up.
- Confusing rounding with formatting:
number_format()returns a string for display; do not calculate with it. - Dividing by a value that might be zero, which throws an error in PHP 8.
Exercise
A customer buys 7 Resistance Bands at 14.99 each. Shipping is 5 per order, and orders over 100 ship free. Calculate the total in paise (cents) to avoid float errors, and print it with two decimals.
Show one possible answer
<?php
$pricePaise = 1499;
$quantity = 7;
$subtotal = $pricePaise * $quantity; // 10493
$shipping = $subtotal > 10000 ? 0 : 500;
$total = $subtotal + $shipping;
echo "Subtotal: " . number_format($subtotal / 100, 2) . "\n";
echo "Shipping: " . number_format($shipping / 100, 2) . "\n";
echo "Total: " . number_format($total / 100, 2) . "\n";Subtotal: 104.93
Shipping: 0.00
Total: 104.93The ? : (ternary) operator picks one of two values; it has its own lesson.
Key points
- The arithmetic operators are + - * / % and ** (power). / returns a float unless the division is exact.
- intdiv() divides and keeps the whole-number part; % gives the remainder.
- round(), floor() and ceil() round in different directions; number_format() formats for display.
- Floats are approximate: 0.1 + 0.2 is not exactly 0.3. Store money as integer paise or cents, or use the BCMath functions.