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

C++で巨大な数aの(a^b) % mを計算する方法

このチュートリアルでは、非常に大きな数 a が与えられたときに、(ab) % m を効率的に計算する方法を解説します。桁数が数十桁を超えるような巨大な整数は、標準の整数型では扱えないため、文字列として受け取りながら処理するのがポイントです。

基本となる考え方

剰余演算の性質から、次の等式が成り立ちます。

(ab) % m = (a % m) × (a % m) × … × (a % m)(b回)

つまり、まず a % m の値を求めてしまえば、あとはそれを b 回掛け、毎回 m で剰余を取るだけで答えが得られます。これにより、巨大な数 a を直接扱う必要がなくなります。

解法の手順

  • 数値 a(文字列)、b、m を初期化します。
  • a % m を求める関数を作成します。
    • 結果を格納する変数を 0 で初期化します。
    • 文字列形式の数値を先頭から順に走査します。
    • 各桁の数字を「変数×10+現在の桁」の形で加えていきます。
    • 毎ステップで mod を取り、値が大きくなりすぎないようにします。
  • a % m の値を取得します。
  • b 回繰り返すループを作成し、各回で「結果 × (a % m)」を計算して mod を取ります。
  • 最終的な結果を出力します。

サンプルコード

実際のコードを見てみましょう。

#include<bits/stdc++.h>
using namespace std;

// 文字列で表された巨大な数 a の mod を計算する
unsigned int aModm(string str, unsigned int mod) {
    unsigned int number = 0;
    for (unsigned int i = 0; i < str.length(); i++) {
        number = number * 10 + (str[i] - '0');
        number %= mod;
    }
    return number;
}

// (a^b) % m を計算する
unsigned int aPowerBmodM(string &a, unsigned int b, unsigned int m) {
    unsigned int a_mod_m_result = aModm(a, m);
    unsigned int final_result = 1;
    for (unsigned int i = 0; i < b; i++) {
        final_result = (final_result * a_mod_m_result) % m;
    }
    return final_result;
}

int main() {
    string a = "123456789012345678901234567890123";
    unsigned int b = 3, m = 7;
    cout << aPowerBmodM(a, b, m) << endl;
    return 0;
}

実行結果

上記のプログラムを実行すると、次の出力が得られます。

1

計算量とさらなる最適化

この手法の時間計算量は O(b) です。b が小さい場合は十分ですが、b が非常に大きい場合(109 以上など)には非効率になります。そのようなケースでは、「繰り返し二乗法(バイナリ累乗)」を使うことで O(log b) まで高速化できます。指数 b を2進数に分解しながら累乗を組み合わせることで、乗算の回数を大幅に減らせる点がポイントです。

まとめ

巨大な整数は文字列として受け取り、剰余演算の性質を活かして段階的に mod を取ることで、オーバーフローを避けながら正確に計算できます。本記事の内容について質問がある場合は、コメント欄でお気軽にお尋ねください。

  1. C++で指定した数字dを含む数値をすべて検索する方法

    問題の概要数字 d と上限値 n が与えられたとき、0 から n までの範囲に存在する、数字 d を含むすべての数値を見つけることを考えます。例えば、n = 20、d = 3 の場合、該当する数値は [3, 13] の2つになります。また、n = 100、d = 3 の場合は、3、13、23、30〜39、43、53 といった具合に、3 が現れるすべての数値が該当します。解決のアプローチこの問題は、各数値を文字列に変換することでシンプルに解決できます。手順は以下のとおりです。1. 各数値を to_string() で文字列に変換する2. 変換した文字列の中に、対象の数字 d が含まれているかを

  2. C++で有理数の最小公倍数(LCM)を求める方法

    本記事では、有理数(分数)の最小公倍数(LCM)を求める方法を解説します。例えば、{2/7, 3/14, 5/3} という有理数のリストが与えられた場合、そのLCMは 30/1 となります。 有理数のLCMを求める公式 この問題を解くには、まずすべての分子のLCM(最小公倍数)を計算し、次にすべての分母のGCD(最大公約数)を計算します。有理数のLCMは、次の式で表されます。 $$LCM = \frac{すべての分子のLCM}{すべての分母のGCD}$$ 各分数の倍数となる有理数は、分子がすべての分子の公倍数であり、かつ分母がすべての分母の公約数である必要があります。その中で最小のものが「分子