Обработка больших чисел в PHP: варианты и реализация

Раздел: PHP программирование -> Числа в PHP

Варианты работы с большими числами в PHP

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

Наиболее эффективным решением для работы с большими числами в PHP является расширение GMP (GNU Multiple Precision). Оно реализовано на языке C и обеспечивает максимальную производительность при выполнении арифметических операций с числами произвольной длины. Расширение доступно в большинстве дистрибутивов PHP и может быть установлено через пакетный менеджер.

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


<?php
$a = gmp_init('12345678901234567890');
$b = gmp_init('98765432109876543210');
$sum = gmp_add($a, $b);
echo gmp_strval($sum); // 111111111011111111100
?>
  

Php случайное число (генерация случайного числа в php)

Пояснение шагов:

  • gmp_init() создает GMP-число из строки или целого числа.
  • gmp_add() производит сложение.
  • gmp_strval() преобразует GMP-число обратно в строку для вывода.

Типичная проблема: отсутствие расширения GMP в окружении. Решение: установить пакет php-gmp (например, в Ubuntu: apt-get install php-gmp). Также на Windows нужно раскомментировать строку extension=gmp в php.ini.

Цель использования: высокопроизводительные вычисления с числами, длина которых превышает разрядность стандартных типов (например, криптография, финансовые расчёты, математические алгоритмы).

Как выполнять точные вычисления без установки дополнительных расширений?

Если расширение GMP недоступно, альтернативой выступает BC Math (Binary Calculator). Оно также является встроенным расширением, но работает медленнее GMP. При этом BC Math использует строки для представления чисел, что упрощает отладку.


<?php
$a = '12345678901234567890';
$b = '98765432109876543210';
$sum = bcadd($a, $b);
echo $sum; // 111111111011111111100
?>
  

количество чисел php (количество чисел в php)

Шаги:

  • bcadd() принимает строки и возвращает строку.
  • Установка точности через bcscale() для управления количеством знаков после запятой.

Ограничение: все операции с BC Math выполняются в пользовательском пространстве, что приводит к снижению производительности при большом объёме вычислений. Также отсутствует поддержка операций по модулю с отрицательными числами в старых версиях.

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

Можно ли обойтись встроенными типами float или int?

Встроенные типы int и float имеют фиксированную разрядность. В PHP на 64-битных системах int вмещает до 9,22·10¹⁸, а float теряет точность на числах с большим количеством цифр. Поэтому для работы с числами, выходящими за эти пределы, они непригодны.


<?php
$large = 12345678901234567890;
var_dump($large); // float(1.2345678901234568E+19) – точность потеряна
?>
  

массив чисел php (массив чисел в php)

Ошибка: неявное преобразование в float при переполнении int. Решения нет, кроме использования специализированных расширений.

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

Как работать с большими числами, если недоступны ни GMP, ни BC Math?

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


<?php
function str_add($a, $b) {
    $len = max(strlen($a), strlen($b));
    $a = str_pad($a, $len, '0', STR_PAD_LEFT);
    $b = str_pad($b, $len, '0', STR_PAD_LEFT);
    $carry = 0;
    $result = '';
    for ($i = $len - 1; $i >= 0; $i--) {
        $sum = (int)$a[$i] + (int)$b[$i] + $carry;
        $carry = intdiv($sum, 10);
        $result = ($sum % 10) . $result;
    }
    if ($carry) $result = $carry . $result;
    return $result;
}
echo str_add('99999999999999999999', '1'); // 100000000000000000000
?>
  

Сложность: реализация умножения, деления и возведения в степень вручную требует много кода и подвержена ошибкам. Производительность значительно ниже GMP.

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

- Php преобразовать число (преобразование числа в php)
- Php целое число (проверка целого числа в php)
- Php большие числа (работа с большими числами в php)

Расширенные примеры работы с большими числами

Вычисление факториала большого числа с помощью GMP

Факториал 1000 содержит 2568 цифр. GMP позволяет получить точный результат за доли секунды.

Пример

<?php
$n = 1000;
$fact = gmp_fact($n);
$result = gmp_strval($fact);
echo 'Длина числа: ' . strlen($result) . "\n";
echo 'Первые 50 цифр: ' . substr($result, 0, 50) . "...";
?>
Длина числа: 2568
Первые 50 цифр: 40238726007709377354370243392300398571937486421071...

Пояснение: функция gmp_fact() оптимизирована для рекурсивного умножения.

Сравнение производительности GMP и BC Math при возведении в степень

Измерим время возведения числа 10^10000 в квадрат 100 раз.

Пример

<?php
$a_gmp = gmp_init('10');
$a_bc = '10';
$exponent = 10000;

$time_start = microtime(true);
for ($i = 0; $i < 100; $i++) {
    $a_gmp = gmp_pow($a_gmp, 2);
}
echo 'GMP: ' . (microtime(true) - $time_start) . " сек\n";

$time_start = microtime(true);
for ($i = 0; $i < 100; $i++) {
    $a_bc = bcpow($a_bc, '2');
}
echo 'BC Math: ' . (microtime(true) - $time_start) . " сек\n";
?>
GMP: 0.0012 сек
BC Math: 0.0789 сек

Результат демонстрирует, что GMP примерно в 65 раз быстрее для данной задачи.

Проверка чисел на простоту с помощью GMP

Функция gmp_prob_prime() использует вероятностный тест Миллера - Рабина, что полезно в криптографии.

Пример

<?php
$candidate = gmp_init('12345678901234567890123456789012345678901234567890123456789012345678901234567890');
$result = gmp_prob_prime($candidate);
if ($result == 2) {
    echo 'Определённо простое';
} elseif ($result == 1) {
    echo 'Вероятно простое';
} else {
    echo 'Составное';
}
?>
Составное

Примечание: возвращаемые значения: 2 - точно простое, 1 - вероятно простое, 0 - составное. Для 100% доказательства требуется дополнительная проверка.

Вычисление числа π с высокой точностью с помощью BC Math

Использование алгоритма Бейли - Боруэйна - Плаффа (BBP) для получения шестнадцатеричных цифр π. Ниже приведён упрощённый фрагмент для вычисления 50 десятичных знаков.

Пример

<?php
bcscale(50);
$a = '1';
$b = bcdiv('1', bcsqrt('2'));
$t = bcdiv('1', '4');
$p = '1';
for ($i = 0; $i < 10; $i++) {
    $a_next = bcdiv(bcadd($a, $b), '2');
    $b = bcsqrt(bcmul($a, $b));
    $t = bcsub($t, bcmul($p, bcsub($a, $a_next)));
    $a = $a_next;
    $p = bcmul($p, '2');
}
$pi = bcdiv(bcpow(bcadd($a, $b), '2'), bcmul($t, '4'));
echo $pi;
?>
3.14159265358979323846264338327950288419716939937510

Количество итераций (10) даёт точность около 50 знаков после запятой. Для бо́льшей точности увеличивается число итераций и масштаб.

Работа с большими числами в PHP - comments

En
Php большие числа (php)