Numbers & Math
Shopping carts, marks, GST, EMI calculators, cricket statistics: almost every program does some maths. PHP has two number types and a good set of maths functions, plus a few traps that every developer should know about.
In this lesson you will learn how PHP stores numbers, how its arithmetic works, how to round and format results, and how to handle money without losing paise.
Integers and floats
PHP has two number types:
- An int (integer) is a whole number, such as
47,-3or0. On a 64-bit system it can go up toPHP_INT_MAX, which is 9,223,372,036,854,775,807. - A float (floating-point number) has a decimal point, such as
3.5or0.18.
Long numbers are hard to read, so PHP lets you put underscores between digits. PHP ignores them, which means you can even group digits the Indian way:
<?php
declare(strict_types=1);
$annualFee = 1_25_000;
$population = 3_12_00_000;
$gstRate = 0.18;
var_dump($annualFee);
var_dump($population);
var_dump($annualFee * $gstRate);int(125000) int(31200000) float(22500)
When you multiply an int by a float, the result is always a float, even if it has no decimal part. That is why the GST amount shows as float(22500).
Arithmetic operators
| 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 |
Division / gives an int only when the answer is a whole number, otherwise a float. When you want only the whole-number part, use intdiv(). The % operator gives the remainder:
<?php
declare(strict_types=1);
$students = 47;
$seatsPerBus = 12;
echo $students / $seatsPerBus, "\n";
echo intdiv($students, $seatsPerBus), " full buses\n";
echo $students % $seatsPerBus, " students left over\n";
echo ceil($students / $seatsPerBus), " buses needed\n";3.9166666666667 3 full buses 11 students left over 4 buses needed
The usual order of operations applies: ** first, then *, / and %, then + and -. Use brackets whenever the order is not obvious, as in ($a + $b) * $c.
Dividing by zero throws a DivisionByZeroError with the message "Division by zero" and stops the script. Check the divisor first when it comes from user input.
Rounding and maths functions
| Function | What it does | Example | Result |
|---|---|---|---|
round($n, $digits) | Round to nearest | round(1299.456, 2) | 1299.46 |
floor($n) | Round down | floor(4.9) | 4 |
ceil($n) | Round up | ceil(4.1) | 5 |
abs($n) | Remove the minus sign | abs(-250) | 250 |
max(...), min(...) | Largest or smallest | max(45, 78, 62) | 78 |
sqrt($n) | Square root | sqrt(144) | 12 |
pi() | The value of pi | pi() | 3.1415926535898 |
round(), floor() and ceil() always return a float, even when the result is a whole number. Cast with (int) if you need an int. By default, round() rounds halves away from zero, so round(2.5) is 3 and round(-2.5) is -3.
<?php
declare(strict_types=1);
$marks = [78, 91, 66, 84];
$average = array_sum($marks) / count($marks);
echo "Average: ", round($average, 1), "\n";
echo "Highest: ", max($marks), "\n";
echo "Lowest: ", min($marks), "\n";
$radius = 7;
echo "Area of the pitch circle: ", round(pi() * $radius ** 2, 2), "\n";Average: 79.8 Highest: 91 Lowest: 66 Area of the pitch circle: 153.94
array_sum() and count() add up and count the items in an array. You will learn more array functions in Array Functions.
Floats are not exact
Computers store floats in binary, and many decimal fractions, such as 0.1, cannot be stored exactly. Small errors appear:
<?php
declare(strict_types=1);
$total = 0.1 + 0.2;
var_dump($total);
var_dump($total == 0.3);
echo $total, "\n";float(0.30000000000000004) bool(false) 0.3
echo rounds the number for display, so it looks like 0.3, but the stored value is slightly more. That is why the comparison with 0.3 is false.
For money, this matters. The safe approach is to store amounts as whole paise in ints, do all the maths with ints, and divide by 100 only when you display the amount. For exact decimal maths you can also use the bcmath extension; PHP 8.4 added a BcMath\Number object that makes it easier to use.
Formatting numbers for people
number_format() adds thousands separators and a fixed number of decimal places. It returns a string, ready to print:
<?php
declare(strict_types=1);
$pricePaise = 129950;
$quantity = 3;
$totalPaise = $pricePaise * $quantity;
echo '₹' . number_format($totalPaise / 100, 2), "\n";
echo number_format(1234567.5, 2), "\n";
$indian = new NumberFormatter('en_IN', NumberFormatter::CURRENCY);
echo $indian->formatCurrency(1234567.5, 'INR'), "\n";₹3,898.50 1,234,567.50 ₹12,34,567.50
number_format() always groups digits in threes (the international style). For the Indian lakh and crore style, use the NumberFormatter class with the en_IN locale, as in the last line. NumberFormatter comes from the intl extension; in XAMPP, enable it by removing the ; before extension=intl in php.ini and restarting Apache.
Random numbers
random_int($min, $max) returns a random whole number between the two values, including both ends. It is cryptographically secure, so it is safe for OTPs and tokens:
<?php
declare(strict_types=1);
$dice = random_int(1, 6);
$otp = random_int(100000, 999999);
echo "You rolled $dice\n";
echo "Your OTP is $otp\n";Each run prints different numbers, for example "You rolled 4" and a six-digit OTP. You may see rand() or mt_rand() in older code. They are fine for games, but they are predictable, so never use them for anything related to security.
Common mistakes
- Storing money as floats. Rounding errors add up. Store paise as ints, or use bcmath.
- Comparing floats with
==. Compare rounded values instead, for exampleround($a, 2) === round($b, 2). - Expecting
/to give an int.7 / 2is3.5. Useintdiv()for whole-number division. - Forgetting that
round()returns a float.round(4.6)isfloat(5). Cast to(int)if you need an int. - Using
rand()for OTPs. Userandom_int()for anything secret.
Key points
- PHP has two number types:
intfor whole numbers andfloatfor decimals. - Underscores in number literals, such as
1_25_000, make big numbers readable. /may return a float;intdiv()gives the whole part and%gives the remainder.round(),floor()andceil()return floats;max(),min()andabs()work as expected.- Floats are not exact, so keep money in paise as ints.
number_format()formats for display;NumberFormatterwithen_INgives lakh and crore grouping.- Use
random_int()for secure random numbers.
Exercise
Write an EMI-style calculator for a ₹49,999 phone bought in 6 monthly instalments. Store the price in paise as an int. Work out the instalment in paise with intdiv(), and the remaining paise that do not divide evenly with %. Print the instalment amount and the leftover amount, both formatted as rupees with two decimal places.
Show solution
<?php
declare(strict_types=1);
$pricePaise = 49_999_00;
$months = 6;
$instalment = intdiv($pricePaise, $months);
$leftover = $pricePaise % $months;
echo 'Monthly instalment: ₹' . number_format($instalment / 100, 2), "\n";
echo 'Added to the last month: ₹' . number_format($leftover / 100, 2), "\n";Monthly instalment: ₹8,333.16 Added to the last month: ₹0.04
Working in paise keeps every value an exact int. The few leftover paise are added to one instalment, so the customer pays exactly ₹49,999.00 in total.
Quick Quiz
1. What does 7 / 2 return in PHP?
Division returns a float when the answer is not a whole number; use intdiv() for 3.
2. What is 17 % 5?
The % operator returns the remainder: 17 is 3 times 5, plus 2.
3. Why should prices be stored as whole paise instead of rupee floats?
Floats like 0.1 are stored approximately, so money totals can be slightly wrong.
4. Which function should you use to generate a login OTP?
random_int() is cryptographically secure; the older functions are predictable.
Learn PHP with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
