PHPで非常に大きな整数を扱いたいと思ったことはありませんか?標準のPHPでは64ビット整数(2^63-1まで)しか扱えませんが、GMP拡張を使えば理論上無制限の大きさの整数を扱うことができます。その入り口となるのがgmp_init
関数です。今回はこの関数について詳しく解説します。
gmp_init関数の基本
gmp_init
は、PHP-GMPライブラリの基礎となる関数で、通常の数値や文字列からGMP数値オブジェクトを作成します。
GMP gmp_init(mixed $num, int $base = 10)
パラメータ
- $num: 初期化する数値(整数、文字列)
- $base: 数値の基数(デフォルトは10進数)
- 2から62までの値を指定可能
- 負の基数も指定可能(詳細は後述)
戻り値
GMP数値オブジェクト(PHP 5.6以降はGMPリソース)を返します。このオブジェクトは他のGMP関数で使用できます。
基本的な使い方
10進数の初期化
<?php
// 通常の整数からGMP数値を作成
$gmp1 = gmp_init(42);
echo "GMP値: " . gmp_strval($gmp1) . "\n"; // 42
// PHPの整数型で表現できない大きな数値(文字列で指定)
$gmp2 = gmp_init("123456789012345678901234567890");
echo "大きな数値: " . gmp_strval($gmp2) . "\n";
?>
異なる基数での初期化
<?php
// 2進数(バイナリ)表現からの初期化
$binary = gmp_init("1010101", 2);
echo "2進数1010101 = " . gmp_strval($binary) . "\n"; // 85
// 16進数からの初期化
$hex = gmp_init("1A2B3C", 16);
echo "16進数1A2B3C = " . gmp_strval($hex) . "\n"; // 1715004
// 36進数(アルファベット+数字)
$base36 = gmp_init("HELLO", 36);
echo "36進数HELLO = " . gmp_strval($base36) . "\n"; // 29234652
?>
高度な使用例
負の基数の使用
GMPでは負の基数も指定できます。これは符号付き数を扱うためのもので、最上位桁が負の数を表します。
<?php
// 通常の10進数の負の数
$neg10 = gmp_init("-123");
echo "通常の負の数: " . gmp_strval($neg10) . "\n"; // -123
// -10進数での表現(上位桁が9以上なら負の数)
$neg_base = gmp_init("923", -10); // 9は基数以上なので負の数とみなされる
echo "-10進数の923: " . gmp_strval($neg_base) . "\n"; // -77
?>
大きな数値の演算
GMP数値を使って、通常のPHPでは扱えない大きさの数値演算を行えます。
<?php
// 非常に大きな数値
$large1 = gmp_init("10000000000000000000000000000000000000000");
$large2 = gmp_init("99999999999999999999999999999999999999999");
// 加算
$sum = gmp_add($large1, $large2);
echo "合計: " . gmp_strval($sum) . "\n";
// 乗算
$product = gmp_mul($large1, $large2);
echo "積: " . gmp_strval($product) . "\n";
// 累乗
$power = gmp_pow($large1, 3);
echo "累乗: " . gmp_strval($power) . "\n";
?>
実用的な応用例
1. 素数の生成と検証
GMPは素数関連の関数も提供しており、大きな素数の生成や検証に使えます。
<?php
// ランダムな素数を生成
function generate_prime($bits) {
do {
// ランダムな数値を生成
$random = gmp_random_bits($bits);
// 確実に奇数にする
$random = gmp_or($random, gmp_init(1));
} while (gmp_prob_prime($random, 50) == 0);
return $random;
}
// 512ビットの素数を生成
$prime = generate_prime(512);
echo "生成した素数: " . gmp_strval($prime) . "\n";
echo "桁数: " . strlen(gmp_strval($prime)) . "\n";
// 素数判定
$is_prime = gmp_prob_prime($prime, 50);
echo "素数判定結果: " . ($is_prime == 2 ? "確実な素数" :
($is_prime == 1 ? "おそらく素数" : "素数ではない")) . "\n";
?>
2. 暗号関連の計算
RSAなどの暗号アルゴリズムでは大きな整数の演算が必要です。
<?php
// シンプルなRSA風の暗号化/復号化のデモ
// 注:これは教育目的のみで、実際の暗号化には使わないでください
// 簡単な素数
$p = gmp_init(61);
$q = gmp_init(53);
// n = p * q
$n = gmp_mul($p, $q);
// トーティエント関数φ(n) = (p-1)(q-1)
$phi = gmp_mul(gmp_sub($p, 1), gmp_sub($q, 1));
// 公開鍵e(φ(n)と互いに素)
$e = gmp_init(17);
// 秘密鍵d(e*d ≡ 1 (mod φ(n)))
$d = gmp_invert($e, $phi);
echo "公開鍵(n,e): (" . gmp_strval($n) . ", " . gmp_strval($e) . ")\n";
echo "秘密鍵d: " . gmp_strval($d) . "\n";
// 暗号化したいメッセージ
$message = gmp_init(123);
echo "元のメッセージ: " . gmp_strval($message) . "\n";
// 暗号化: c = m^e mod n
$encrypted = gmp_powm($message, $e, $n);
echo "暗号化: " . gmp_strval($encrypted) . "\n";
// 復号化: m = c^d mod n
$decrypted = gmp_powm($encrypted, $d, $n);
echo "復号化: " . gmp_strval($decrypted) . "\n";
?>
3. フィボナッチ数列の大きな項
通常のPHPでは計算できないような大きなフィボナッチ数を計算できます。
<?php
// GMPを使った効率的なフィボナッチ数列計算
function fibonacci_gmp($n) {
if ($n <= 0) return gmp_init(0);
if ($n == 1) return gmp_init(1);
$a = gmp_init(0);
$b = gmp_init(1);
for ($i = 2; $i <= $n; $i++) {
$c = gmp_add($a, $b);
$a = $b;
$b = $c;
}
return $b;
}
// 第1000項のフィボナッチ数を計算
$fib1000 = fibonacci_gmp(1000);
echo "フィボナッチ数列の第1000項: " . gmp_strval($fib1000) . "\n";
echo "桁数: " . strlen(gmp_strval($fib1000)) . "\n";
?>
パフォーマンス比較
GMPライブラリはCで実装されているため、純粋なPHPコードよりもはるかに高速です。
<?php
// 大きな階乗を計算する例
// PHPのみでの実装
function factorial_php($n) {
$result = "1";
for ($i = 2; $i <= $n; $i++) {
// BCMathを使用
$result = bcmul($result, (string)$i);
}
return $result;
}
// GMPを使った実装
function factorial_gmp($n) {
$result = gmp_init(1);
for ($i = 2; $i <= $n; $i++) {
$result = gmp_mul($result, $i);
}
return $result;
}
// 計測開始
$n = 10000;
$start = microtime(true);
$fact_gmp = factorial_gmp($n);
$gmp_time = microtime(true) - $start;
$start = microtime(true);
$fact_php = factorial_php($n);
$php_time = microtime(true) - $start;
echo "GMP時間: {$gmp_time}秒\n";
echo "PHP時間: {$php_time}秒\n";
echo "GMPは " . ($php_time / $gmp_time) . " 倍高速\n";
// 結果の一部を表示
echo "階乗の最後の10桁: " . substr(gmp_strval($fact_gmp), -10) . "\n";
echo "桁数: " . strlen(gmp_strval($fact_gmp)) . "\n";
?>
gmp_init使用時の注意点
1. GMP拡張が必要
GMPを使用するには、PHPにGMP拡張がインストールされている必要があります。
<?php
if (!extension_loaded('gmp')) {
die('GMP拡張がインストールされていません。');
}
?>
2. エラー処理
不正な入力に対してはエラーが発生します。
<?php
try {
// 不正な入力
$invalid = gmp_init("not_a_number");
} catch (Exception $e) {
echo "エラー: " . $e->getMessage() . "\n";
}
// 基数の範囲チェック
try {
$invalid_base = gmp_init("123", 63); // 基数は62まで
} catch (Exception $e) {
echo "エラー: " . $e->getMessage() . "\n";
}
?>
3. メモリ使用量
非常に大きな数値を扱う場合、メモリ使用量に注意が必要です。
<?php
// 極端に大きな数の生成(メモリ使用量に注意)
function generate_large_factorial($n) {
$result = gmp_init(1);
for ($i = 1; $i <= $n; $i++) {
$result = gmp_mul($result, $i);
// 定期的にメモリ使用量をチェック
if ($i % 1000 == 0) {
$memory = memory_get_usage() / 1024 / 1024;
echo "メモリ使用量({$i}回目): {$memory} MB\n";
}
}
return $result;
}
// メモリ使用量に注意
$large = generate_large_factorial(20000);
echo "20000の階乗の桁数: " . strlen(gmp_strval($large)) . "\n";
?>
まとめ
gmp_init
関数は、PHPで大きな整数を扱うための最初のステップです。この関数を使うことで:
- PHPの標準整数型では表現できない巨大な数値を扱える
- 暗号化、素数計算、科学計算などの高度な数値処理が可能
- 様々な基数(2進数から62進数まで)で数値を初期化できる
- C実装のGMPライブラリを活用した高速な計算が可能
数値計算が重要なPHPアプリケーションを開発する際には、GMP拡張とその基本となるgmp_init
関数の使用を検討してみてください。特に暗号化、科学計算、金融計算など、精度と速度が重要な場面で真価を発揮します。
GMPを使いこなすことで、PHPの数値処理能力を大幅に拡張できるでしょう。