[PHP]大数演算マスター: gmp_sqrt関数で実現する高精度平方根計算

PHP

はじめに

数学的計算において平方根(ルート)の算出は基本的かつ重要な操作です。しかし、PHPの標準関数では大きな整数の平方根を精密に計算することは困難です。そこで登場するのが、GMP拡張モジュールのgmp_sqrt関数です。この記事では、高精度な平方根計算を実現するgmp_sqrtの使い方から応用例まで、詳しく解説します。

gmp_sqrt関数とは?

gmp_sqrtは、GMP(GNU Multiple Precision)拡張モジュールが提供する関数で、任意の精度の大きな非負整数の平方根を計算します。平方根の結果は整数に切り捨てられるため、正確な整数の平方根が得られます。

基本構文

gmp_sqrt(GMP|string|int $num): GMP

パラメータ

  • $num: 平方根を計算したいGMP数値オブジェクト、整数、または数値を表す文字列(負の数は指定できません)

戻り値

  • 入力された数値の平方根をGMP数値オブジェクトとして返します
  • 計算結果は整数に切り捨てられます

基本的な使用例

まずは、gmp_sqrtの基本的な使い方を見てみましょう:

<?php
// 単純な平方根計算
$number = gmp_init(25);
$sqrt = gmp_sqrt($number);
echo "25の平方根: " . gmp_strval($sqrt) . "\n"; // 出力: 5

// 大きな数値の平方根
$bigNumber = "123456789012345678901234567890";
$bigSqrt = gmp_sqrt($bigNumber);
echo $bigNumber . "の平方根: " . gmp_strval($bigSqrt) . "\n";
// 出力: 11111111106055556

// 完全平方数でない場合(切り捨て)
$nonPerfect = gmp_init(10);
$approxSqrt = gmp_sqrt($nonPerfect);
echo "10の平方根(整数部分): " . gmp_strval($approxSqrt) . "\n"; // 出力: 3
?>

様々な入力形式での使用

gmp_sqrt関数は柔軟な入力形式をサポートしています:

<?php
// 整数を直接渡す
echo "16の平方根: " . gmp_strval(gmp_sqrt(16)) . "\n"; // 4

// 文字列形式の数値
echo "100の平方根: " . gmp_strval(gmp_sqrt("100")) . "\n"; // 10

// 16進数表記(プレフィックス「0x」が必要)
echo "0x100の平方根: " . gmp_strval(gmp_sqrt("0x100")) . "\n"; // 16

// GMP数値オブジェクト
$num = gmp_init("10000000000");
echo "10000000000の平方根: " . gmp_strval(gmp_sqrt($num)) . "\n"; // 100000
?>

実践的な応用例

例1: 完全平方数かどうかを判定する関数

<?php
function isPerfectSquare($num) {
    // GMP数値オブジェクトに変換
    $num = gmp_init($num);
    
    // 負の数は完全平方数ではない
    if (gmp_sign($num) < 0) {
        return false;
    }
    
    // 平方根を計算
    $sqrt = gmp_sqrt($num);
    
    // 平方根を二乗して元の数と一致するか確認
    $squared = gmp_pow($sqrt, 2);
    
    return gmp_cmp($squared, $num) === 0;
}

// テスト
$testNumbers = [16, 25, 100, 10, 17, 12345654321];
foreach ($testNumbers as $number) {
    echo $number . "は完全平方数";
    echo isPerfectSquare($number) ? "です。\n" : "ではありません。\n";
}
?>

例2: 平方根の小数部分を近似計算

GMPは整数演算のためのライブラリですが、工夫することで小数部分も近似計算できます:

<?php
function approximateSqrt($num, $precision = 10) {
    // 正の数かチェック
    if (gmp_sign($num) < 0) {
        throw new InvalidArgumentException("負の数の平方根は計算できません");
    }
    
    // 整数部分を計算
    $integerPart = gmp_sqrt($num);
    
    // 完全平方数なら小数部分はなし
    if (gmp_cmp(gmp_pow($integerPart, 2), $num) === 0) {
        return gmp_strval($integerPart);
    }
    
    // 小数点以下の計算のため、数値を拡大
    $scaleFactor = gmp_pow(10, 2 * $precision);
    $scaledNum = gmp_mul($num, $scaleFactor);
    
    // 拡大した数値の平方根を計算
    $scaledSqrt = gmp_sqrt($scaledNum);
    
    // 整数部と小数部を結合
    $intPart = gmp_strval($integerPart);
    $decPart = substr(gmp_strval($scaledSqrt), strlen($intPart), $precision);
    
    return $intPart . "." . $decPart;
}

// 様々な数値の平方根を近似計算
$testValues = [2, 3, 10, 123456789];
foreach ($testValues as $value) {
    echo $value . "の平方根(近似値): " . approximateSqrt($value, 15) . "\n";
    // PHPの標準関数と比較
    echo "標準関数での計算結果: " . sqrt($value) . "\n\n";
}
?>

例3: 数論での応用 – ペル方程式の解法

ペル方程式(x² – Dy² = 1)の解を見つける関数:

<?php
function solvePellEquation($D, $limit = 100) {
    // Dが完全平方数の場合は自明な解しかない
    if (isPerfectSquare($D)) {
        return ["x" => 1, "y" => 0];
    }
    
    // 連分数展開による解法
    $a0 = gmp_sqrt($D);
    $m = 0;
    $d = 1;
    $a = $a0;
    
    // 収束分数の計算用
    $p1 = 1;
    $p2 = gmp_strval($a0);
    $q1 = 0;
    $q2 = 1;
    
    for ($i = 1; $i <= $limit; $i++) {
        $m = gmp_sub(gmp_mul($a, $d), $m);
        $d = gmp_div_q(gmp_sub($D, gmp_pow($m, 2)), $d);
        $a = gmp_div_q(gmp_add($a0, $m), $d);
        
        // 収束分数を計算
        $p = gmp_add(gmp_mul($a, $p2), $p1);
        $q = gmp_add(gmp_mul($a, $q2), $q1);
        
        // x² - Dy² = 1 を満たすか確認
        $left = gmp_sub(gmp_pow($p, 2), gmp_mul(gmp_mul($D, $q), $q));
        if (gmp_cmp($left, 1) === 0) {
            return ["x" => gmp_strval($p), "y" => gmp_strval($q)];
        }
        
        $p1 = $p2;
        $p2 = $p;
        $q1 = $q2;
        $q2 = $q;
    }
    
    return ["x" => "解が見つかりませんでした", "y" => "解が見つかりませんでした"];
}

// ペル方程式 x² - 2y² = 1 の解を求める
$D = 2;
$solution = solvePellEquation($D);
echo "x² - {$D}y² = 1 の最小解: x = {$solution['x']}, y = {$solution['y']}\n";
// 出力: x² - 2y² = 1 の最小解: x = 3, y = 2
?>

gmp_sqrt と関連関数

gmp_sqrtは他のGMP関数と組み合わせることで、より高度な数学計算が可能になります:

  • gmp_sqrtrem: 平方根とその剰余を計算
  • gmp_pow: 累乗計算
  • gmp_perfect_square: 完全平方数かどうかを判定

gmp_sqrtremの使用例

<?php
$number = 10;
list($sqrt, $remainder) = gmp_sqrtrem($number);
echo $number . "の平方根: " . gmp_strval($sqrt) . "\n";
echo "剰余: " . gmp_strval($remainder) . "\n";
// 出力: 
// 10の平方根: 3
// 剰余: 1
// (3² = 9, 10 - 9 = 1)
?>

性能と注意点

性能面での利点

  1. 高精度計算: 標準のPHP関数では扱えない巨大な整数の平方根も正確に計算できます
  2. 高速処理: 内部でアルゴリズムが最適化されているため、大きな数値でも高速に計算できます

注意点

  1. 負の数の扱い: gmp_sqrtは負の数の平方根を計算できません(実行時エラーになります)
  2. 小数部分の切り捨て: 結果は整数に切り捨てられるため、完全平方数でない場合は近似値となります
  3. GMP拡張の必要性: この関数を使用するには、PHPにGMP拡張モジュールがインストールされている必要があります
<?php
// 拡張モジュールがインストールされているか確認
if (extension_loaded('gmp')) {
    echo "GMP拡張モジュールは利用可能です。\n";
} else {
    echo "GMP拡張モジュールがインストールされていません。\n";
}
?>

まとめ

gmp_sqrt関数は、PHPでの大きな整数の平方根計算において非常に強力なツールです。標準のPHP関数では精度の問題が生じる大きな数値でも、正確に平方根を計算できます。数論、暗号論、金融計算など、高精度な平方根計算が必要なアプリケーションで活躍することでしょう。

GMPライブラリの他の関数と組み合わせることで、PHPでも高度な数値計算が可能になります。大きな整数を扱う必要がある場合は、ぜひGMP拡張モジュールとgmp_sqrt関数を活用してみてください。


この記事が、PHPでの高精度な平方根計算に悩む開発者の方々のお役に立てば幸いです。GMPライブラリの強力な機能を使いこなして、より高度な数値計算を実現しましょう。

タイトルとURLをコピーしました