PHP Manual

Математика в PHP

16. 02. 2020

Obsah článku

Як і в інших мовах, числа в PHP представлені в двійковій системі (системі одиниць і нулів), тому деякі математичні операції можуть давати дещо інші результати, ніж можна було б очікувати. На цій сторінці наведено огляд поведінки обчислень у різних контекстах. Для розуміння потрібні принаймні базові знання про **числові методи** та **системи числення**.

Представлення чисел в пам'яті

Спосіб представлення чисел характеризується типом даних, наприклад, ціле число перетворюється безпосередньо з вихідного коду з десяткової системи числення в двійкову. Нам взагалі не потрібно турбуватися про конвертацію цифр, все робиться автоматично.

Наслідком такого перетворення є те, що максимальне значення цілого числа визначається кількістю розрядів, доступних в пам'яті. На 32-бітному PHP діапазон від -2 147 483 648 до -2 147 483 647 (~ ± 2 мільярди), на 64-бітному PHP діапазон від -9 223 372 036 854 775 808 до -9 223 372 036 854 775 807 (~ ± 9 квінтильйонів). Максимальне значення завжди можна отримати, викликавши константу PHP_INT_MAX.

Десяткові числа зберігаються в типі даних float, який має обмежену точність, тому зберігається внутрішньо у вигляді пари чисел, до яких застосовується математична операція мантиса * (2^експонента). Практичним наслідком є те, що ми можемо зберігати відносно велику кількість (порядку мільярдів) в невеликій кількості бітів, просто не дуже точно.

Наслідком використання типу даних float є те, що результат обчислення 1 - 0,9 не є точно 0,1.

Приклад з веб-форумів:

$x = 0.3;
$y = 0.4;
echo 0.7 - $x - $y; // prints -5.5511151231258E-17

Якщо трохи підкоригувати цифри:

$x = 6.5;
$y = 7.5;
echo 14.0 - $x - $y; // виводить 0

Взагалі це питання обговорюється в окремій статті на VTM.e15.cz: Чому комп'ютери мають проблеми з десятковими числами, або взагалі про плаваючу крапку у Вікіпедії.

Як правило, бажано округляти результат після обчислення або взагалі уникати десяткових знаків. Наприклад, зберігати ціну не в кронах (як 14,90), а в копійках (як 1490) і потім працювати саме з нею. Округлення обговорюється в наступному розділі цієї статті.

Математичні операції

$a = 5;
$b = 3;
echo $a + $b;

Для операцій можуть використовуватися загальноприйняті математичні конвенції, які поважають пріоритет операторів згідно з правилами математики (множення має пріоритет над додаванням і т.д.). Значення можуть бути записані безпосередньо або прочитані через змінні.

Можливо, це не очевидно на перший погляд, але в математичному прикладі не написано знак рівності (=). Звідси випливає, що розв'язувати можна лише прості "бінарні операції", які завжди працюють лише з "двома елементами" (рівняння не рахувати, для цього треба використовувати спеціалізовану бібліотеку).

Огляд основних операторів

У колонці "результат" я перераховую, що буде надруковано в припущенні:

$a = 5;
$b = 3;
$c = 10;

Операція Позначення Позначення словами Приклад позначення Результат
Додавання + Плюс echo $a + $b; 8
Віднімання - Мінус echo $a - $b; 2
Множення * Зірочка echo $a * $b; 15
поділ / коса риска echo $a / $b; 1.666666666666667
дужки ( ) дужки echo $a + ($b * $c); 35
Конкатенація рядків . Крапка echo $a . $b . $c; 5310
Залишок після ділення % Відсоток echo $a % $b; 2
Додавання одного ++ двох плюсів echo $a++; 6
Відняти один мінус два мінус чотири.
Сила - дві зірочки - відлуння $a ** $b; 125

Оператор степеня (подвійна зірочка) доступний тільки починаючи з версії PHP 7.1. В інших версіях PHP необхідно використовувати універсальну функцію pow($a, $b).

Огляд основних математичних функцій

Якщо ви вирішуєте якусь поширену обчислювальну задачу, то швидше за все вже є функція безпосередньо в PHP, ось анотований огляд їх.

Округлення

Звичайне округлення виконується функцією round(), вона має 3 параметри:

  • Округлене число
  • Необов'язково: Точність (до скількох знаків після коми)
  • Необов'язково: Округлення значення вдвічі (від якого значення округляти в більшу сторону)

round(5); // 5
round(5.1); // 5
round(5.4); // 5
round(5.5); // 6
round(5.8); // 6
round(5483.47621, 2); // 5483.47
round(5483.47621, -2); // 5500

Існує також функція floor() для округлення в меншу сторону і ceil() для округлення в більшу сторону.

Обережно, типи даних!

Всі функції округлення повертають результат як float, навіть якщо результат є цілим числом.

Якщо ви хочете обробляти результат як ціле число, важливо переписати результат після цього. Наприклад: echo (int) round(3.14);.

PHP працює з різними типами даних, наприклад з float легко може статися так, що результатом функції round() буде не число з кінцевим десятковим розкладанням. Для лістингу рекомендую використовувати функцію number_format(), про яку я розповім нижче.

Гоніометричні функції

Вони використовуються для багатьох різних розрахунків і базуються на одиничному колі. Вони використовуються, наприклад, при побудові кіл, еліпсів, переміщень тощо.

Циклометричні функції

Обчислити кут від x і y. Перетворення декартових і полярних координат.

Гіперболічні функції

На основі одиничної гіперболи. Їх визначення можна легко описати, використовуючи приклади:

  • Еліпс, Коло, Коло з радіусом 1
  • Гіпербола, Рівнобічна гіпербола, Одинична гіпербола

Вони використовуються, наприклад, для генерації рельєфу місцевості та фізичного моделювання.

Гіперболічні функції

На основі одиничної гіперболи.

Приклади використання гоніометричних функцій

echo sin(30); // -0.98803162409286
echo sin(deg2rad(30)); // 0.5
echo cos(deg2rad(123)); // -0.54463903501503
echo 1/tan(deg2rad(45)); // 1 (один котангенс)
echo sin(deg2rad(500)); // 0.64278760968654
echo atan2(deg2rad(50), deg2rad(23)); // 1.1396575860761

Калькулятор - обробка математичних виразів

Іноді може статися так, що нам потрібно обробити математичний вираз у вигляді рядка користувача, наприклад 5+2^(1+3/2).

Не існує простого способу обробки такого вводу в PHP, але я запрограмував ряд бібліотек, які вирішують цю проблему.

Детальніше дивіться в окремій статті Калькулятор на PHP: Обробка математичного виразу у вигляді рядка.

Операції з великими числами і точність розрахунків

Великі числа і десяткові знаки в PHP зберігаються як числа з плаваючою комою, плюс вони округляються приблизно до 15 знаків після коми, що іноді може дратувати. Саме тому було створено бібліотеку довільної прецизійної математики BCMath.

Числа в цій бібліотеці представлені як строки, тому вони не обмежені неточністю float, але операції, що виконуються, відбуваються на кілька порядків повільніше (але все одно швидше, ніж якби ми запрограмували таку функцію самостійно).

Наприклад, якщо ми хочемо отримати квадратний корінь з 2 до 3 знаків після коми, ми просто викликаємо:

echo bcsqrt('2', 3); // 1.414

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
2.
Status:
All systems normal.
2024