GMP 大数运算
PHP 的 GMP 扩展(GNU Multiple Precision)提供了任意精度的大整数运算。与 BC Math 不同,GMP 专门针对整数运算优化,速度更快,支持位操作、模运算、素数检测等数论运算。在密码学、大数计算、组合数学等领域有广泛应用。
前置知识
阅读本节前,建议先了解:BC Math 任意精度、Math 数学函数
基础概念
GMP vs BC Math
| 特性 | GMP | BC Math |
|---|---|---|
| 数据类型 | 整数 | 整数 + 小数 |
| 输入参数 | int/string/GMP | 字符串 |
| 速度 | 更快 | 较慢 |
| 位操作 | 支持 | 不支持 |
| 精度控制 | 自动 | 手动 |
安装
bash
# 编译安装
./configure --enable-gmp
# Ubuntu/Debian
sudo apt-get install php-gmp基本运算
创建 GMP 数
php
<?php
declare(strict_types=1);
use GMP;
// 从整数创建
$num = gmp_init(12345678901234567890);
// 从字符串创建
$num = gmp_init('12345678901234567890');
// 从其他进制创建
$hex = gmp_init('FF', 16); // 255
$oct = gmp_init('377', 8); // 255
$bin = gmp_init('11111111', 2); // 255
// PHP 8.4+ 可以直接构造
// $num = new GMP('12345678901234567890');
// 转换为字符串
echo gmp_strval($num) . PHP_EOL;
// 转换为其他进制
echo gmp_strval(gmp_init(255), 16) . PHP_EOL; // ff
echo gmp_strval(gmp_init(255), 2) . PHP_EOL; // 11111111
// 转换为整数
echo gmp_intval(gmp_init('42')) . PHP_EOL; // 42
// 导出为二进制字符串
echo gmp_export(gmp_init('12345')) . PHP_EOL;算术运算
php
<?php
declare(strict_types=1);
$a = gmp_init('123456789012345678901234567890');
$b = gmp_init('987654321098765432109876543210');
// 加法
echo gmp_strval(gmp_add($a, $b)) . PHP_EOL;
// 减法
echo gmp_strval(gmp_sub($a, $b)) . PHP_EOL;
// 乘法
echo gmp_strval(gmp_mul($a, $b)) . PHP_EOL;
// 除法(返回商和余数)
[$quotient, $remainder] = gmp_div_qr($a, $b);
echo "商: " . gmp_strval($quotient) . PHP_EOL;
echo "余: " . gmp_strval($remainder) . PHP_EOL;
// 模运算
echo gmp_strval(gmp_mod($a, gmp_init('100'))) . PHP_EOL;
// 幂运算
echo gmp_strval(gmp_pow(gmp_init(2), 100)) . PHP_EOL; // 2^100
// 模幂运算
echo gmp_strval(gmp_powm(gmp_init(2), 10, gmp_init(1000))) . PHP_EOL; // 24
// 平方根(向下取整)
echo gmp_strval(gmp_sqrt(gmp_init('144'))) . PHP_EOL; // 12
// 绝对值
echo gmp_strval(gmp_abs(gmp_init(-100))) . PHP_EOL; // 100
// 取反
echo gmp_strval(gmp_neg(gmp_init(100))) . PHP_EOL; // -100
// 符号
echo gmp_sign(gmp_init(-100)) . PHP_EOL; // -1
echo gmp_sign(gmp_init(0)) . PHP_EOL; // 0
echo gmp_sign(gmp_init(100)) . PHP_EOL; // 1比较
php
<?php
declare(strict_types=1);
$a = gmp_init('100000000000000000000');
$b = gmp_init('200000000000000000000');
// gmp_cmp: 0 = 相等, 1 = a > b, -1 = a < b
echo gmp_cmp($a, $b) . PHP_EOL; // -1
echo gmp_cmp($b, $a) . PHP_EOL; // 1
echo gmp_cmp($a, $a) . PHP_EOL; // 0
// gmp_equal, gmp_gt, gmp_lt (PHP 8.4+)位操作
php
<?php
declare(strict_types=1);
$num = gmp_init('0xFF'); // 255
// 与(AND)
echo gmp_strval(gmp_and($num, gmp_init('0x0F')), 16) . PHP_EOL; // f
// 或(OR)
echo gmp_strval(gmp_or($num, gmp_init('0x0F')), 16) . PHP_EOL; // ff
// 异或(XOR)
echo gmp_strval(gmp_xor($num, gmp_init('0x0F')), 16) . PHP_EOL; // f0
// 非(NOT)
echo gmp_strval(gmp_com($num), 16) . PHP_EOL;
// 左移
echo gmp_strval(gmp_mul_2exp(gmp_init(1), 10)) . PHP_EOL; // 1024 (1 << 10)
// 右移
echo gmp_strval(gmp_div_2exp(gmp_init(1024), 10)) . PHP_EOL; // 1 (1024 >> 10)
// 设置位
echo gmp_strval(gmp_setbit(gmp_init(0), 5)) . PHP_EOL; // 32
// 扫描位
echo gmp_scan0(gmp_init('0b1000'), 0) . PHP_EOL; // 3 (第一个0的位置)
echo gmp_scan1(gmp_init('0b0111'), 0) . PHP_EOL; // 1 (第一个1的位置)
// 位测试
echo gmp_testbit(gmp_init('0b100'), 2) ? '1' : '0' . PHP_EOL; // 1
// 统计1的位数
echo gmp_hamdist(gmp_init('0b10101'), gmp_init(0)) . PHP_EOL;
// 注意: gmp_popcount 统计1的数量 (PHP 7.0+)数论函数
php
<?php
declare(strict_types=1);
// 最大公约数(GCD)
echo gmp_strval(gmp_gcd(gmp_init(48), gmp_init(18))) . PHP_EOL; // 6
// 最小公倍数(LCM)
echo gmp_strval(gmp_lcm(gmp_init(12), gmp_init(18))) . PHP_EOL; // 36
// 素数检测
echo gmp_prob_prime(gmp_init('99999999999999997'), 10) . PHP_EOL;
// 返回: 0 = 非素数, 1 = 可能素数, 2 = 确定素数
// 下一个素数
echo gmp_strval(gmp_nextprime(gmp_init(100))) . PHP_EOL; // 101
// 随机素数
$randomPrime = gmp_random_prime(256); // 256位素数
echo gmp_strval($randomPrime) . PHP_EOL;
// Legendre 符号
echo gmp_legendre(gmp_init(3), gmp_init(11)) . PHP_EOL;
// Jacobi 符号
echo gmp_jacobi(gmp_init(2), gmp_init(5)) . PHP_EOL;
// 阶乘
echo gmp_strval(gmp_fact(20)) . PHP_EOL; // 2432902008176640000
// 组合数 C(n, k)
echo gmp_strval(gmp_binomial(10, 3)) . PHP_EOL; // 120
// Fibonacci 数
echo gmp_strval(gmp_fib(10)) . PHP_EOL; // 55实战示例
RSA 密钥生成辅助
php
<?php
declare(strict_types=1);
/**
* 使用 GMP 辅助生成素数对
*/
function generatePrimePair(int $bitLength = 512): array
{
$p = gmp_random_prime($bitLength);
$q = gmp_random_prime($bitLength);
// 确保 p != q
while (gmp_cmp($p, $q) === 0) {
$q = gmp_random_prime($bitLength);
}
// 计算 n = p * q
$n = gmp_mul($p, $q);
// 计算 phi(n) = (p-1) * (q-1)
$phi = gmp_mul(gmp_sub($p, 1), gmp_sub($q, 1));
return [
'p' => gmp_strval($p),
'q' => gmp_strval($q),
'n' => gmp_strval($n),
'phi' => gmp_strval($phi),
];
}
// $keys = generatePrimePair(256);
// echo "n = " . $keys['n'] . PHP_EOL;
// echo "phi = " . $keys['phi'] . PHP_EOL;注意事项
- GMP 参数可以是整数、字符串或 GMP 对象
- 大数运算比普通整数运算慢
- PHP 8.4+ 引入了
GMP类的改进
下一节
继续学习:Random 统一随机数生成器