C++でフェルマーの小定理を検証する方法
フェルマーの小定理とは
フェルマーの小定理とは、p を素数としたとき、任意の整数 a に対して「ap − a が p の倍数になる」という定理です。
これを剰余演算(mod)で表現すると、次のようになります。
ap ≡ a (mod p)
さらに、a が p で割り切れない場合(a と p が互いに素である場合)は、両辺を a で割ることで次の形に変形できます。
ap−1 ≡ 1 (mod p)
この記事で扱う問題
ここでは、2つの整数 a と p が与えられ、これらの値に対してフェルマーの小定理が実際に成り立つかどうかを検証します。具体的には、次のいずれかの式が成立するかを確認します。
- ap ≡ a (mod p)
- ap−1 ≡ 1 (mod p) ※a が p で割り切れない場合
具体例で理解しよう
入力: a = 3, p = 11
出力: True(定理は成立)
解説:
ap−1 ≡ 1 (mod p) が成り立つかを順に確認していきます。
- 310 = 59049
- 59049 − 1 = 59048
- 59048 ÷ 11 = 5368 → 割り切れるため、定理は成立
C++による実装例
以下は、与えられた a と p に対してフェルマーの小定理が成立するかを判定するプログラムです。
#include <iostream>
#include <math.h>
using namespace std;
int fermatLittle(int a, int p) {
int powVal;
if(a % p == 0){
// a が p で割り切れる場合は a^p ≡ a (mod p) を確認
powVal = pow(a, p);
if((powVal - a) % p == 0){
cout<<"フェルマーの小定理は成立します!";
}
else{
cout<<"フェルマーの小定理は成立しません!";
}
}
else {
// a が p で割り切れない場合は a^(p-1) ≡ 1 (mod p) を確認
powVal = pow(a, (p - 1));
if((powVal - 1) % p == 0){
cout<<"フェルマーの小定理は成立します!";
}
else{
cout<<"フェルマーの小定理は成立しません!";
}
}
}
int main()
{
int a = 3, p = 11;
fermatLittle(a, p);
return 0;
}
実行結果
フェルマーの小定理は成立します!
実装時の注意点
上記のコードでは説明のため pow() 関数を直接使用していますが、pow() は戻り値が浮動小数点型(double)であり、指数が大きくなるとオーバーフローや精度誤差が発生する可能性があります。
実際の競技プログラミングや暗号処理などでは、「繰り返し二乗法(高速べき乗)」を使って各乗算のたびに mod を取ることで、大きな数でも正確かつ効率的に計算するのが一般的です。
-
オイラーの定理を実装するC++プログラム:モジュラ逆元の求め方
本記事では、オイラーの定理に基づいてモジュラ乗法逆元(modular multiplicative inverse)を求めるC++プログラムを紹介します。モジュラ乗法逆元が存在するためには、対象となる数と法(modular value)が互いに素である必要があります。モジュラ乗法逆元とは整数 a の法 m におけるモジュラ乗法逆元とは、次の式を満たす整数 x のことです。(a * x) % m = 1このような x が存在するのは、a と m の最大公約数が1(つまり互いに素)の場合のみです。オイラーの定理を利用すると、効率的に逆元を計算できます。アルゴリズム以下の手順で、1から入力値までの各
-
C++で学ぶフェルマー素数判定テスト:アルゴリズムと実装コード
フェルマー素数判定テスト(Fermat Primality Test)は、与えられた整数が素数かどうかを確率的に判定するための古典的な手法です。本記事では、このアルゴリズムの仕組みと、C++による実装コードをわかりやすく解説します。 フェルマーの小定理の基本 フェルマー素数判定は「フェルマーの小定理」に基づいています。p を素数、a を p の倍数でない任意の整数とすると、次の関係が常に成り立ちます。 ap−1 ≡ 1 (mod p) この性質を利用し、判定したい数 n に対してランダムな底 a を選び、an−1 mod n が 1 と一致するかを確認します。一致しなければ n は確実に合成数