大きな素数のa ^ (p-2)
場合、通常は計算できないことをしなければならないからです。
べき乗剰余が必要なため、IVlad で言及されている 2 乗によるべき乗 では、最大でサイズの数の剰余乗算のみが必要です。中間結果は によって制限されるため、大きな素数では計算できませんが、通常は制限されます。その方法は簡単に実装できます。Θ(log p)
p-1
p^2
a^(p-2)
(a ^ (p-2)) % p
unsigned long long invert_mod(unsigned long long a, unsigned long long p) {
unsigned long long ex = p-2, result = 1;
while (ex > 0) {
if (ex % 2 == 1) {
result = (result*a) % p;
}
a = (a*a) % p;
ex /= 2;
}
return result;
}
しかし、いくつかの欠点があります。使用されている型で表現可能でなければなりません (任意精度の整数が使用されている場合は [ huge(p-1)^2
を除いて] 問題ではありません)。そうしないと、オーバーフローのために無効な結果が得られ、少なくとも剰余乗算が常に使用されます。 p
log (p-2)/log 2
user448810 で提案されている拡張ユークリッド アルゴリズム、または同等の連分数法は、 より大きい中間値を生成することはありませp
んp
。さらに、素数だけでなく、任意の 2 つの互いに素な数についても剰余逆数を計算します。
unsigned long long invert_mod(unsigned long long a, unsigned long long p) {
unsigned long long new = 1, old = 0, q = p, r, h;
int pos = 0;
while (a > 0) {
r = q%a;
q = q/a;
h = q*new + old;
old = new;
new = h;
q = a;
a = r;
pos = !pos;
}
return pos ? old : (p - old);
}
コードは少し長くなりますが、最適化コンパイラは反復ごとに 1 つの除算のみを使用して短いループにコンパイルする必要があります。