Как правильно считать проценты для цен в PHP

0 20 января 2026

В этой статье я расскажу, как удобно и точно работать с процентами для цен: скидки, наценки, доля от суммы или процентное изменение. Приведу рабочие примеры на PHP 8+ и дам советы, как безопасно обращаться с дробными числами и аккуратно отображать результаты в интернет-магазине.


1. Основные формулы для процентов

Чтобы корректно работать с ценами, полезно помнить базовые формулы:

  • Процент от суммы: x = сумма * (процент / 100)
  • Добавить процент к цене: x = сумма * (1 + процент / 100)
  • Уменьшить цену на процент: x = сумма * (1 - процент / 100)
  • Изменение в процентах между старой и новой ценой: процент = ((новая - старая) / старая) * 100

Эти формулы просты, но важно учитывать точность вычислений и правильные типы данных.


2. Почему float может подвести

Использование float для цен может приводить к неточностям (например, 0.1 + 0.2 ≠ 0.3). Чтобы избежать проблем:

  • Храните цены в целых единицах — копейках или центах int.
  • Или используйте BCMath для точных операций с десятичными числами.

3. Практичные функции на PHP 8+

<?php
declare(strict_types=1);

function percentOf(int $amountCents, float $percent): int {
    return (int) round($amountCents * ($percent / 100), 0, PHP_ROUND_HALF_UP);
}

function addPercent(int $amountCents, float $percent): int {
    return $amountCents + percentOf($amountCents, $percent);
}

function subtractPercent(int $amountCents, float $percent): int {
    $res = $amountCents - percentOf($amountCents, $percent);
    return $res >= 0 ? $res : 0;
}

function percentChange(int $oldCents, int $newCents): ?float {
    if ($oldCents === 0) return null;
    return (($newCents - $oldCents) / $oldCents) * 100.0;
}

function formatMoney(int $amountCents, int $decimals = 2): string {
    return number_format($amountCents / 100, $decimals, '.', ' ');
}
?>

Пример использования:

$price = 100000; // 1000.00 у.е. в копейках
$discount = 20.0; // 20%

$newPrice = subtractPercent($price, $discount); // 80000
echo formatMoney($newPrice); // "800.00"

4. Точный вариант с BCMath

function bc_add_percent(string $amount, string $percent, int $scale = 2): string {
    $mult = bcdiv($percent, "100", $scale + 2);
    $inc = bcmul($amount, $mult, $scale + 2);
    return bcadd($amount, $inc, $scale);
}

echo bc_add_percent("1000.00", "12.5", 2); // "1125.00"

BCMath идеально подходит, если цены хранятся как строки и важна максимальная точность.


5. Советы для практики

  • Храните цены в копейках/центах — проще и безопаснее.
  • Округляйте только в конце, чтобы накопленная точность не терялась.
  • Используйте PHP_ROUND_HALF_UP для финансовых операций.
  • Проверяйте крайние случаи: ноль, отрицательные значения, большие числа.
  • Будьте прозрачны: показывайте старую цену, сумму скидки и процент.
  • Если используете налоги, решите, считать их до или после скидки, и соблюдайте единообразие.

6. Примеры сценариев

  • Скидка 15% на товар 749.99 → храните 74999 (копейки), subtractPercent(74999, 15.0) → округлённый результат.
  • Наценка 25% → используйте addPercent(). Чтобы найти базовую цену: base = price / (1 + p/100).
  • Процент изменения цены → percentChange(), если старая цена 0 — решите, как обрабатывать (null или бесконечный рост).

7. Заключение

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


🙏 Благодарностей 0
Привет! Похоже, Вы ещё не вошли на сайт.
Чтобы получить полный доступ, зарегистрируйтесь или войдите под своим именем.