EasyТеория10 min

Математические функции

abs, ceil, floor, round, pow, sqrt, тригонометрия, случайные числа, Random\Randomizer, конвертация систем счисления

PHP предоставляет обширный набор встроенных математических функций для работы с числами: от базового округления до тригонометрии, генерации случайных чисел и конвертации между системами счисления. Все эти функции доступны без подключения дополнительных расширений.

Базовые математические функции

abs() -- модуль числа

<?php
declare(strict_types=1);

// abs() returns the absolute value
echo abs(-42);    // 42
echo abs(42);     // 42
echo abs(-3.14);  // 3.14
echo abs(0);      // 0

// Practical: calculating distance between two points on a line
function distanceOnLine(float $a, float $b): float
{
    return abs($a - $b);
}

echo distanceOnLine(10.5, 3.2); // 7.3
echo distanceOnLine(3.2, 10.5); // 7.3

ceil(), floor(), round() -- округление

<?php
declare(strict_types=1);

// ceil() — always rounds UP (ceiling)
echo ceil(4.1);   // 5
echo ceil(4.9);   // 5
echo ceil(-4.1);  // -4
echo ceil(-4.9);  // -4
echo ceil(5.0);   // 5

// floor() — always rounds DOWN (floor)
echo floor(4.1);  // 4
echo floor(4.9);  // 4
echo floor(-4.1); // -5
echo floor(-4.9); // -5
echo floor(5.0);  // 5

// round() — rounds to the nearest value
echo round(4.4);  // 4
echo round(4.5);  // 5
echo round(4.6);  // 5
echo round(-4.5); // -5

// round() with precision (number of decimal places)
echo round(3.14159, 2);  // 3.14
echo round(3.14159, 3);  // 3.142
echo round(3.14159, 0);  // 3.0
echo round(1234.5, -1);  // 1230.0 (negative precision!)
echo round(1234.5, -2);  // 1200.0
echo round(1250.0, -2);  // 1300.0

Режимы округления round()

<?php
declare(strict_types=1);

// PHP_ROUND_HALF_UP — rounds 0.5 away from zero (default)
echo round(2.5, 0, PHP_ROUND_HALF_UP);   // 3
echo round(-2.5, 0, PHP_ROUND_HALF_UP);  // -3
echo round(3.55, 1, PHP_ROUND_HALF_UP);  // 3.6

// PHP_ROUND_HALF_DOWN — rounds 0.5 toward zero
echo round(2.5, 0, PHP_ROUND_HALF_DOWN);   // 2
echo round(-2.5, 0, PHP_ROUND_HALF_DOWN);  // -2
echo round(3.55, 1, PHP_ROUND_HALF_DOWN);  // 3.5

// PHP_ROUND_HALF_EVEN — rounds 0.5 to nearest even (banker's rounding)
echo round(2.5, 0, PHP_ROUND_HALF_EVEN);   // 2 (2 is even)
echo round(3.5, 0, PHP_ROUND_HALF_EVEN);   // 4 (4 is even)
echo round(4.5, 0, PHP_ROUND_HALF_EVEN);   // 4 (4 is even)
echo round(5.5, 0, PHP_ROUND_HALF_EVEN);   // 6 (6 is even)

// PHP_ROUND_HALF_ODD — rounds 0.5 to nearest odd
echo round(2.5, 0, PHP_ROUND_HALF_ODD);    // 3 (3 is odd)
echo round(3.5, 0, PHP_ROUND_HALF_ODD);    // 3 (3 is odd)
echo round(4.5, 0, PHP_ROUND_HALF_ODD);    // 5 (5 is odd)

Banker's rounding (HALF_EVEN) -- используется в финансовых расчётах для минимизации систематической ошибки округления. При обычном округлении 0.5 всегда вверх -- за большое число операций сумма систематически завышается.

fmod(), intdiv(), fdiv() -- деление

<?php
declare(strict_types=1);

// fmod() — floating-point modulo (remainder)
echo fmod(10.5, 3.2);  // 0.9 (10.5 - 3 * 3.2 = 0.9)
echo fmod(10, 3);       // 1.0
echo fmod(-10, 3);      // -1.0

// Difference from % operator: fmod works with floats
echo 10 % 3;            // 1 (integer modulo)
// echo 10.5 % 3.2;     // TypeError in PHP 8.0+ (int operands required)
echo fmod(10.5, 3.2);   // 0.9 (float modulo works)

// intdiv() — integer division (truncated toward zero)
echo intdiv(7, 2);      // 3
echo intdiv(-7, 2);     // -3
echo intdiv(7, -2);     // -3
echo intdiv(1, 3);      // 0

// intdiv throws DivisionByZeroError
try {
    intdiv(10, 0);
} catch (\DivisionByZeroError $e) {
    echo $e->getMessage(); // "Division by zero"
}

// fdiv() — float division (PHP 8.0+)
// Unlike /, fdiv() returns INF or NAN instead of errors
echo fdiv(10, 3);       // 3.3333333333333
echo fdiv(10, 0);       // INF (no warning!)
echo fdiv(-10, 0);      // -INF
echo fdiv(0, 0);        // NAN
echo 10 / 0;            // DivisionByZeroError in PHP 8.0+

Степени и логарифмы

<?php
declare(strict_types=1);

// pow() — exponentiation
echo pow(2, 8);      // 256
echo pow(2, -1);     // 0.5
echo pow(27, 1/3);   // 3.0 (cube root)
echo 2 ** 8;         // 256 (** operator, same as pow)

// sqrt() — square root
echo sqrt(144);      // 12.0
echo sqrt(2);        // 1.4142135623731

// sqrt of negative returns NAN
echo sqrt(-1);       // NAN
var_dump(is_nan(sqrt(-1))); // true

// log() — natural logarithm (base e)
echo log(M_E);       // 1.0
echo log(1);         // 0.0
echo log(100);       // 4.6051701859881

// log() with custom base (second argument)
echo log(8, 2);      // 3.0 (log base 2 of 8)
echo log(1000, 10);  // 3.0 (log base 10 of 1000)

// log2() — base-2 logarithm
echo log2(256);      // 8.0
echo log2(1024);     // 10.0

// log10() — base-10 logarithm (common logarithm)
echo log10(100);     // 2.0
echo log10(1000);    // 3.0

// exp() — e raised to the power
echo exp(0);         // 1.0
echo exp(1);         // 2.718281828... (M_E)
echo exp(2);         // 7.3890560989307

// Practical: compound interest
function compoundInterest(
    float $principal,
    float $rate,
    int $timesPerYear,
    int $years
): float {
    return $principal * pow(1 + $rate / $timesPerYear, $timesPerYear * $years);
}

// $10,000 at 5% annual, compounded monthly, for 10 years
echo compoundInterest(10000, 0.05, 12, 10); // 16470.09...

Тригонометрические функции

<?php
declare(strict_types=1);

// All trig functions work with RADIANS, not degrees!

// sin(), cos(), tan() — basic trigonometric functions
echo sin(0);         // 0.0
echo sin(M_PI / 2);  // 1.0
echo sin(M_PI);      // ~0 (1.2246...e-16, floating point imprecision)
echo cos(0);         // 1.0
echo cos(M_PI);      // -1.0
echo tan(0);         // 0.0
echo tan(M_PI / 4);  // ~1.0

// Inverse trig functions: asin(), acos(), atan()
echo asin(1);        // 1.5707963... (PI/2)
echo acos(0);        // 1.5707963... (PI/2)
echo atan(1);        // 0.7853981... (PI/4)

// atan2(y, x) — angle from X axis to point (x, y)
// Handles all quadrants correctly, unlike atan(y/x)
echo atan2(1, 1);    // 0.7853981... (PI/4, 45 degrees)
echo atan2(1, -1);   // 2.3561944... (3*PI/4, 135 degrees)
echo atan2(-1, -1);  // -2.3561944... (-3*PI/4, -135 degrees)
echo atan2(0, -1);   // 3.1415926... (PI, 180 degrees)

// deg2rad() and rad2deg() — conversion
echo deg2rad(180);   // 3.1415926... (PI)
echo deg2rad(90);    // 1.5707963... (PI/2)
echo deg2rad(360);   // 6.2831853... (2*PI)
echo rad2deg(M_PI);  // 180.0
echo rad2deg(1);     // 57.29577951...

// Practical: distance between two GPS coordinates (Haversine formula)
function haversineDistance(
    float $lat1, float $lon1,
    float $lat2, float $lon2
): float {
    $earthRadius = 6371; // km

    $dLat = deg2rad($lat2 - $lat1);
    $dLon = deg2rad($lon2 - $lon1);

    $a = sin($dLat / 2) ** 2
       + cos(deg2rad($lat1)) * cos(deg2rad($lat2))
       * sin($dLon / 2) ** 2;

    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));

    return $earthRadius * $c;
}

// Moscow to Saint Petersburg (~634 km)
echo haversineDistance(55.7558, 37.6173, 59.9343, 30.3351); // ~634.4

min(), max(), array_sum(), array_product()

<?php
declare(strict_types=1);

// min() and max() — with individual arguments
echo min(2, 3, 1, 6, 7);  // 1
echo max(2, 3, 1, 6, 7);  // 7

// min() and max() — with arrays
$numbers = [15, 3, 42, 8, 23];
echo min($numbers);  // 3
echo max($numbers);  // 42

// Be careful with mixed types!
echo min(0, 'hello');   // 0 (numeric comparison)
echo min('a', 'b');     // 'a' (string comparison)

// array_sum() — sum of all values
echo array_sum([1, 2, 3, 4, 5]);         // 15
echo array_sum([1.5, 2.5, 3.0]);         // 7.0
echo array_sum([]);                       // 0

// array_product() — product of all values
echo array_product([1, 2, 3, 4, 5]);     // 120
echo array_product([2, 2, 2]);           // 8
echo array_product([]);                   // 1 (empty product = 1)

// Practical: average, median, standard deviation
function average(array $numbers): float
{
    if (count($numbers) === 0) {
        throw new \InvalidArgumentException('Array cannot be empty');
    }
    return array_sum($numbers) / count($numbers);
}

function median(array $numbers): float
{
    if (count($numbers) === 0) {
        throw new \InvalidArgumentException('Array cannot be empty');
    }
    sort($numbers);
    $count = count($numbers);
    $middle = intdiv($count, 2);

    if ($count % 2 === 0) {
        return ($numbers[$middle - 1] + $numbers[$middle]) / 2;
    }

    return (float) $numbers[$middle];
}

function standardDeviation(array $numbers): float
{
    $avg = average($numbers);
    $squaredDiffs = array_map(
        fn(float|int $n): float => ($n - $avg) ** 2,
        $numbers
    );
    return sqrt(average($squaredDiffs));
}

$data = [4, 8, 15, 16, 23, 42];
echo average($data);            // 18.0
echo median($data);             // 15.5
echo standardDeviation($data);  // 12.159...

Случайные числа

random_int() -- криптографически безопасный CSPRNG

<?php
declare(strict_types=1);

// random_int() — cryptographically secure random integer (PHP 7+)
// Uses /dev/urandom or CryptGenRandom — suitable for security
echo random_int(1, 100);       // random number from 1 to 100
echo random_int(0, 1);         // random 0 or 1 (coin flip)
echo random_int(PHP_INT_MIN, PHP_INT_MAX); // full range

// random_bytes() — cryptographically secure random bytes
$bytes = random_bytes(16);       // 16 random bytes
echo bin2hex($bytes);            // hex representation

// Generate random token
function generateToken(int $length = 32): string
{
    return bin2hex(random_bytes($length));
}

echo generateToken();    // 64 hex characters
echo generateToken(16);  // 32 hex characters

mt_rand() -- устаревший генератор (legacy)

<?php
declare(strict_types=1);

// mt_rand() — Mersenne Twister (NOT cryptographically secure!)
// Use ONLY for non-security purposes
echo mt_rand();            // random int
echo mt_rand(1, 100);     // random int from 1 to 100
echo mt_getrandmax();     // maximum possible value (2147483647)

// rand() — alias for mt_rand() since PHP 7.1
echo rand(1, 100);

// NEVER use mt_rand/rand for:
// - Passwords, tokens, session IDs
// - Cryptographic keys
// - CSRF tokens
// - Any security-sensitive context

Random\Randomizer -- ООП API (PHP 8.2+)

<?php
declare(strict_types=1);

use Random\Randomizer;
use Random\Engine\Mt19937;
use Random\Engine\PcgOneseq128XslRr64;
use Random\Engine\Xoshiro256StarStar;
use Random\Engine\Secure;

// Default engine (Secure — CSPRNG)
$randomizer = new Randomizer();
echo $randomizer->nextInt();              // random int
echo $randomizer->getInt(1, 100);         // random int in range
echo $randomizer->getBytes(16);           // 16 random bytes

// Shuffle array
$cards = range(1, 52);
$shuffled = $randomizer->shuffleArray($cards);

// Shuffle string
echo $randomizer->shuffleBytes('Hello World'); // random permutation

// Pick random keys from array
$items = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
$picked = $randomizer->pickArrayKeys($items, 3); // 3 random keys

// Get random float in [0, 1) — PHP 8.3+
// echo $randomizer->nextFloat();         // 0.0 <= x < 1.0
// echo $randomizer->getFloat(0.0, 1.0);  // float in range

// Mt19937 engine — deterministic, reproducible sequences
$seeded = new Randomizer(new Mt19937(42));
echo $seeded->getInt(1, 100);  // always same sequence for seed 42
echo $seeded->getInt(1, 100);  // always same second value

// PcgOneseq128XslRr64 — fast, good statistical properties
$pcg = new Randomizer(new PcgOneseq128XslRr64(12345));
echo $pcg->getInt(1, 1000);

// Xoshiro256StarStar — extremely fast, good for simulations
$xoshiro = new Randomizer(new Xoshiro256StarStar(98765));
echo $xoshiro->getInt(1, 1000);

// Secure engine — explicit CSPRNG (same as default)
$secure = new Randomizer(new Secure());
echo $secure->getInt(1, 1000);

// Practical: weighted random selection
function weightedRandom(Randomizer $rng, array $weights): string
{
    $total = array_sum($weights);
    $roll = $rng->getInt(1, $total);
    $cumulative = 0;

    foreach ($weights as $item => $weight) {
        $cumulative += $weight;
        if ($roll <= $cumulative) {
            return (string) $item;
        }
    }

    throw new \LogicException('Unreachable');
}

$loot = [
    'common'    => 60,
    'uncommon'  => 25,
    'rare'      => 10,
    'legendary' => 5,
];

echo weightedRandom(new Randomizer(), $loot); // random loot drop

Конвертация между системами счисления

<?php
declare(strict_types=1);

// base_convert() — convert between any bases (2 to 36)
echo base_convert('ff', 16, 10);   // "255" (hex to decimal)
echo base_convert('255', 10, 16);  // "ff" (decimal to hex)
echo base_convert('255', 10, 2);   // "11111111" (decimal to binary)
echo base_convert('377', 8, 10);   // "255" (octal to decimal)

// Specialized functions (faster, type-aware)

// Binary
echo decbin(255);    // "11111111"
echo bindec('11111111'); // 255

// Octal
echo decoct(255);    // "377"
echo octdec('377');  // 255

// Hexadecimal
echo dechex(255);    // "ff"
echo hexdec('ff');   // 255
echo dechex(16777215); // "ffffff" (white color in RGB)

// Practical: color conversion
function hexToRgb(string $hex): array
{
    $hex = ltrim($hex, '#');

    // Support shorthand (#fff -> #ffffff)
    if (strlen($hex) === 3) {
        $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
    }

    return [
        'r' => hexdec(substr($hex, 0, 2)),
        'g' => hexdec(substr($hex, 2, 2)),
        'b' => hexdec(substr($hex, 4, 2)),
    ];
}

function rgbToHex(int $r, int $g, int $b): string
{
    return sprintf('#%02x%02x%02x', $r, $g, $b);
}

var_dump(hexToRgb('#ff6600')); // ['r' => 255, 'g' => 102, 'b' => 0]
echo rgbToHex(255, 102, 0);   // "#ff6600"

Математические константы

<?php
declare(strict_types=1);

// Mathematical constants
echo M_PI;          // 3.1415926535898 — Pi
echo M_E;           // 2.718281828459  — Euler's number (e)
echo M_LOG2E;       // 1.442695040889  — log2(e)
echo M_LOG10E;      // 0.43429448190325 — log10(e)
echo M_LN2;         // 0.69314718055995 — ln(2)
echo M_LN10;        // 2.302585092994  — ln(10)
echo M_PI_2;        // 1.5707963267949 — Pi/2
echo M_PI_4;        // 0.78539816339745 — Pi/4
echo M_1_PI;        // 0.31830988618379 — 1/Pi
echo M_2_PI;        // 0.63661977236758 — 2/Pi
echo M_SQRT2;       // 1.4142135623731 — sqrt(2)
echo M_SQRT3;       // 1.7320508075689 — sqrt(3)
echo M_SQRT1_2;     // 0.70710678118655 — 1/sqrt(2)

// PHP integer/float limits
echo PHP_INT_MAX;       // 9223372036854775807 (on 64-bit)
echo PHP_INT_MIN;       // -9223372036854775808
echo PHP_INT_SIZE;      // 8 (bytes on 64-bit)
echo PHP_FLOAT_MAX;     // 1.7976931348623E+308
echo PHP_FLOAT_MIN;     // 2.2250738585072E-308 (smallest positive normalized)
echo PHP_FLOAT_EPSILON; // 2.2204460492503E-16 (smallest x such that 1.0 + x != 1.0)
echo PHP_FLOAT_DIG;     // 15 (number of significant digits)

// Special float values
echo INF;               // INF (infinity)
echo -INF;              // -INF
echo NAN;               // NAN (Not a Number)
echo log(0);            // -INF
echo acos(2);           // NAN (argument out of range)

is_nan(), is_infinite(), is_finite()

<?php
declare(strict_types=1);

// is_nan() — check if value is Not A Number
var_dump(is_nan(NAN));          // true
var_dump(is_nan(sqrt(-1)));     // true
var_dump(is_nan(acos(2)));      // true
var_dump(is_nan(42));           // false
var_dump(is_nan(INF));          // false (infinity is not NAN)

// IMPORTANT: NAN !== NAN (NAN is never equal to anything, even itself)
var_dump(NAN == NAN);           // false!
var_dump(NAN === NAN);          // false!
// Always use is_nan() for checks

// is_infinite() — check for +/- infinity
var_dump(is_infinite(INF));     // true
var_dump(is_infinite(-INF));    // true
var_dump(is_infinite(log(0)));  // true (-INF)
var_dump(is_infinite(42));      // false
var_dump(is_infinite(NAN));     // false

// is_finite() — check if value is a finite number
var_dump(is_finite(42));        // true
var_dump(is_finite(3.14));      // true
var_dump(is_finite(INF));       // false
var_dump(is_finite(NAN));       // false

// Practical: safe division function
function safeDivide(float $a, float $b): float|null
{
    $result = fdiv($a, $b);

    if (!is_finite($result)) {
        return null;
    }

    return $result;
}

echo safeDivide(10, 3) ?? 'undefined';  // 3.3333...
echo safeDivide(10, 0) ?? 'undefined';  // "undefined"
echo safeDivide(0, 0) ?? 'undefined';   // "undefined" (NAN)

Практические примеры

Расчёт вероятности

<?php
declare(strict_types=1);

// Factorial using array_product
function factorial(int $n): int
{
    if ($n < 0) {
        throw new \InvalidArgumentException('Factorial of negative number');
    }
    if ($n <= 1) {
        return 1;
    }
    return array_product(range(1, $n));
}

// Combinations C(n, k) = n! / (k! * (n-k)!)
function combinations(int $n, int $k): int
{
    if ($k > $n || $k < 0) {
        return 0;
    }
    return intdiv(factorial($n), factorial($k) * factorial($n - $k));
}

// Permutations P(n, k) = n! / (n-k)!
function permutations(int $n, int $k): int
{
    return intdiv(factorial($n), factorial($n - $k));
}

echo factorial(10);         // 3628800
echo combinations(52, 5);  // 2598960 (poker hands)
echo permutations(10, 3);  // 720

// Probability of getting at least one six in 4 dice throws
$probNoSix = pow(5/6, 4);
$probAtLeastOne = 1 - $probNoSix;
echo round($probAtLeastOne * 100, 2) . '%'; // 51.77%

Геометрические вычисления

<?php
declare(strict_types=1);

// Circle area and perimeter
function circleArea(float $radius): float
{
    return M_PI * $radius ** 2;
}

function circlePerimeter(float $radius): float
{
    return 2 * M_PI * $radius;
}

// Euclidean distance between 2D points
function distance2D(float $x1, float $y1, float $x2, float $y2): float
{
    return sqrt(($x2 - $x1) ** 2 + ($y2 - $y1) ** 2);
}

// Angle between two 2D vectors
function angleBetween(
    float $x1, float $y1,
    float $x2, float $y2
): float {
    $dot = $x1 * $x2 + $y1 * $y2;
    $mag1 = sqrt($x1 ** 2 + $y1 ** 2);
    $mag2 = sqrt($x2 ** 2 + $y2 ** 2);
    return rad2deg(acos($dot / ($mag1 * $mag2)));
}

echo circleArea(5);                          // 78.539...
echo circlePerimeter(5);                     // 31.415...
echo distance2D(0, 0, 3, 4);                // 5.0
echo angleBetween(1, 0, 0, 1);              // 90.0

Проверь себя

5 из 12

Какая из тригонометрических функций принимает два аргумента (y, x) и корректно определяет квадрант?

Какую функцию следует использовать для генерации случайного токена в PHP?

Что вернёт array_product([])?

Какой класс в PHP 8.2+ предоставляет ООП API для работы со случайными числами?

Что вернёт выражение round(2.5, 0, PHP_ROUND_HALF_EVEN)?