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 を取ることで、オーバーフローを避けながら正確に計算できます。本記事の内容について質問がある場合は、コメント欄でお気軽にお尋ねください。
-
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 が含まれているかを
-
C++で有理数の最小公倍数(LCM)を求める方法
本記事では、有理数(分数)の最小公倍数(LCM)を求める方法を解説します。例えば、{2/7, 3/14, 5/3} という有理数のリストが与えられた場合、そのLCMは 30/1 となります。 有理数のLCMを求める公式 この問題を解くには、まずすべての分子のLCM(最小公倍数)を計算し、次にすべての分母のGCD(最大公約数)を計算します。有理数のLCMは、次の式で表されます。 $$LCM = \frac{すべての分子のLCM}{すべての分母のGCD}$$ 各分数の倍数となる有理数は、分子がすべての分子の公倍数であり、かつ分母がすべての分母の公約数である必要があります。その中で最小のものが「分子