C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でGCD(a^n, c)を求める方法 ― a、n、cが1〜10^9の範囲の場合

本記事では、片方の数が (10^9)^(10^9) にもなり得るような巨大な2つの数の最大公約数(GCD)を求める方法を解説します。この規模の数値は、long型をはじめとする標準的なデータ型には格納できません。例えば、a = 10248585、n = 1000000、b = 12564 の場合、GCD(a^n, b) の結果は 9 になります。

数が非常に大きいため、通常のユークリッドの互除法を直接適用することはできません。そこで、O(log n) の計算量で実行できる「繰り返し二乗法(modular exponentiation)」を活用します。

解法の考え方

ここで重要となるのが、次の性質です。
GCD(a^n, b) = GCD(a^n mod b, b)
つまり、巨大な a^n を実際に計算する必要はなく、「a^n を b で割った余り」だけを求めればよいことになります。繰り返し二乗法を使えば、この剰余を O(log n) の計算量で効率的に求められます。

C++での実装例

#include<iostream>
#include<algorithm>
using namespace std;
long long power(long long a, long long n, long long b) {
    long long res = 1;
    a = a % b;
    while (n > 0) {
        if (n & 1)
            res = (res*a) % b;
        n = n>>1;
        a = (a*a) % b;
    }
    return res;
}
long long bigGCD(long long a, long long n, long long b) {
    if (a % b == 0)
        return b;
    long long exp_mod = power(a, n, b);
    return __gcd(exp_mod, b);
}
int main() {
    long long a = 10248585, n = 1000000, b = 12564;
    cout << "GCD value is: " << bigGCD(a, n,b);
}

出力結果

GCD value is: 9

コードの解説

power関数は繰り返し二乗法を実装したものです。指数 n を2進数として扱い、ビットが立っている場合にのみ結果に現在の底を掛け、各ステップで底を2乗しながら剰余を取り続けることで、オーバーフローを防ぎつつ高速に計算します。

bigGCD関数では、まず a が b で割り切れるかどうかを判定します。割り切れる場合はGCDが b そのものになるため、そのまま b を返します。そうでなければ、power関数で a^n mod b を求め、その値と b のGCDを標準関数 __gcd で計算して返します。

この手法により、指数が10^9を超えるような巨大な場合でも、わずか O(log n) の計算量で正確にGCDを求めることができます。

  1. C++で2つの数の最大公約数(GCD)を求めるプログラム

    最大公約数(GCD)とは最大公約数(GCD: Greatest Common Divisor)とは、2つの整数をどちらも割り切る正の整数のうち、最も大きい数のことです。プログラミングの基礎的なアルゴリズム問題としてよく取り上げられるテーマであり、分数の約分や暗号処理など、さまざまな場面で活用されます。例として、45と27という2つの数を考えてみましょう。45 = 5 × 3 × 327 = 3 × 3 × 3両方の数に共通する素因数は「3 × 3」であるため、45と27の最大公約数は9となります。方法1:ユークリッドの互除法による実装2つの数の最大公約数を求める最も効率的な方法が「ユークリッド

  2. CおよびC++の最新標準規格ドキュメントはどこで入手できる?

    プログラミング言語の標準規格に沿った開発を行うには、公式の規格ドキュメントを参照することが重要です。ここでは、C言語およびC++の最新標準規格ドキュメントを入手できる場所を紹介します。 C標準規格ドキュメントの入手先 現在のC言語標準規格(ISO/IEC 9899)の公式ドキュメントは、ANSIが運営するオンラインストア「ANSI Webstore」から購入できます。以下のリンクからアクセスしてください。 https://webstore.ansi.org/RecordDetail.aspx?sku=INCITS%2FISO%2FIEC+9899-2012 C++標準規格ドキュメントの入手