Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 92 · С нуля до полного API

BCMath: точные десятичные расчёты и Number

Десятичные строки, масштаб, все функции и методы BCMath, округление и реальные границы денежных расчётов.

Задача: получить 0.30 без двоичного приближения

Наглядная модель

Десятичная сумма без скрытого перехода в float

Строки 0.10 и 0.20 передаются в вычисление как точные десятичные записи.

  1. Вход: строки

    Проверенные значения '0.10' и '0.20', без предварительного float-преобразования.

  2. bcadd(..., 2)

    Вычисление в десятичной арифметике; scale задаёт два знака после точки.

  3. Строка '0.30'

    Результат сохраняет десятичную запись. Это ещё не локализованный текст цены.

  4. Политика денег

    Единицы, допустимый диапазон, округление и распределение копеек определяет приложение.

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

Магазин складывает десятичные суммы, интеграция передаёт цену строкой, прибор сохраняет много знаков после точки. В PHP float хранит двоичное приближение; BCMath вычисляет по десятичным строкам. Результат первого вызова — строка 0.30, которую можно сохранить без предварительного float.

bcadd — готовая функция сложения. (...) ограничивают её входы, запятая разделяет их. '0.10' и '0.20' — строки, кавычки не входят в число. Третий аргумент 2 оставляет два знака после точки. echo печатает результат; ; завершает команду, "\n" переводит строку.

Путь первой суммы
  1. Текст 0.10 и текст 0.20
  2. bcadd разбирает десятичные цифры
  3. Складывает без промежуточного float
  4. Возвращает текст 0.30; echo печатает
Десятичная суммаСамостоятельный пример
<?php
echo bcadd('0.10', '0.20', 2), "\n";
Ожидаемый результат
0.30

Число знаков после точки называется scale. Это модель цифр, не буквальная коробка с бесконечной памятью: время и память ограничены.

Для целого количества копеек часто подходит обычный int при контроле диапазона. BCMath нужен, когда важна десятичная дробь, много разрядов или выход за диапазон int. Он не выбирает валюту, правила налога, этап округления и допустимую точность входного измерения. Что такое переменная; Чем отличаются int, float и string.

Проверить расширение, версию и значение по умолчанию

BCMath входит в исходники PHP, но в Unix-сборке требуется --enable-bcmath либо соответствующий пакет дистрибутива. Официальная Windows-сборка имеет встроенную поддержку; не требуется искать отдельную BCMath DLL. CLI и веб-сервер могут использовать разные сборки и ini: проверяйте тот процесс, где выполняется приложение. Общая установка — подготовка PHP.

extension_loaded проверяет наличие расширения; function_exists и class_exists — доступность конкретного API. var_dump показывает true/false. Операторы ниже изучаются отдельно: здесь лишь безопасная диагностика без изменения сервера.

Проверка перед запуском современного примера
  1. Текущий процесс PHP
  2. Есть bcmath?
  3. Есть bcround и BcMath\Number?
  4. Если да — доступна ветка PHP 8.4+
Диагностика учебного окруженияСамостоятельный пример
<?php
var_dump(extension_loaded('bcmath'));
var_dump(function_exists('bcround'));
var_dump(class_exists(BcMath\Number::class));
Ожидаемый результат
bool(true)
bool(true)
bool(true)

Вывод относится к проверенному PHP 8.5.11. На PHP 8.2/8.3 первые базовые функции могут существовать, а Number, bcdivmod и три функции округления ещё отсутствуют.

НастройкаДоговор
bcmath.scaleПо умолчанию "0", режим INI_ALL. Определяет scale процедурных функций при null/пропуске. bcscale читает/меняет значение.
Явный scaleЛокально определяет конкретный вызов, удобен для библиотек и workers.
NumberС PHP 8.4, независим от bcmath.scale; масштаб задаётся методом либо вычисляется из входов.

В этой ветке нет отдельной внешней библиотеки, каталога ресурсов или собственных констант режимов. RoundingMode — общий встроенный enum, уже описанный в RoundingMode.

Числовая строка не равна любому тексту из формы

BCMath принимает десятичную точку, необязательный знак и цифры; научную запись E, пробелы, запятую, INF/NAN он не понимает. Официальная грамматика /^[+-]?[0-9]*(\.[0-9]*)?$/ допускает даже отсутствие цифр. В PHP 8.5.11 пустая строка, знак или точка дают ноль: это допустимость низкоуровневого API, а не хорошая проверка цены.

До PHP 8.0 превращение float в строку могло зависеть от региональной десятичной запятой. Сейчас это уже не так, но двоичная погрешность и возможность E-записи остаются. JSON-число могло стать float ещё при json_decode: точное десятичное поле передают строкой по контракту. JSON при интеграции.

$input = ... сохраняет строку; try/catch ловит неверный вход. Затем вводим preg_match: он проверяет формат; \A/\z ограничивают всю строку, [0-9] — цифра, {1,9} — 1–9 повторов, ? делает группу необязательной. Это строгая политика именно нашей формы, не описание всей BCMath-грамматики. Как читать регулярное выражение.

Путь цены из поля
  1. Строка 12.30
  2. Проверяем обязательность, длину и два десятичных места
  3. Только затем bcadd(input,0,2)
  4. Каноническая цена 12.30
Пустой ввод и экспонентаСамостоятельный пример
<?php
echo bcadd('', '0', 2), "\n";
try { bcadd('1e-3', '0', 3); }
catch (ValueError $error) { echo "Экспонента не поддерживается\n"; }
Ожидаемый результат
0.00
Экспонента не поддерживается

Отсутствие ValueError для пустой строки не доказывает, что пользователь заполнил поле.

Теперь вынесем проверку в function normalizedPrice($input) { ... }: вызов передаёт текст локальному параметру, return возвращает строку либо null при отказе. if проверяет условие; ! означает «не», || — «или». foreach по очереди берёт строки списка. условие ? A : B выбирает, что вывести. Определение, вызов и результат; Условия и циклы.

Принять неотрицательную цену в установленном форматеСамостоятельный пример
<?php
function normalizedPrice($input) {
    if (!is_string($input) || strlen($input) > 12 ||
        preg_match('/\A(?:0|[1-9][0-9]{0,8})(?:\.[0-9]{1,2})?\z/', $input) !== 1) {
        return null;
    }
    return bcadd($input, '0', 2);
}
foreach (['12.3', '', '12,30', '1e3', '12.345', '-1', '0'] as $input) {
    $price = normalizedPrice($input);
    echo $price === null ? 'Ошибка' : $price;
    echo "\n";
}
Ожидаемый результат
12.30
Ошибка
Ошибка
Ошибка
Ошибка
Ошибка
0.00

Функция принимает неотрицательную цену с максимум девятью целыми и двумя дробными разрядами; ноль разрешён сознательно. ! отрицает, || означает «или», !==1 требует успешного совпадения, null обозначает отказ. В реальной форме проверяют также HTTP-метод, CSRF и вывод ошибки: приём формы.

Не исправляйте молча «1,234»: это может быть десятичная дробь или тысячи. Не восстанавливайте точный исходник через sprintf после float: это только новое представление уже приближённого значения. Условия валюты/диапазона проверяйте отдельно.

Масштаб, усечение и момент округления

scale считает знаки после точки, а не значащие цифры всей записи. Большинство bc-функций усекают лишнее к нулю. Введём переменную $raw для промежуточного результата; bcround затем выбирает ближайшие сотые. Нужные функции доступны с PHP 8.4. На старших этапах функция не может вернуть цифры, которые предыдущий вызов уже отбросил.

Комиссия по исходным десятичным данным
  1. 19.99 × 0.075
  2. bcmul с scale 5 → 1.49925
  3. bcround до сотых
  4. 1.50; преждевременное усечение дало бы 1.49
Усечение и округление решают разные задачиСамостоятельный пример
<?php
$raw = bcmul('19.99', '0.075', 5);
echo $raw, "\n";
echo bcmul('19.99', '0.075', 2), "\n";
echo bcround($raw, 2), "\n";
Ожидаемый результат
1.49925
1.49
1.50

Произведение конечных дробей имеет не больше суммы их дробных разрядов. Для деления/корня такого простого конечного предела нет: нужен договор допустимой погрешности.

Строки счёта и общий итог могут отличатьсяСамостоятельный пример
<?php
$oneLine = bcround('0.335', 2);
$sumRoundedLines = bcmul($oneLine, '3', 2);
$roundedTotal = bcround(bcmul('0.335', '3', 3), 2);
echo $sumRoundedLines, "\n", $roundedTotal, "\n";
Ожидаемый результат
1.02
1.01

Оба алгоритма точны в своих правилах, но округляют на разных этапах. В заказе надо хранить и объяснять выбранное правило; нельзя произвольно комбинировать уже округлённые строки с другим способом подсчёта итога.

Технический предел scale — 2147483647, но миллиард знаков не является разумной настройкой веб-запроса. Ограничьте длину поля, scale, показатель степени и число операций. Функции не становятся безопасными для произвольных входов лишь из-за слова «точность». Измерять стоимость вычислений.

Все восемь правил RoundingMode

Enum задаёт конечный набор именованных вариантов. Запись RoundingMode::HalfEven выбирает один вариант; RoundingMode::cases() возвращает их список. Четыре Half-режима отличаются только на точной половине, остальные четыре задают направление для любой ненулевой удаляемой части. Каноническая карточка: RoundingMode.

ВариантПравило2.5 / −2.5 до целого
HalfAwayFromZeroБлижайшее; ровно половина от нуля3 / -3
HalfTowardsZeroБлижайшее; ровно половина к нулю2 / -2
HalfEvenБлижайшее; половина к чётной сохраняемой цифре2 / -2
HalfOddБлижайшее; половина к нечётной сохраняемой цифре3 / -3
TowardsZeroВсегда к нулю2 / -2
AwayFromZeroВсегда от нуля при ненулевой удаляемой части3 / -3
NegativeInfinityВ сторону −∞2 / -3
PositiveInfinityВ сторону +∞3 / -2
Один конкретный выбор правила
  1. −2.5
  2. HalfEven: ближайшие целые −2 и −3
  3. При половине выбираем чётное −2
  4. bcround возвращает строку −2
Проверить все режимы на точной половинеСамостоятельный пример
<?php
foreach (RoundingMode::cases() as $mode) {
    echo $mode->name, ': ', bcround('2.5', 0, $mode), ' / ', bcround('-2.5', 0, $mode), "\n";
}
Ожидаемый результат
HalfAwayFromZero: 3 / -3
HalfTowardsZero: 2 / -2
HalfEven: 2 / -2
HalfOdd: 3 / -3
TowardsZero: 2 / -2
AwayFromZero: 3 / -3
NegativeInfinity: 2 / -3
PositiveInfinity: 3 / -2

foreach берёт варианты по одному, ->name читает название. HalfAwayFromZero — default. Это тот же enum, что у round, но bcround требует enum и не принимает старые int-константы PHP_ROUND_*.

Округление цены не является юридическим правилом расчёта налога: требуемую политику выбирает доменная спецификация. Полезное упражнение: замените 2.5 на 2.1. HalfEven и TowardsZero всё ещё совпадут на положительном входе, а HalfAwayFromZero и AwayFromZero уже разойдутся.

Тот же расчёт через Number: что хранит объект

Функции удобны, когда данные уже строки. Number (PHP 8.4+) хранит строковое значение и масштаб вместе, возвращая новое число после каждой операции. new создаёт объект, -> вызывает его метод. В цепочке результат первого метода становится получателем второго. Number не знает, что такое рубль, количество или НДС: это контейнер числа, а не целый класс денег.

Операция без явного scaleПравило Number
add, sub, modМаксимальный scale двух входов.
mulСумма scale входов.
div, sqrtИсходный scale, по необходимости ещё до 10 знаков; лишние нули расширения убираются.
powПоложительная степень: scale основания × показатель. Ноль: 0. Отрицательная: правило расширения как у div.
powmod0.
divmodЧастное 0, остаток — максимум входов.
compareВсе разряды при null.
ceil, floor0.
roundПоложительная precision либо 0.
Объекты при расчёте трёх единиц
  1. price = Number(12.30)
  2. price->mul(3) → отдельный subtotal 36.90
  3. subtotal->add(2.10) → отдельный total 39.00
  4. price по-прежнему 12.30
Один расчёт с сохранением исходной ценыСамостоятельный пример
<?php
$price = new BcMath\Number('12.30');
$subtotal = $price->mul(3);
$total = $subtotal->add('2.10');
echo $price, "\n", $subtotal, "\n", $total, "\n";
Ожидаемый результат
12.30
36.90
39.00

Никакое ООП-обёртывание не делает вычисление автоматически быстрее. Польза здесь — связанное значение/масштаб и локальное правило методов. Для PHP 8.2/8.3 такой же результат дают bcmul и bcadd с явным scale.

Не смешивайте методы с неявным int/float cast. Арифметика Number поддерживает + − * / % **; сравнения == != < <= > >= <=> числовые, === проверяет идентичность. Нулевой Number в bool — false. Подробности и пограничные случаи: BcMath\Number, BcMath\Number::compare.

Упражнение: счёт, возврат и неизрасходованная копейка

Задача: товар стоит 19.90, куплено 3 штуки, доставка 4.30. Получить 64.00, вычесть возврат 19.90 и разделить остаток между тремя получателями без потери копейки. Валюта общая, входы уже проверены; правило распределения — первые участники получают по дополнительной копейке до исчерпания остатка.

Функция splitCents получает сумму и количество людей, а return отдаёт список долей. bcdivmod возвращает две строки — целое частное и остаток; запись [$share, $rest] = ... раскладывает их по переменным. $parts[] = ... добавляет элемент массива; for задаёт старт, условие и шаг счётчика, ++ увеличивает его на один. ?/: выбирают значение по условию, implode соединяет список для вывода. Счётчики здесь малы и безопасно помещаются в int. Циклы и условия.

Точный путь учебного счёта
  1. 19.90 × 3 + 4.30 = 64.00
  2. Возврат 19.90 → 44.10
  3. Перевод единиц: 4410 копеек / 3
  4. Три доли по 1470 → 14.70
Вариант решения без floatСамостоятельный пример
<?php
function splitCents($cents, $people) {
    [$share, $rest] = bcdivmod($cents, (string) $people, 0);
    $parts = [];
    for ($index = 0; $index < $people; $index++) {
        $extra = bccomp((string) $index, $rest, 0) < 0 ? '1' : '0';
        $parts[] = bcdiv(bcadd($share, $extra, 0), '100', 2);
    }
    return $parts;
}
$total = bcadd(bcmul('19.90', '3', 2), '4.30', 2);
$remaining = bcsub($total, '19.90', 2);
echo $total, "\n", $remaining, "\n";
echo implode(', ', splitCents(bcmul($remaining, '100', 0), 3)), "\n";
echo implode(', ', splitCents('1000', 3)), "\n";
Ожидаемый результат
64.00
44.10
14.70, 14.70, 14.70
3.34, 3.33, 3.33

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

Продолжение: сохраните исходную цену, валюту, этап округления и итог операции; обновляйте остаток в транзакции БД. BCMath не обеспечивает конкурентную блокировку, авторизацию или идемпотентность повторного платежного запроса.

Полный API BCMath: выбрать функцию или метод

Все функции и методы официальной ветки находятся ниже. Аналогичные задачи связывают процедурный и объектный API; различия default scale указаны в карточках.

Нужный результатВход
Сумма/разность/произведениеbcadd, bcsub, bcmul
Частное/остаток/обаbcdiv, bcmod, bcdivmod
Сравнение и настройкиbccomp, bcscale
Степень/модуль/кореньbcpow, bcpowmod, bcsqrt
Округлениеbcceil, bcfloor, bcround
Объектное значениеBcMath\Number
Метод NumberНазначение
BcMath\Number::addСложить сумму заказа с доставкой.
BcMath\Number::ceilПолучить ближайшее целое не меньше исходного.
BcMath\Number::compareПроверить числовое равенство или порядок, не привязываясь к идентичности объектов.
BcMath\Number::__constructСоздать проверенное десятичное число из строки или целого.
BcMath\Number::divРазделить число и сохранить достаточные дополнительные разряды в пределах автоматического правила.
BcMath\Number::divmodРазделить количество на полные группы и получить остаток объектами Number.
BcMath\Number::floorПолучить ближайшее целое не больше исходного.
BcMath\Number::modНайти остаток длины после целого количества отрезков.
BcMath\Number::mulУмножить тариф на количество или коэффициент.
BcMath\Number::powВозвести число в целую степень с автоматическим масштабом результата.
BcMath\Number::powmodВычислить модульную степень, не материализуя полную огромную степень.
BcMath\Number::roundПолучить новое число, округлённое до выбранного десятичного разряда.
BcMath\Number::__serializeПодготовить внутренние данные Number для штатного PHP serialize().
BcMath\Number::sqrtПолучить неотрицательный квадратный корень и управлять числом его разрядов.
BcMath\Number::subВычесть возврат, сохранив исходную сумму для журнала.
BcMath\Number::__toStringПолучить исходную десятичную строку для текста или явной передачи в другой интерфейс.
BcMath\Number::__unserializeВосстановить новый Number из состояния, созданного сериализацией.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

bcaddСложить цены, сохранив десятичные разряды.

PHP 4+; nullable scale с 8.0 · bcmath

bcadd(string $num1, string $num2, ?int $scale = null): string

Сложить цены, сохранив десятичные разряды.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. foreach ($items as $item) проходит список; форма $key => $value получает также ключ. [...] создаёт массив; [$a, $b] = ... раскладывает два результата по переменным, $data["value"] читает элемент по ключу. Начало: переменная; Вызов и return.

Часть договораЗначение
num1, num2Левый и правый операнды в десятичной строковой записи.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего.
ВозвратСтрока: сумма.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики.
ВерсияPHP 4+; nullable scale с 8.0
Что происходит в первом опыте
  1. 19.90 и 0.10 — строки
  2. bcadd(..., 2) складывает значения
  3. Возвращает строку 20.00
Две суммы без преобразования в floatСамостоятельный пример
<?php
echo bcadd('19.90', '0.10', 2), "\n";
echo bcadd('999999999999999999999', '1', 0), "\n";
Ожидаемый результат
20.00
1000000000000000000000

Первый результат можно отправить в десятичное поле БД. Второй не помещается в обычный int: кавычки сохраняют все цифры.

Сумма корзины внутри функцииСамостоятельный пример
<?php
function cartSum($prices) {
    $total = '0.00';
    foreach ($prices as $price) {
        $total = bcadd($total, $price, 2);
    }
    return $total;
}
echo cartSum(['12.40', '0.60', '7.00']), "\n";
Ожидаемый результат
20.00

Все цены уже проверены и выражены в одной валюте с двумя знаками. Начальное строковое 0.00 задаёт понятный формат, а явный scale не зависит от стороннего кода.

Практическая граница. При scale 2 промежуточные тысячные теряются на каждом сложении. Если они значимы, храните их до выбранного этапа округления. Большие идентификаторы не нужно складывать лишь потому, что они состоят из цифр.

Соседние инструменты: bcsub, bcround, BcMath\Number::add. Выбор по задаче.

bcsubВычесть возврат или оплату из суммы счёта.

PHP 4+; nullable scale с 8.0 · bcmath

bcsub(string $num1, string $num2, ?int $scale = null): string

Вычесть возврат или оплату из суммы счёта.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. if (условие) выбирает действие; === сравнивает значение и тип, !== проверяет их различие. Начало: переменная; Вызов и return.

Часть договораЗначение
num1, num2Левый и правый операнды в десятичной строковой записи.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего.
ВозвратСтрока: разность num1 − num2.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики.
ВерсияPHP 4+; nullable scale с 8.0
Что происходит в первом опыте
  1. Счёт 50.00
  2. Вычитаем оплату 12.35
  3. Остаток 37.65
Остаток и отрицательная корректировкаСамостоятельный пример
<?php
echo bcsub('50.00', '12.35', 2), "\n";
echo bcsub('0', '0.019', 2), "\n";
Ожидаемый результат
37.65
-0.01

Усечение идёт к нулю: −0.019 превращается в −0.01, а не −0.02. Второе значение показывает, почему scale не равен floor.

Не списывать больше остаткаСамостоятельный пример
<?php
function debit($balance, $amount) {
    if (bccomp($amount, $balance, 2) === 1) {
        return 'Недостаточно средств';
    }
    return bcsub($balance, $amount, 2);
}
echo debit('25.00', '10.20'), "\n";
echo debit('25.00', '30.00'), "\n";
Ожидаемый результат
14.80
Недостаточно средств

Учебные входы неотрицательны и имеют два знака. В БД проверка и списание должны быть одной защищённой транзакцией: арифметика сама не предотвращает две одновременные покупки.

Практическая граница. Порядок операндов существенен. Отрицательный результат допустим математически, но не всегда допустим для остатка товара/баланса. Правила задачи проверяются отдельно.

Соседние инструменты: bcadd, bcround, BcMath\Number::sub. Выбор по задаче.

bcmulПолучить стоимость количества или сумму комиссии.

PHP 4+; nullable scale с 8.0; заполнение нулями по scale с 7.3 · bcmath

bcmul(string $num1, string $num2, ?int $scale = null): string

Получить стоимость количества или сумму комиссии.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. RoundingMode::HalfEven — именованный вариант правила округления, а не строка или вызов. Начало: переменная; Вызов и return.

Часть договораЗначение
num1, num2Левый и правый операнды в десятичной строковой записи.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего.
ВозвратСтрока: произведение.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики.
ВерсияPHP 4+; nullable scale с 8.0; заполнение нулями по scale с 7.3
Что происходит в первом опыте
  1. Тариф 12.35
  2. Умножаем на количество 3
  3. Получаем строку 37.05
Количество и сохранение нулейСамостоятельный пример
<?php
echo bcmul('12.35', '3', 2), "\n";
echo bcmul('4', '5', 2), "\n";
Ожидаемый результат
37.05
20.00

Количество тоже строка. Начиная с PHP 7.3 результат дополняется до scale; в более старых версиях хвостовые нули могли отсутствовать.

Комиссию сначала вычислить, затем округлитьСамостоятельный пример
<?php
$commission = bcmul('19.99', '0.075', 5);
echo $commission, "\n";
echo bcround($commission, 2, RoundingMode::HalfAwayFromZero), "\n";
Ожидаемый результат
1.49925
1.50

PHP 8.4+. 2 + 3 дробных разряда входов дают до пяти у точного произведения. Если сразу использовать scale 2, получится 1.49 и утраченный разряд уже нельзя восстановить округлением.

Практическая граница. Для целых копеек int бывает проще, пока нет переполнения и дробных частей копейки. Умножение длинных строк и большой scale требуют времени и памяти: ограничивайте внешние размеры и измеряйте свой расчёт.

Соседние инструменты: bcdiv, bcround, BcMath\Number::mul. Выбор по задаче.

bcdivРазделить сумму на количество, не переходя к двоичному float.

PHP 4+ · bcmath

bcdiv(string $num1, string $num2, ?int $scale = null): string

Разделить сумму на количество, не переходя к двоичному float.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. if (условие) выбирает действие; === сравнивает значение и тип, !== проверяет их различие. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Начало: переменная; Вызов и return.

Часть договораЗначение
num1Делимое.
num2Делитель; числовой ноль запрещён.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего.
ВозвратЧастное строкой.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики. Деление на ноль → DivisionByZeroError (с PHP 8.0; ранее null).
ВерсияPHP 4+
Что происходит в первом опыте
  1. 10.00 делим на 3
  2. Сохраняем два знака без округления
  3. Возврат 3.33
Деление и знакСамостоятельный пример
<?php
echo bcdiv('10.00', '3', 2), "\n";
echo bcdiv('-10', '3', 0), "\n";
Ожидаемый результат
3.33
-3

Отрицательное частное также усекается к нулю. Это не распределение всей суммы: три раза 3.33 дают 9.99.

Средняя цена и отказ для нулевого количестваСамостоятельный пример
<?php
function averagePrice($total, $count) {
    if (bccomp($count, '0', 0) <= 0) {
        return 'Количество должно быть положительным';
    }
    return bcdiv($total, $count, 4);
}
echo averagePrice('25.00', '8'), "\n";
echo averagePrice('25.00', '0'), "\n";
Ожидаемый результат
3.1250
Количество должно быть положительным

Здесь count уже проверенное целое. Для общего десятичного делителя сравнение со scale 0 непригодно: 0.5 оно считает нулём.

Перехват нулевого делителяСамостоятельный пример
<?php
try { bcdiv('1', '-0.00', 2); }
catch (DivisionByZeroError $error) { echo "Делитель равен нулю\n"; }
Ожидаемый результат
Делитель равен нулю

Разные текстовые формы нуля не обходят математическое ограничение.

Практическая граница. Ограниченный scale не представляет бесконечную периодическую дробь точно. Для распределения копеек понадобятся целое частное и остаток, а не одинаковая усечённая доля.

Соседние инструменты: bcdivmod, bcmul, BcMath\Number::div. Выбор по задаче.

bcmodНайти остаток после целого количества порций, включая дробные исходные величины.

PHP 4+; дробные операнды и scale с 7.2; nullable и DivisionByZeroError с 8.0 · bcmath

bcmod(string $num1, string $num2, ?int $scale = null): string

Найти остаток после целого количества порций, включая дробные исходные величины.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Начало: переменная; Вызов и return.

Часть договораЗначение
num1Делимое; ненулевой остаток имеет его знак.
num2Делитель, не ноль.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего.
ВозвратОстаток строкой.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики. При нулевом делителе DivisionByZeroError.
ВерсияPHP 4+; дробные операнды и scale с 7.2; nullable и DivisionByZeroError с 8.0
Что происходит в первом опыте
  1. 17.55 литра
  2. Четыре ёмкости по 4.2: 16.8
  3. Остаток 0.75
Дробный остаток не равен оператору %Самостоятельный пример
<?php
echo bcmod('17.55', '4.2', 2), "\n";
echo bcmod('-17.55', '4.2', 2), "\n";
Ожидаемый результат
0.75
-0.75

С PHP 7.2 дробные части входов не отбрасываются, тогда же добавлен scale. Оператор % преобразует обычные операнды в целые; fmod работает с float.

Остаток большого счётчика упаковокСамостоятельный пример
<?php
function looseItems($items, $packSize) {
    return bcmod($items, $packSize, 0);
}
echo looseItems('100000000000000000005', '12'), "\n";
try { looseItems('10', '0'); }
catch (DivisionByZeroError $error) { echo "Размер упаковки не может быть нулём\n"; }
Ожидаемый результат
9
Размер упаковки не может быть нулём

Для целых количеств scale 0 достаточен; входной размер ещё нужно проверить на положительность.

Практическая граница. Отрицательный остаток не является автоматически номером циклической ячейки 0…m−1. Для положительного m нормализуют при необходимости bcmod(bcadd(r,m),m); это отдельное правило задачи.

Соседние инструменты: bcdivmod, bcpowmod, BcMath\Number::mod. Выбор по задаче.

bcdivmodПолучить целое частное и остаток одним вызовом: например, разделить 1000 копеек на три части.

PHP 8.4+ · bcmath

bcdivmod(string $num1, string $num2, ?int $scale = null): array

Получить целое частное и остаток одним вызовом: например, разделить 1000 копеек на три части.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. [...] создаёт массив; [$a, $b] = ... раскладывает два результата по переменным, $data["value"] читает элемент по ключу. Начало: переменная; Вызов и return.

Часть договораЗначение
num1, num2Делимое и ненулевой делитель строками.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего. Здесь он относится к остатку: частное всегда целое.
ВозвратИндексированный массив [частное-строка, остаток-строка]. Частное усекается к нулю; знак ненулевого остатка совпадает с делимым.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики. Ноль в num2 → DivisionByZeroError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. 1000 копеек / 3
  2. Целое частное 333
  3. Остаток 1 копейка
Два результатаСамостоятельный пример
<?php
[$share, $rest] = bcdivmod('1000', '3', 0);
echo $share, "\n", $rest, "\n";
Ожидаемый результат
333
1

Квадратные скобки слева присваивают первый и второй элементы двум переменным. Полученные строки сохраняют точность.

Распределение остатка без потери копейкиСамостоятельный пример
<?php
[$share, $rest] = bcdivmod('1000', '3', 0);
$parts = [$share, $share, $share];
$parts[0] = bcadd($parts[0], $rest, 0);
echo implode(', ', $parts), "\n";
echo bcadd(bcadd($parts[0], $parts[1], 0), $parts[2], 0), "\n";
Ожидаемый результат
334, 333, 333
1000

Для именно трёх долей и остатка 1 выбран первый участник. В общей системе надо явно задать порядок распределения нескольких копеек, а не отдавать весь остаток одному без договора.

Частное не получает дробных знаковСамостоятельный пример
<?php
[$q, $r] = bcdivmod('-17.55', '4.2', 1);
echo $q, "\n", $r, "\n";
Ожидаемый результат
-4
-0.7

Истинный остаток −0.75 усечён до −0.7: при недостаточном scale равенство a = q*b+r перестаёт быть точным.

Практическая граница. Для точного восстановления входа выбирайте достаточный scale остатка. На PHP 8.2/8.3 вызывайте bcdiv(a,b,0) и bcmod(a,b,scale) отдельно.

Соседние инструменты: bcdiv, bcmod, BcMath\Number::divmod. Выбор по задаче.

bccompСравнить значения десятичных строк, даже если их текстовый формат различается.

PHP 4+ · bcmath

bccomp(string $num1, string $num2, ?int $scale = null): int

Сравнить значения десятичных строк, даже если их текстовый формат различается.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. if (условие) выбирает действие; === сравнивает значение и тип, !== проверяет их различие. Начало: переменная; Вызов и return.

Часть договораЗначение
num1, num2Левое и правое сравниваемые числа.
scaleГлубина сравнения после точки, 0…2147483647; лишние знаки игнорируются. null берёт bcscale()/INI.
Возвратint: −1 (левое меньше), 0 (равны в выбранном масштабе), 1 (левое больше).
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики.
ВерсияPHP 4+
Что происходит в первом опыте
  1. 12.345 и 12.349
  2. Сравнение в scale 2
  3. Оба 12.34 → результат int 0
Равенство зависит от масштаба сравненияСамостоятельный пример
<?php
var_dump(bccomp('12.345', '12.349', 2));
var_dump(bccomp('12.345', '12.349', 3));
var_dump(bccomp('-0.00', '+0.000', 3));
Ожидаемый результат
int(0)
int(-1)
int(0)

На проверенном PHP 8.5.11 отрицательная запись нуля равна положительной. Старые обсуждения ошибки нельзя переносить на современный результат.

Порог бесплатной доставкиСамостоятельный пример
<?php
function deliveryLabel($total) {
    if (bccomp($total, '1500.00', 2) >= 0) {
        return 'Бесплатно';
    }
    return 'По тарифу';
}
echo deliveryLabel('1499.99'), "\n";
echo deliveryLabel('1500.0'), "\n";
Ожидаемый результат
По тарифу
Бесплатно

Уже проверенные суммы имеют не более двух знаков. Результат сравнения числовой: проверка if (bccomp(...)) означала бы «не равны», а не «больше».

Практическая граница. Строковое === сравнивает запись, а преобразование в float теряет точность. Выберите масштаб по данным; для Number::compare(null) используются все разряды.

Соседние инструменты: BcMath\Number::compare, bcscale. Выбор по задаче.

bcscaleЗадать значение по умолчанию для процедурных вычислений или узнать текущее.

PHP 4+; getter и возврат старого значения с 7.3; nullable с 8.0 · bcmath

bcscale(?int $scale = null): int

Задать значение по умолчанию для процедурных вычислений или узнать текущее.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
scalenull/пропуск: прочитать. Целое 0…2147483647: установить для последующих bc-функций с неуказанным/null scale.
ВозвратПри установке — предыдущее значение, при чтении — текущее.
ОтказыНедопустимый диапазон → ValueError; неподходящий тип → TypeError.
ВерсияPHP 4+; getter и возврат старого значения с 7.3; nullable с 8.0

До PHP 7.3 параметр был обязательным, а setter возвращал true. bcmath.scale по умолчанию 0 и имеет режим INI_ALL.

Что происходит в первом опыте
  1. Сначала задаём scale 2
  2. Следующее деление без scale
  3. 1 / 8 → 0.12
Прочитать и установитьСамостоятельный пример
<?php
bcscale(2);
echo bcscale(), "\n";
echo bcdiv('1', '8'), "\n";
echo bcscale(4), "\n";
echo bcdiv('1', '8'), "\n";
Ожидаемый результат
2
0.12
2
0.1250

Setter вернул прежние 2, затем вычисление использовало 4. Отдельный процесс примера не меняет настройки других запусков.

Восстановить настройку после старого модуляСамостоятельный пример
<?php
bcscale(2);
function legacyReport() {
    $old = bcscale(4);
    try { return bcdiv('1', '8'); }
    finally { bcscale($old); }
}
echo legacyReport(), "\n";
echo bcscale(), "\n";
echo (new BcMath\Number('1'))->div(8), "\n";
Ожидаемый результат
0.1250
2
0.125

finally восстанавливает настройку и при return/исключении. Последний вызов PHP 8.4+ показывает независимость Number от глобального scale.

Практическая граница. Скрытая настройка усложняет библиотеки и долгоживущие workers: предпочтительны явные scale. Это не региональная точность, не количество значащих цифр и не правило округления.

Соседние инструменты: bcdiv, BcMath\Number. Выбор по задаче.

bcpowВозвести десятичное основание в целую степень: накопление коэффициента за несколько периодов.

PHP 4+ · bcmath

bcpow(string $num, string $exponent, ?int $scale = null): string

Возвести десятичное основание в целую степень: накопление коэффициента за несколько периодов.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Начало: переменная; Вызов и return.

Часть договораЗначение
numДесятичное основание.
exponentЦелочисленное значение строкой, без ненулевой дробной части. Диапазон платформы как минимум −2147483648…2147483647; в реализации используется C long, поэтому его предел нельзя автоматически приравнять к PHP_INT_MAX на любой ОС.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего.
ВозвратСтепень строкой; отрицательный показатель означает обратное значение.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики. Дробный/слишком большой показатель → ValueError. 0 в отрицательной степени → DivisionByZeroError с 8.4.
ВерсияPHP 4+
Что происходит в первом опыте
  1. Коэффициент 1.05
  2. Два периода: 1.05 × 1.05
  3. Результат 1.1025
Положительная, нулевая и отрицательная степеньСамостоятельный пример
<?php
echo bcpow('1.05', '2', 4), "\n";
echo bcpow('2', '0', 2), "\n";
echo bcpow('2', '-3', 3), "\n";
Ожидаемый результат
1.1025
1.00
0.125

Показатель 0 даёт единицу; отрицательный не означает отрицательный результат.

Расчёт по согласованному коэффициентуСамостоятельный пример
<?php
function projectedTotal($initial, $factor, $periods) {
    return bcmul($initial, bcpow($factor, $periods, 6), 6);
}
echo projectedTotal('1000.00', '1.02', '3'), "\n";
try { bcpow('9', '0.5', 2); }
catch (ValueError $error) { echo "Показатель должен быть целым\n"; }
Ожидаемый результат
1061.208000
Показатель должен быть целым

Это арифметическая модель с постоянным коэффициентом, не прогноз. Для квадратного корня есть bcsqrt; прежнее молчаливое усечение дробного показателя заменено ValueError с PHP 8.0.

Новая ошибка нулевого основанияСамостоятельный пример
<?php
try { bcpow('0', '-1', 2); }
catch (DivisionByZeroError $error) { echo "Обратного нулю нет\n"; }
Ожидаемый результат
Обратного нулю нет

PHP 8.4+: раньше этот случай возвращал 0. Масштаб результата заполняется нулями с PHP 7.3.

Практическая граница. Размер результата быстро растёт с показателем. Для огромного показателя по модулю используйте bcpowmod, а не сначала полную степень. Оператор ^ в PHP — XOR, степень записывается **.

Соседние инструменты: bcpowmod, bcsqrt, BcMath\Number::pow. Выбор по задаче.

bcpowmodВычислить остаток большой степени, не создавая сначала всю огромную степень.

PHP 5+ · bcmath

bcpowmod(string $num, string $exponent, string $modulus, ?int $scale = null): string

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

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Начало: переменная; Вызов и return.

Часть договораЗначение
numЦелое основание строкой.
exponentНеотрицательное целое строкой.
modulusНенулевое целое строкой.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего.
ВозвратСтрока: num в степени exponent по modulus.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики. Ненулевая дробная часть любого из трёх чисел или отрицательный exponent → ValueError; modulus 0 → DivisionByZeroError.
ВерсияPHP 5+
Что происходит в первом опыте
  1. 7 в степени 4
  2. Вычисление с сокращением по модулю 13
  3. Остаток 9
Модульная степеньСамостоятельный пример
<?php
echo bcpowmod('7', '4', '13', 0), "\n";
echo bcpowmod('-7', '3', '13', 2), "\n";
Ожидаемый результат
9
-5.00

Алгоритм быстрого возведения сокращает промежуточные результаты. Отрицательное основание может дать отрицательный остаток; это не автоматическая нормализация 0…m−1.

Большой показатель в модели циклического индексаСамостоятельный пример
<?php
echo bcpowmod('2', '1000', '97', 0), "\n";
try { bcpowmod('2', '-1', '97', 0); }
catch (ValueError $error) { echo "Отрицательный показатель запрещён\n"; }
Ожидаемый результат
36
Отрицательный показатель запрещён

Пример иллюстрирует модульную арифметику. Это не готовая криптография: здесь не обещаются постоянное время исполнения, безопасные ключи или протокол.

Практическая граница. Для целых положительных входов соответствует bcmod(bcpow(...),modulus), но избегает роста полной степени. Не путайте отрицательную степень с модульным обратным: данный API её не вычисляет. С PHP 8.0 отрицательный exponent/нулевой modulus дают исключения вместо false; scale допускает null.

Соседние инструменты: bcpow, bcmod, BcMath\Number::powmod. Выбор по задаче.

bcsqrtПолучить квадратный корень для расчёта стороны или нормирования величины.

PHP 4+ · bcmath

bcsqrt(string $num, ?int $scale = null): string

Получить квадратный корень для расчёта стороны или нормирования величины.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Начало: переменная; Вызов и return.

Часть договораЗначение
numНеотрицательная десятичная строка.
scaleЧисло знаков после точки: целое от 0 до 2147483647, технический предел не обещает доступной памяти. Явный scale усекает лишние дробные разряды к нулю и дополняет недостающие нулями. null/пропуск: текущее bcscale(), исходно bcmath.scale (обычно 0). Это не округление до ближайшего.
ВозвратНеотрицательный квадратный корень строкой.
ОтказыНеверная десятичная запись или scale вне диапазона → ValueError; несовместимый тип → TypeError. Операнды передаются строками, без пробелов, запятой, E-экспоненты, INF/NAN. Данные формы проверяют строже допустимой BCMath-грамматики. Отрицательный num → ValueError.
ВерсияPHP 4+
Что происходит в первом опыте
  1. Площадь 6.25
  2. bcsqrt с двумя знаками
  3. Сторона 2.50
Точный и бесконечный кореньСамостоятельный пример
<?php
echo bcsqrt('6.25', 2), "\n";
echo bcsqrt('3', 5), "\n";
Ожидаемый результат
2.50
1.73205

Первый корень представим точно. Второй ограничен пятью знаками: произвольная точность не означает бесконечную память.

Проверка площади перед корнемСамостоятельный пример
<?php
function squareSide($area) {
    return bcsqrt($area, 3);
}
echo squareSide('12.25'), "\n";
try { squareSide('-1'); }
catch (ValueError $error) { echo "Площадь не может быть отрицательной\n"; }
Ожидаемый результат
3.500
Площадь не может быть отрицательной

Для отрицательного реального числа квадратный корень вне действительной области; комплексные числа BCMath не представляет.

Практическая граница. Для округления корня до заданного разряда нужен запас вычисленных цифр и согласованная политика погрешности. С PHP 8.0 плохая строка/отрицательное число — ValueError вместо warning; отрицательный scale больше не превращается молча в 0.

Соседние инструменты: bcpow, BcMath\Number::sqrt, bcround. Выбор по задаче.

bcceilОкруглить десятичную строку до целого в сторону +∞.

PHP 8.4+ · bcmath

bcceil(string $num): string

Округлить десятичную строку до целого в сторону +∞.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. Начало: переменная; Вызов и return.

Часть договораЗначение
numЧисло в десятичной строковой записи; scale не передаётся.
ВозвратСтрока целого числа без дробной части.
ОтказыПлохая строка → ValueError; несовместимый тип → TypeError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Вход 2.1
  2. bcceil выбирает целое в сторону +∞
  3. Возврат 3
Положительный и отрицательный входСамостоятельный пример
<?php
echo bcceil('2.1'), "\n";
echo bcceil('-2.1'), "\n";
Ожидаемый результат
3
-2

Направление выбирается на числовой прямой. «Вверх» не означает увеличить модуль отрицательного числа.

Необходимое количество упаковокСамостоятельный пример
<?php
$ratio = bcdiv('17', '4', 2);
echo bcceil($ratio), "\n";
Ожидаемый результат
5

17 штук не помещаются в четыре упаковки по четыре. Здесь частное 4.25 конечно и scale 2 сохраняет его полностью; произвольно усечённое почти целое частное могло бы дать неверное ceil. Для целых количеств надёжнее bcdivmod плюс проверка остатка.

Практическая граница. Не зависит от bcscale. Для двух знаков после точки используйте bcround с соответствующим RoundingMode. Не переводите результат в int без проверки диапазона.

Соседние инструменты: bcfloor, bcround, BcMath\Number::ceil. Выбор по задаче.

bcfloorОкруглить десятичную строку до целого в сторону −∞.

PHP 8.4+ · bcmath

bcfloor(string $num): string

Округлить десятичную строку до целого в сторону −∞.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. Начало: переменная; Вызов и return.

Часть договораЗначение
numЧисло в десятичной строковой записи; scale не передаётся.
ВозвратСтрока целого числа без дробной части.
ОтказыПлохая строка → ValueError; несовместимый тип → TypeError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Вход 2.1
  2. bcfloor выбирает целое в сторону −∞
  3. Возврат 2
Положительный и отрицательный входСамостоятельный пример
<?php
echo bcfloor('2.1'), "\n";
echo bcfloor('-2.1'), "\n";
Ожидаемый результат
2
-3

Направление выбирается на числовой прямой. «Вверх» не означает увеличить модуль отрицательного числа.

Нижняя граница интервала измеренияСамостоятельный пример
<?php
function lowerBucket($measurement) { return bcfloor($measurement); }
echo lowerBucket('3.8'), "\n";
echo lowerBucket('-0.2'), "\n";
Ожидаемый результат
3
-1

Величины принадлежат интервалам [3,4) и [−1,0). Усечение к нулю ошибочно поместило бы −0.2 в другой интервал.

Практическая граница. Не зависит от bcscale. Для двух знаков после точки используйте bcround с соответствующим RoundingMode. Не переводите результат в int без проверки диапазона.

Соседние инструменты: bcceil, bcround, BcMath\Number::floor. Выбор по задаче.

bcroundОкруглить точное десятичное значение по явно выбранному правилу.

PHP 8.4+ · bcmath

bcround(string $num, int $precision = 0, RoundingMode $mode = RoundingMode::HalfAwayFromZero): string

Округлить точное десятичное значение по явно выбранному правилу.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. RoundingMode::HalfEven — именованный вариант правила округления, а не строка или вызов. Начало: переменная; Вызов и return.

Часть договораЗначение
numДесятичная строка.
precision0 — единицы, 2 — сотые, −1 — десятки, −2 — сотни. Это число десятичных мест, не общее количество значащих цифр.
modeОдин из восьми вариантов RoundingMode. По умолчанию ближайшее, при половине — от нуля. Старые PHP_ROUND_* int-константы здесь не принимаются.
ВозвратСтрока с округлённым числом; при положительной precision дополняется нулями.
ОтказыПлохая строка → ValueError. В реализации 8.5.11 положительная precision ограничена 2147483647 (превышение → ValueError), отрицательная помещается в int PHP. Manual также указывает неверный mode → ValueError, но публичная типизированная сигнатура при int/чужом enum даёт TypeError; корректные варианты RoundingMode замкнуты.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. 12.345
  2. precision 2 и HalfAwayFromZero
  3. 12.35
Сотые, десятки и добавление нулейСамостоятельный пример
<?php
echo bcround('12.345', 2), "\n";
echo bcround('126', -1), "\n";
echo bcround('2.5', 3), "\n";
Ожидаемый результат
12.35
130
2.500

Знак precision указывает сторону от десятичной точки. В отличие от scale округление учитывает удаляемую часть.

Половина и строго типизированное правилоСамостоятельный пример
<?php
echo bcround('2.345', 2, RoundingMode::HalfEven), "\n";
echo bcround('-2.345', 2, RoundingMode::HalfAwayFromZero), "\n";
try { bcround('1.5', 0, PHP_ROUND_HALF_UP); }
catch (TypeError $error) { echo "Нужен вариант RoundingMode\n"; }
Ожидаемый результат
2.34
-2.35
Нужен вариант RoundingMode

HalfEven выбирает чётную последнюю сохраняемую цифру при точной половине. Режим обязан совпадать с договором расчёта; один режим не универсально «правильнее» другого.

Плохая запись и отрицательный scale — разные отказыСамостоятельный пример
<?php
try { bcround('12,30', 2); }
catch (ValueError $error) { echo "Неверная запись числа\n"; }
try { bcadd('1', '2', -1); }
catch (ValueError $error) { echo "Отрицательный scale запрещён\n"; }
echo bcround('126', -1), "\n";
Ожидаемый результат
Неверная запись числа
Отрицательный scale запрещён
130

Отрицательная precision у округления полезна и разрешена, отрицательный scale у арифметики — ошибка. Это два разных параметра.

Практическая граница. PHP 8.4+. На 8.2/8.3 встроенного bcround нет: не превращайте строку во float ради round; применяйте проверенную decimal/money-библиотеку с нужной политикой. Очень большая precision требует памяти; ограничьте её диапазоном задачи.

Соседние инструменты: RoundingMode, bcceil, bcfloor, BcMath\Number::round. Выбор по задаче.

BcMath\NumberХранить точное десятичное значение вместе с его масштабом и получать новые числа при вычислениях.

PHP 8.4+ · bcmath

final readonly class BcMath\Number implements Stringable

Хранить точное десятичное значение вместе с его масштабом и получать новые числа при вычислениях.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
valueПубличное readonly string-свойство: десятичное значение.
scaleПубличное readonly int-свойство: количество знаков после точки.
final / readonlyНаследование и изменение свойств запрещены. Это встроенный неизменяемый объект значения, а не запись баланса в БД.
StringableПоддерживает строковое представление; арифметические/сравнительные операторы перегружены именно этим встроенным классом.
ВозвратМетоды вычислений создают новый Number. Результат может отличаться по scale; bcscale()/INI не участвуют.
ОтказыИзменение readonly свойства → Error; ошибки конкретных входов описаны у методов.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. price: Number 12.30, scale 2
  2. price->mul(3) создаёт другой Number
  3. total 36.90; price остаётся 12.30
Цена сохраняется, итог создаётся отдельноСамостоятельный пример
<?php
$price = new BcMath\Number('12.30');
$total = $price->mul(3);
echo $price->value, " / ", $price->scale, "\n";
echo $total->value, " / ", $total->scale, "\n";
Ожидаемый результат
12.30 / 2
36.90 / 2

Объект берёт на себя десятичное представление, но не хранит валюту, ставку налога или смысл «за штуку». Эти сведения остаются частью модели приложения.

Краткая запись и сохранение старого значенияСамостоятельный пример
<?php
$price = new BcMath\Number('5.25');
$before = $price;
$total = $price * 2 + '0.50';
$price += '1.00';
echo $total, "\n", $before, "\n", $price, "\n";
Ожидаемый результат
11.00
5.25
6.25

+ − * / % ** соответствуют методам с scale null. += присваивает переменной новый объект; прежнее число не меняется. Это специальная возможность Number, а не правило для любого пользовательского класса.

Равенство чисел, идентичность и нольСамостоятельный пример
<?php
$a = new BcMath\Number('2.00');
$b = new BcMath\Number('2');
var_dump($a == $b, $a === $b, $a->compare($b) === 0);
var_dump((bool) new BcMath\Number('0.00'));
try { $a->value = '3'; }
catch (Error $error) { echo "Значение нельзя переписать\n"; }
Ожидаемый результат
bool(true)
bool(false)
bool(true)
bool(false)
Значение нельзя переписать

== сравнивает числа; === для объектов требует тот же экземпляр. Преобразование Number нуля в bool даёт false — это специальная реализация класса, не общая ложность объектов.

Практическая граница. Поиск нуля через if($number) отличается от проверки строки "0.00". В арифметике с обычными десятичными строками без объекта PHP может выбрать float: нужен Number хотя бы с одной стороны. Для явной точности удобнее методы, а для обычного PHP 8.2/8.3 — bc-функции.

Соседние инструменты: BcMath\Number::__construct, BcMath\Number::compare, bcadd, bcscale. Выбор по задаче.

BcMath\Number::__constructСоздать проверенное десятичное число из строки или целого.

PHP 8.4+ · bcmath

new BcMath\Number(string|int $num)

Создать проверенное десятичное число из строки или целого.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. declare(strict_types=1) включает строгую передачу скалярных аргументов в этом файле. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
numint даёт scale 0; строка разбирается, scale равен количеству её дробных разрядов, включая хвостовые нули. Number не входит в контракт самого конструктора.
Возвратnew возвращает созданный Number; сам конструктор не имеет возвращаемого типа.
ОтказыНеправильная строка → ValueError; float при strict_types=1 → TypeError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Строка +0012.300
  2. Убираем лишний плюс и ведущие нули
  3. value 12.300 и scale 3
Запись и числовой масштабСамостоятельный пример
<?php
$amount = new BcMath\Number('+0012.300');
$count = new BcMath\Number(12);
echo $amount->value, ':', $amount->scale, "\n";
echo $count->value, ':', $count->scale, "\n";
Ожидаемый результат
12.300:3
12:0

Исходный текст нормализуется. scale 3 не доказывает измерительную точность или валюту; это число хранимых знаков.

Не принимать запятую и float молчаСамостоятельный пример
<?php
declare(strict_types=1);
try { new BcMath\Number('12,30'); }
catch (ValueError $error) { echo "Нужна десятичная точка\n"; }
try { new BcMath\Number(12.3); }
catch (TypeError $error) { echo "Передайте исходную строку\n"; }
Ожидаемый результат
Нужна десятичная точка
Передайте исходную строку

Нестрогие скалярные преобразования не делают float точным. Для копирования Number обычно достаточно присвоить тот же неизменяемый объект; при необходимости можно создать новый из value.

Практическая граница. Конструктор подтверждает синтаксис BCMath, но не правила цены. Пустая строка и один знак в текущем PHP превращаются в ноль, поэтому обязательность и формат внешнего поля нужно проверять до new.

Соседние инструменты: BcMath\Number, BcMath\Number::__serialize. Выбор по задаче.

BcMath\Number::addСложить сумму заказа с доставкой.

PHP 8.4+ · bcmath

Number::add(Number|string|int $num, ?int $scale = null): Number

Сложить сумму заказа с доставкой.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
numДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError.
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет.
Автоматический scaleМаксимум масштабов двух входов.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше.
ОтказыПлохая строка или недопустимый scale → ValueError; несовместимый тип → TypeError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Сумма 12.30
  2. Добавляем 0.125
  3. Новый результат 12.425, scale 3
Минимальное действие и масштаб результатаСамостоятельный пример
<?php
$amount = new BcMath\Number('12.30');
$result = $amount->add('0.125');
echo $result, ':', $result->scale, "\n";
echo $amount, "\n";
Ожидаемый результат
12.425:3
12.30

Значение value — десятичная строка, а scale — число знаков после точки. Каждый вход сохраняет собственный масштаб.

Условия реальной операцииСамостоятельный пример
<?php
function withShipping($subtotal, $shipping) {
    return $subtotal->add($shipping, 2);
}
echo withShipping(new BcMath\Number('24.50'), '3.70'), "\n";
echo (new BcMath\Number('1.999'))->add('0', 2), "\n";
Ожидаемый результат
28.20
1.99

Последующие вычисления работают с новым результатом. Явный scale ограничивает разряды, а отказ нулевого делителя, если он используется, обрабатывается отдельно.

Практическая граница. Не путайте уменьшение scale с округлением. Новый результат нужно сохранить; вызов $amount->add(...) сам по себе не меняет $amount.

Соседние инструменты: bcadd, BcMath\Number::sub, BcMath\Number::round. Выбор по задаче.

BcMath\Number::subВычесть возврат, сохранив исходную сумму для журнала.

PHP 8.4+ · bcmath

Number::sub(Number|string|int $num, ?int $scale = null): Number

Вычесть возврат, сохранив исходную сумму для журнала.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
numДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError.
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет.
Автоматический scaleМаксимум масштабов двух входов.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше.
ОтказыПлохая строка или недопустимый scale → ValueError; несовместимый тип → TypeError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Сумма 20.00
  2. Возврат 3.125
  3. Новый остаток 16.875
Минимальное действие и масштаб результатаСамостоятельный пример
<?php
$amount = new BcMath\Number('20.00');
echo $amount->sub('3.125'), "\n";
echo $amount, "\n";
Ожидаемый результат
16.875
20.00

Значение value — десятичная строка, а scale — число знаков после точки. Каждый вход сохраняет собственный масштаб.

Условия реальной операцииСамостоятельный пример
<?php
function remaining($amount, $refund) {
    return $amount->sub($refund, 2);
}
echo remaining(new BcMath\Number('15.50'), 4), "\n";
echo remaining(new BcMath\Number('1.00'), '2.00'), "\n";
Ожидаемый результат
11.50
-1.00

Последующие вычисления работают с новым результатом. Явный scale ограничивает разряды, а отказ нулевого делителя, если он используется, обрабатывается отдельно.

Практическая граница. Отрицательный ответ допустим API; запрет переплаты/перевозврата — отдельный инвариант приложения. Неизменяемый объект не заменяет транзакцию БД.

Соседние инструменты: bcsub, BcMath\Number::add, BcMath\Number::round. Выбор по задаче.

BcMath\Number::mulУмножить тариф на количество или коэффициент.

PHP 8.4+ · bcmath

Number::mul(Number|string|int $num, ?int $scale = null): Number

Умножить тариф на количество или коэффициент.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
numДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError.
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет.
Автоматический scaleСумма масштабов двух входов; выход за допустимый масштаб → ValueError.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше.
ОтказыПлохая строка или недопустимый scale → ValueError; несовместимый тип → TypeError. Автоматический scale также должен оставаться в диапазоне.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Тариф 2.50, scale 2
  2. Коэффициент 1.2, scale 1
  3. Результат 3.000, scale 3
Минимальное действие и масштаб результатаСамостоятельный пример
<?php
$tariff = new BcMath\Number('2.50');
$result = $tariff->mul('1.2');
echo $result, ':', $result->scale, "\n";
Ожидаемый результат
3.000:3

Значение value — десятичная строка, а scale — число знаков после точки. Каждый вход сохраняет собственный масштаб.

Условия реальной операцииСамостоятельный пример
<?php
function lineTotal($price, $quantity) { return $price->mul($quantity, 2); }
echo lineTotal(new BcMath\Number('7.35'), 3), "\n";
echo (new BcMath\Number('19.99'))->mul('0.075')->round(2), "\n";
Ожидаемый результат
22.05
1.50

Последующие вычисления работают с новым результатом. Явный scale ограничивает разряды, а отказ нулевого делителя, если он используется, обрабатывается отдельно.

Практическая граница. Автоматический scale сохраняет все разряды конечного произведения, но растёт при длинной цепочке умножений. Округляйте на согласованных границах и ограничивайте число/размер входов.

Соседние инструменты: bcmul, BcMath\Number::div, BcMath\Number::round. Выбор по задаче.

BcMath\Number::modНайти остаток длины после целого количества отрезков.

PHP 8.4+ · bcmath

Number::mod(Number|string|int $num, ?int $scale = null): Number

Найти остаток длины после целого количества отрезков.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
numДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError.
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет.
Автоматический scaleМаксимум масштабов двух входов.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше.
ОтказыПлохая строка или недопустимый scale → ValueError; несовместимый тип → TypeError. Делитель 0 → DivisionByZeroError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Длина 17.55
  2. Отрезки по 4.2
  3. Остаток 0.75, scale 2
Минимальное действие и масштаб результатаСамостоятельный пример
<?php
$length = new BcMath\Number('17.55');
$rest = $length->mod('4.2');
echo $rest, ':', $rest->scale, "\n";
echo $length->mod('4.2', 1), "\n";
Ожидаемый результат
0.75:2
0.7

Значение value — десятичная строка, а scale — число знаков после точки. Каждый вход сохраняет собственный масштаб.

Условия реальной операцииСамостоятельный пример
<?php
echo (new BcMath\Number('-17.55'))->mod('4.2'), "\n";
try { (new BcMath\Number('8'))->mod(0); }
catch (DivisionByZeroError $error) { echo "Нулевой размер отрезка\n"; }
Ожидаемый результат
-0.75
Нулевой размер отрезка

Последующие вычисления работают с новым результатом. Явный scale ограничивает разряды, а отказ нулевого делителя, если он используется, обрабатывается отдельно.

Практическая граница. Ненулевой остаток имеет знак исходного числа, а не делителя. Перегруженный % для Number сохраняет десятичное поведение, в отличие от обычного % с простыми числовыми строками.

Соседние инструменты: bcmod, BcMath\Number::divmod, BcMath\Number::round. Выбор по задаче.

BcMath\Number::divРазделить число и сохранить достаточные дополнительные разряды в пределах автоматического правила.

PHP 8.4+ · bcmath

Number::div(Number|string|int $num, ?int $scale = null): Number

Разделить число и сохранить достаточные дополнительные разряды в пределах автоматического правила.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
numДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError. Делитель не должен быть нулём.
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет.
Автоматическое правилоОт scale делимого до scale делимого + 10. Расширение только по необходимости; хвостовые нули расширенной части удаляются, но не ниже исходного scale. Масштаб делителя не задаёт нижнюю границу.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше.
ОтказыНулевой делитель → DivisionByZeroError. Плохая строка, заданный/вычисленный scale вне диапазона → ValueError; несовместимый тип → TypeError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. 1.00, исходный scale 2
  2. Деление на 3
  3. 0.333333333333, scale 12
Конечная и периодическая дробьСамостоятельный пример
<?php
$one = new BcMath\Number('1.00');
$third = $one->div(3);
$eighth = $one->div(8);
echo $third, ':', $third->scale, "\n";
echo $eighth, ':', $eighth->scale, "\n";
Ожидаемый результат
0.333333333333:12
0.125:3

Периодическая дробь дошла до предела +10. Для восьмой части понадобился только один дополнительный разряд.

Очень малая величина требует явной точностиСамостоятельный пример
<?php
$one = new BcMath\Number('1');
echo $one->div('2000000000000'), "\n";
echo $one->div('2000000000000', 13), "\n";
echo (new BcMath\Number('10.00'))->div(3, 2), "\n";
Ожидаемый результат
0
0.0000000000005
3.33

Автоматика не бесконечна: ненулевое частное может стать нулём. Последний расчёт показывает явное усечение до сотых, а не округление.

Практическая граница. Автоматический +10 — договор API, не универсальная гарантия требуемой погрешности. Для денег/измерений выбирайте масштаб по задаче, а для распределения всей суммы используйте divmod.

Соседние инструменты: bcdiv, BcMath\Number::divmod, BcMath\Number::sqrt. Выбор по задаче.

BcMath\Number::divmodРазделить количество на полные группы и получить остаток объектами Number.

PHP 8.4+ · bcmath

Number::divmod(Number|string|int $num, ?int $scale = null): array

Разделить количество на полные группы и получить остаток объектами Number.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. [...] создаёт массив; [$a, $b] = ... раскладывает два результата по переменным, $data["value"] читает элемент по ключу. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
numДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError. Ненулевой делитель.
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет. Относится к остатку.
Автоматическое правилоЧастное всегда scale 0. Остаток получает максимум масштабов входов.
ВозвратМассив [новый Number частного, новый Number остатка]; частное усечено к нулю.
ОтказыValueError для плохой строки/scale, DivisionByZeroError для нуля, TypeError для несовместимого типа.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. 17.55 / 4.2
  2. Целое частное 4 (scale 0)
  3. Остаток 0.75 (scale 2)
Прочитать оба результатаСамостоятельный пример
<?php
[$q, $r] = (new BcMath\Number('17.55'))->divmod('4.2');
echo $q, ':', $q->scale, "\n";
echo $r, ':', $r->scale, "\n";
Ожидаемый результат
4:0
0.75:2

Два объекта независимы от исходного; каждое имеет собственный масштаб.

Количество полных коробок и остатокСамостоятельный пример
<?php
function packing($items, $size) {
    [$boxes, $loose] = $items->divmod($size);
    return 'Коробки: ' . $boxes . '; отдельно: ' . $loose;
}
echo packing(new BcMath\Number('53'), 12), "\n";
[$q, $r] = (new BcMath\Number('-17.55'))->divmod('4.2', 1);
echo $q, ' / ', $r, "\n";
Ожидаемый результат
Коробки: 4; отдельно: 5
-4 / -0.7

Точка соединяет текст и строковое представление Number. Во второй строке недостаточный scale остатка разрушает точное восстановление исходного делимого.

Практическая граница. Это не пара «полное десятичное частное и остаток»: частное целое. Проверьте положительность размера коробки; нулевой размер API отклоняет сам.

Соседние инструменты: bcdivmod, BcMath\Number::div, BcMath\Number::mod. Выбор по задаче.

BcMath\Number::compareПроверить числовое равенство или порядок, не привязываясь к идентичности объектов.

PHP 8.4+ · bcmath

Number::compare(Number|string|int $num, ?int $scale = null): int

Проверить числовое равенство или порядок, не привязываясь к идентичности объектов.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
numДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError.
scalenull: все разряды обоих чисел; целое 0…2147483647: игнорировать остальные дробные разряды. Не использует bcscale.
Возвратint −1 / 0 / 1: это число меньше / равно / больше num.
ОтказыПлохая строка/scale → ValueError; несовместимый тип → TypeError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. 2.005 сравниваем с 2.009
  2. Весь масштаб
  3. Левое меньше: int −1
Всё значение или выбранные разрядыСамостоятельный пример
<?php
$a = new BcMath\Number('2.005');
var_dump($a->compare('2.009'));
var_dump($a->compare('2.009', 2));
var_dump($a->compare('2.0050') === 0);
Ожидаемый результат
int(-1)
int(0)
bool(true)

null отличается от процедурного bccomp(null), который берёт глобальный scale. Строгое сравнение с int 0 проверяет равенство результата сравнения.

Проверка лимита точного измеренияСамостоятельный пример
<?php
function fitsBudget($cost, $limit) {
    return $cost->compare($limit) <= 0;
}
var_dump(fitsBudget(new BcMath\Number('100.0001'), '100'));
var_dump(fitsBudget(new BcMath\Number('100.0000'), '100'));
Ожидаемый результат
bool(false)
bool(true)

В этой задаче даже одна десятитысячная значима. Сравнение со scale 2 ошибочно пропустило бы превышение.

Практическая граница. compare() возвращает int, а не bool. === между двумя Number сравнивает идентичность, не арифметическое равенство; == и <=> встроенный класс перегружает для чисел.

Соседние инструменты: bccomp, BcMath\Number. Выбор по задаче.

BcMath\Number::powВозвести число в целую степень с автоматическим масштабом результата.

PHP 8.4+ · bcmath

Number::pow(Number|string|int $exponent, ?int $scale = null): Number

Возвести число в целую степень с автоматическим масштабом результата.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
exponentДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError. Значение без ненулевой дробной части. Диапазон платформенный, не уже −2147483648…2147483647.
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет.
Автоматическое правилоПоложительный exponent: scale основания × exponent; нулевой: 0; отрицательный: от scale основания до +10, как div().
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше.
ОтказыПлохой/дробный/непомещающийся показатель или заданный/расчётный scale вне диапазона → ValueError. Ноль в отрицательной степени → DivisionByZeroError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. 1.20, scale 2
  2. pow(3): три множителя
  3. 1.728000, scale 6
Масштаб для трёх видов показателяСамостоятельный пример
<?php
$base = new BcMath\Number('1.20');
echo $base->pow(3), "\n";
echo $base->pow(0), "\n";
echo (new BcMath\Number('2.0'))->pow(-3), "\n";
Ожидаемый результат
1.728000
1
0.125

Для положительной степени сохраняется сумма дробных разрядов множителей. Для отрицательной возможна ограниченная периодическая дробь.

Повторяющийся коэффициент и неподходящий кореньСамостоятельный пример
<?php
$factor = new BcMath\Number('1.02');
echo $factor->pow(3)->mul('1000')->round(2), "\n";
try { $factor->pow('0.5'); }
catch (ValueError $error) { echo "Дробная степень не поддерживается\n"; }
Ожидаемый результат
1061.21
Дробная степень не поддерживается

Цепочка вызывает следующий метод у результата предыдущего. Квадратный корень вычисляется sqrt, а не pow(0.5).

Практическая граница. Проверяйте разумный предел exponent и длину входов. Формально допустимая степень может потребовать больше ресурсов, чем доступно веб-запросу.

Соседние инструменты: bcpow, BcMath\Number::powmod, BcMath\Number::sqrt. Выбор по задаче.

BcMath\Number::powmodВычислить модульную степень, не материализуя полную огромную степень.

PHP 8.4+ · bcmath

Number::powmod(Number|string|int $exponent, Number|string|int $modulus, ?int $scale = null): Number

Вычислить модульную степень, не материализуя полную огромную степень.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
exponentДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError. Неотрицательное целое значение.
modulusДругой Number, десятичная строка или int; float не входит в заявленный контракт. В строгом режиме он вызывает TypeError. Ненулевое целое значение.
ОснованиеТекущий Number тоже должен иметь целочисленное значение.
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет. При null результат всегда scale 0.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше.
ОтказыНенулевая дробная часть любого операнда/плохая строка/отрицательный показатель/недопустимый scale → ValueError; modulus 0 → DivisionByZeroError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. 7 в степени 4
  2. Сокращение по модулю 13
  3. Новый Number 9, scale 0
Остаток и формат результатаСамостоятельный пример
<?php
$base = new BcMath\Number('7');
echo $base->powmod(4, 13), "\n";
echo $base->powmod(4, 13, 2), "\n";
Ожидаемый результат
9
9.00

Математический результат целый, но явный scale позволяет формат с нулями.

Большая степень и отказ дробного основанияСамостоятельный пример
<?php
echo (new BcMath\Number('2'))->powmod(1000, 97), "\n";
try { (new BcMath\Number('2.5'))->powmod(3, 7); }
catch (ValueError $error) { echo "Нужно целое основание\n"; }
Ожидаемый результат
36
Нужно целое основание

Проверка относится и к самому объекту, не только к аргументам метода.

Практическая граница. Ненулевые отрицательные остатки возможны. Алгоритм не является обещанием постоянного времени исполнения и не заменяет криптографический протокол.

Соседние инструменты: bcpowmod, BcMath\Number::pow, BcMath\Number::mod. Выбор по задаче.

BcMath\Number::sqrtПолучить неотрицательный квадратный корень и управлять числом его разрядов.

PHP 8.4+ · bcmath

Number::sqrt(?int $scale = null): Number

Получить неотрицательный квадратный корень и управлять числом его разрядов.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
scaleЯвный scale: 0…2147483647; null/пропуск выбирает правило этого метода. bcscale() и bcmath.scale на объект не влияют. Уменьшение scale усекает к нулю, не округляет.
Автоматическое правилоИсходный scale, расширенный по необходимости максимум на 10; хвостовые нули расширения удаляются, ниже исходного scale не опускается.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше.
ОтказыОтрицательное число либо заданный/вычисленный scale вне диапазона → ValueError.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Площадь 6.25, scale 2
  2. sqrt()
  3. Сторона 2.50, scale 2
Корень с исходным и новым масштабомСамостоятельный пример
<?php
echo (new BcMath\Number('6.25'))->sqrt(), "\n";
echo (new BcMath\Number('3'))->sqrt(5), "\n";
Ожидаемый результат
2.50
1.73205

Явный scale для иррационального корня означает усечение, а не точное представление всей бесконечной дроби.

Размер по площади и обработка невозможного входаСамостоятельный пример
<?php
function sideFromArea($area) { return $area->sqrt(3); }
echo sideFromArea(new BcMath\Number('12.25')), "\n";
try { sideFromArea(new BcMath\Number('-1')); }
catch (ValueError $error) { echo "Нет действительной стороны\n"; }
Ожидаемый результат
3.500
Нет действительной стороны

Обработчик ошибки преобразует технический отказ в смысл задачи. Внешняя форма должна объяснять причину ещё до расчёта.

Практическая граница. Количество десятичных разрядов результата не равно доказанной точности исходных измерений. Для очень маленького корня автоматического масштаба может не хватить.

Соседние инструменты: bcsqrt, BcMath\Number::pow, BcMath\Number::div. Выбор по задаче.

BcMath\Number::ceilПолучить ближайшее целое не меньше исходного.

PHP 8.4+ · bcmath

Number::ceil(): Number

Получить ближайшее целое не меньше исходного.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
ПараметрыНет. Метод работает со значением текущего объекта.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше. У результата scale всегда 0.
ОтказыДля корректного созданного Number отдельного доменного отказа нет; недопустимая строка отклоняется ещё конструктором.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Исходное 2.1
  2. ceil выбирает целое не меньше исходного
  3. Новый Number 3, scale 0
Оба знака и масштаб нольСамостоятельный пример
<?php
$positive = (new BcMath\Number('2.1'))->ceil();
$negative = (new BcMath\Number('-2.1'))->ceil();
echo $positive, ':', $positive->scale, "\n";
echo $negative, ':', $negative->scale, "\n";
Ожидаемый результат
3:0
-2:0

Направление сравнивается на числовой прямой. Операция не меняет исходное число.

Минимум ящиков для конечного точного частногоСамостоятельный пример
<?php
$items = new BcMath\Number('17');
$needed = $items->div(4)->ceil();
echo $needed, "\n";
echo $items, "\n";
Ожидаемый результат
5
17

Для 17/4 автоматическое деление даёт точное 4.25. Для больших целых и опасности потери малой дроби выбирайте divmod: ceil не восстановит уже потерянный остаток.

Практическая граница. Это округление до целого независимо от bcscale. Для разрядов после точки есть round с нужным RoundingMode; для точных денежных единиц не приводите произвольно большой результат к int.

Соседние инструменты: bcceil, BcMath\Number::floor, BcMath\Number::round. Выбор по задаче.

BcMath\Number::floorПолучить ближайшее целое не больше исходного.

PHP 8.4+ · bcmath

Number::floor(): Number

Получить ближайшее целое не больше исходного.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. function name($x) { ... } объявляет повторяемое действие; параметр получает вход, return отдаёт результат вызывающему коду. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
ПараметрыНет. Метод работает со значением текущего объекта.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше. У результата scale всегда 0.
ОтказыДля корректного созданного Number отдельного доменного отказа нет; недопустимая строка отклоняется ещё конструктором.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Исходное 2.1
  2. floor выбирает целое не больше исходного
  3. Новый Number 2, scale 0
Оба знака и масштаб нольСамостоятельный пример
<?php
$positive = (new BcMath\Number('2.1'))->floor();
$negative = (new BcMath\Number('-2.1'))->floor();
echo $positive, ':', $positive->scale, "\n";
echo $negative, ':', $negative->scale, "\n";
Ожидаемый результат
2:0
-3:0

Направление сравнивается на числовой прямой. Операция не меняет исходное число.

Координата ячейки слева от измеренияСамостоятельный пример
<?php
function cellStart($measurement) { return $measurement->floor(); }
echo cellStart(new BcMath\Number('4.9')), "\n";
echo cellStart(new BcMath\Number('-0.1')), "\n";
Ожидаемый результат
4
-1

Нижняя граница отрицательного измерения — −1, а не 0. Это полезно при разбиении числовой шкалы на интервалы.

Практическая граница. Это округление до целого независимо от bcscale. Для разрядов после точки есть round с нужным RoundingMode; для точных денежных единиц не приводите произвольно большой результат к int.

Соседние инструменты: bcfloor, BcMath\Number::ceil, BcMath\Number::round. Выбор по задаче.

BcMath\Number::roundПолучить новое число, округлённое до выбранного десятичного разряда.

PHP 8.4+ · bcmath

Number::round(int $precision = 0, RoundingMode $mode = RoundingMode::HalfAwayFromZero): Number

Получить новое число, округлённое до выбранного десятичного разряда.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. RoundingMode::HalfEven — именованный вариант правила округления, а не строка или вызов. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
precisionПоложительная: знаки после точки. 0: единицы. Отрицательная: десятки, сотни и т. д. Это не число значащих цифр.
modeОдин из восьми RoundingMode; по умолчанию ближайшее с точной половиной от нуля.
ВозвратВозвращается новый Number; исходный объект сохраняет value и scale. Результат нужно присвоить или передать дальше. scale результата равен положительной precision, а при precision ≤ 0 равен 0.
ОтказыManual указывает ValueError для неверного mode; передача int вместо enum в проверенном API даёт TypeError. В PHP 8.5.11 precision > 2147483647 отклоняется с ValueError; отрицательная precision помещается в int PHP. Допустимый диапазон не гарантирует доступной памяти.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Исходная цена 2.345
  2. round(2, HalfEven)
  3. Новая цена 2.34, исходная 2.345
Согласованное правило половиныСамостоятельный пример
<?php
$raw = new BcMath\Number('2.345');
echo $raw->round(2, RoundingMode::HalfEven), "\n";
echo $raw->round(2, RoundingMode::HalfAwayFromZero), "\n";
echo $raw, "\n";
Ожидаемый результат
2.34
2.35
2.345

Результаты разных политик законно различаются. Копия raw остаётся для аудита вычисления.

Разряды по обе стороны точкиСамостоятельный пример
<?php
$price = new BcMath\Number('126.4');
$tens = $price->round(-1);
$padded = $price->round(3);
echo $tens, ':', $tens->scale, "\n";
echo $padded, ':', $padded->scale, "\n";
Ожидаемый результат
130:0
126.400:3

Округление до десятков не создаёт отрицательный scale. Дополнение нулями меняет представление, но не числовое значение.

Практическая граница. Сначала согласуйте, округляется ли строка заказа, ставка, комиссия или итог целиком. Number не выбирает этап округления. Полная таблица восьми режимов есть в начале этой главы.

Соседние инструменты: bcround, RoundingMode, BcMath\Number::ceil, BcMath\Number::floor. Выбор по задаче.

BcMath\Number::__toStringПолучить исходную десятичную строку для текста или явной передачи в другой интерфейс.

PHP 8.4+ · bcmath

Number::__toString(): string

Получить исходную десятичную строку для текста или явной передачи в другой интерфейс.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. [...] создаёт массив; [$a, $b] = ... раскладывает два результата по переменным, $data["value"] читает элемент по ключу. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
ПараметрыНет; обычно вызывается автоматически при echo или (string).
ВозвратСтрока свойства value, включая значимые для представления хвостовые нули.
ОтказыМетод не форматирует локаль и не преобразует валюту.
ВерсияPHP 8.4+
Что происходит в первом опыте
  1. Number 12.300
  2. Явное (string)
  3. Строка 12.300 без преобразования в float
Текстовое представлениеСамостоятельный пример
<?php
$amount = new BcMath\Number('12.300');
$text = (string) $amount;
echo $text, "\n";
var_dump($text === $amount->value);
Ожидаемый результат
12.300
bool(true)

Круглые скобки с string — явное приведение к строке. Оно вызывает __toString; прямой вызов метода тоже допустим, но обычно не нужен.

JSON-контракт сохраняет цену строкойСамостоятельный пример
<?php
$amount = new BcMath\Number('9007199254740993.20');
$payload = ['amount' => (string) $amount, 'currency' => 'RUB'];
echo json_encode($payload, JSON_THROW_ON_ERROR), "\n";
Ожидаемый результат
{"amount":"9007199254740993.20","currency":"RUB"}

Ключи подписывают поля массива, json_encode создаёт JSON. Строка согласована с контрактом API: не используйте JSON_NUMERIC_CHECK, который превратит её в потенциально неточное число. JSON_THROW_ON_ERROR сообщает об ошибке кодирования.

Практическая граница. Stringable не означает, что Number будет принят строковым параметром при strict_types=1: передавайте явное (string). Приведение самого объекта к int/float не является API точного значения; форматирующие функции с float могут уничтожить разряды.

Соседние инструменты: BcMath\Number::__construct, BcMath\Number::__serialize. Выбор по задаче.

BcMath\Number::__serializeПодготовить внутренние данные Number для штатного PHP serialize().

PHP 8.4+ · bcmath

Number::__serialize(): array

Подготовить внутренние данные Number для штатного PHP serialize().

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. [...] создаёт массив; [$a, $b] = ... раскладывает два результата по переменным, $data["value"] читает элемент по ключу. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
ПараметрыНет. serialize($number) вызывает этот hook автоматически.
ВозвратМассив состояния; в PHP 8.5.11 это ["value" => десятичная строка]. Scale восстанавливается из её разрядов.
ОтказыДля штатного созданного Number отдельного доменного отказа нет.
ВерсияPHP 8.4+

Магические методы и жизненный цикл объясняет вызов hook движком; здесь показан конкретный путь числового состояния.

Что происходит в первом опыте
  1. Number 12.300
  2. serialize вызывает __serialize
  3. Состояние хранит value 12.300, откуда восстановится scale 3
Посмотреть состояние до сериализацииСамостоятельный пример
<?php
$number = new BcMath\Number('12.300');
$state = $number->__serialize();
echo $state['value'], "\n";
echo count($state), "\n";
Ожидаемый результат
12.300
1

Прямой вызов нужен здесь для объяснения механизма. Его массив ещё не является строкой PHP-сериализации.

Локальный снимок своего объектаСамостоятельный пример
<?php
$original = new BcMath\Number('12345678901234567890.00');
$snapshot = serialize($original);
$copy = unserialize($snapshot, ['allowed_classes' => [BcMath\Number::class]]);
echo $copy, ':', $copy->scale, "\n";
var_dump($copy->compare($original) === 0, $copy === $original);
Ожидаемый результат
12345678901234567890.00:2
bool(true)
bool(false)

::class даёт имя класса; список allowed_classes ограничивает восстановление этой локальной копии. Возникает новый объект с тем же числом, а не ссылка на старый.

Практическая граница. Не принимайте сериализованные PHP-объекты из недоверенного запроса. allowed_classes не превращает недоверенный формат в безопасный протокол. Для обмена обычно яснее JSON с десятичной строкой и валидацией. Структура hook показана для проверенной версии, не как долгосрочная внешняя схема.

Соседние инструменты: BcMath\Number::__unserialize, BcMath\Number::__toString. Выбор по задаче.

BcMath\Number::__unserializeВосстановить новый Number из состояния, созданного сериализацией.

PHP 8.4+ · bcmath

Number::__unserialize(array $data): void

Восстановить новый Number из состояния, созданного сериализацией.

$name — переменная; = сохраняет результат, кавычки задают строку, ; завершает команду. name(...) вызывает функцию с аргументами через запятую. echo выводит, "\n" переносит строку; var_dump показывает значение и его тип. new BcMath\Number(...) создаёт число-объект. Обратная косая черта — часть полного имени класса. $number->method(...) вызывает действие этого объекта; ->value и ->scale читают его свойства. public означает доступность извне, readonly — запрет изменения после инициализации, final — запрет наследования. try начинает попытку, catch (Тип $error) обрабатывает пойманный отказ, finally выполняет завершающие действия. throw new ... сообщает об отказе; finally его не подавляет. [...] создаёт массив; [$a, $b] = ... раскладывает два результата по переменным, $data["value"] читает элемент по ключу. Объект и обращение к нему. Начало: переменная; Вызов и return.

Часть договораЗначение
dataАссоциативный массив состояния. В PHP 8.5.11 требуется непустая строка value в корректной BCMath-записи; scale выводится из неё.
Обычный вызовunserialize() выделяет экземпляр и вызывает hook. Это не setter уже созданного Number.
Возвратvoid: значимого возвращаемого результата нет; инициализируется восстанавливаемый экземпляр.
ОтказыНа официальной странице заявлен ValueError. Однако PHP 8.5.11 и его исходник выбрасывают обычный Exception для неверного массива/числа. Повторная инициализация корректным состоянием → Error readonly. Несовместимый тип data → TypeError.
ВерсияPHP 8.4+

Расхождение подтверждено первичным исходником php-8.5.11/ext/bcmath/bcmath.c, метод __unserialize и отдельным выполнением. В другой версии тип отказа нужно сверять повторно.

Что происходит в первом опыте
  1. Локальный serialize содержит 7.250
  2. unserialize создаёт новый экземпляр
  3. __unserialize восстанавливает value и scale 3
Штатное восстановление делает движокСамостоятельный пример
<?php
$snapshot = serialize(new BcMath\Number('7.250'));
$restored = unserialize($snapshot, ['allowed_classes' => [BcMath\Number::class]]);
echo $restored->value, ':', $restored->scale, "\n";
Ожидаемый результат
7.250:3

Конструктор вручную не вызывается; механизм восстановления инициализирует новый объект. Здесь строка создана самим примером, внешних данных нет.

Плохое состояние и запрет переписать числоСамостоятельный пример
<?php
$number = new BcMath\Number('7.25');
try { $number->__unserialize(['value' => 5]); }
catch (Throwable $error) { echo $error::class, "\n"; }
try { $number->__unserialize(['value' => '9.00']); }
catch (Throwable $error) { echo $error::class, "\n"; }
echo $number, "\n";
Ожидаемый результат
Exception
Error
7.25

Это диагностический опыт PHP 8.5.11, не рекомендуемый путь загрузки данных. Throwable охватывает обе ветви отказа; ::class показывает фактический класс ошибки. Исходное значение не изменилось.

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

Соседние инструменты: BcMath\Number::__serialize, BcMath\Number::__construct. Выбор по задаче.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.