logo

連続二乗法の証明 📂整数論

連続二乗法の証明

アルゴリズム

自然数 $a,k,m$ に対して $b \equiv a^{k} \pmod{m}$ を次のように計算できる。


ステップ 1. $k$ の2進展開

$u_{i} = 0$ 又は $u_{i} = 1$ に対して次のように表す。 $$ k = \sum_{i=0}^{r} u_{i} 2^{i} = u_{0} + 2 u_{1} + \cdots + 2^r u_{r} $$


ステップ 2.

$a^{2^{r}} \equiv ( a^{2^{r-1}} )^2 \equiv A_{r-1}^2 \equiv A_{r} \pmod{m}$ を以下のように計算する。 $$ \begin{align*} a & & & \equiv A_{0} \pmod{m} \\ a^{2} & \equiv ( a^1 )^2 & \equiv A_{0}^2 & \equiv A_{1} \pmod{m} \\ a^{4} & \equiv ( a^2 )^2 & \equiv A_{1}^2 & \equiv A_{2} \pmod{m} \\ a^{8} & \equiv ( a^4 )^2 & \equiv A_{2}^2 & \equiv A_{3} \pmod{m} \\ & & & \vdots \end{align*} $$


ステップ 3.

$A_{0}^{u_{0}} \cdot A_{1}^{u_{1}} \cdot \cdots A_{r}^{u_{r}}$ を計算すると次の結果が得られる。 $$ a^{k} \equiv A_{0}^{u_{0}} \cdot A_{1}^{u_{1}} \cdot \cdots A_{r}^{u_{r}} \pmod{m} $$

説明

コンピュータの発展によりべき乗の計算も速くできる時代が来たが、人間は満足を知らない。連続べき乗法はモジュラ演算において、非常に大きな数を直接計算することなくその答えを得る方法だ。一度べき乗するたびに$\pmod{m}$ で割っていくために、数が$m$ 以下に落ちて、計算量が減るのだ。

例えば、$7^{327} \pmod{853}$ を計算するとしよう。$7^{327}$ に常用対数を取ると$327 \log 7 \approx 327 \cdot 0.8450 = 276.315$ であり、桁数だけで $277$ の大きな数だ。正直に全部掛けて割り算するには大きすぎるから、上のアルゴリズムを使ってみよう。まず上のアルゴリズム通りに$327$ を2進展開すると以下のようになる。 $$ 327 = 256 + 64 + 4 +2 +1 = 2^{8} + 2^{6} + 2^2 + 2^1 + 2^0 $$ ステップ2通りに計算してみると $$ \begin{align*} 7 & & \equiv 7 & \equiv 7 \pmod{853} \\ 7^{2} & \equiv ( 7^1 )^2 & \equiv 7^2 & \equiv 49 \pmod{853} \\ 7^{4} & \equiv ( 7^2 )^2 & \equiv 49^2 & \equiv 2401 \equiv 695 \pmod{853} \\ 7^{8} & \equiv ( 7^4 )^2 & \equiv 695^2 & \equiv 227 \pmod{853} \\ 7^{16} & \equiv ( 7^8 )^2 & \equiv 227^2 & \equiv 349 \pmod{853} \\ 7^{32} & \equiv ( 7^{16} )^2 & \equiv 349^2 & \equiv 675 \pmod{853} \\ 7^{64} & \equiv ( 7^{32} )^2 & \equiv 675^2 & \equiv 123 \pmod{853} \\ 7^{128} & \equiv ( 7^{64} )^2 & \equiv 123^2 & \equiv 628 \pmod{853} \\ 7^{256} & \equiv ( 7^{128} )^2 & \equiv 628^2 & \equiv 298 \pmod{853} \end{align*} $$ したがって $$ 7^{327} = 7^{256} \cdot 7^{64} \cdot 7^{4} \cdot 7^{2} \cdot 7^{1} = 298 \cdot 123 \cdot 695 \cdot 49 \cdot 7 \equiv 286 \pmod{853} $$ この方法も大変と感じるかもしれないが、ただ$327$ 回を一つずつ乗算するよりは、とても計算量が少ない。

証明

$$ \begin{align*} a^{k} =& a^{u_{0} + 2u_{1} + \cdots + 2^r u_{r} } \\ =& a^{u_{0}} a^{ 2u_{1} } \cdots a^{ 2^r u_{r} } \\ \equiv & A_{0}^{u_{0}} A_{1}^{u_{1}} \cdots A_{r}^{u_{r}} \pmod{m} \end{align*} $$

コード

以下は、$7^{327} \pmod{853}$ を連続べき乗法で計算する例のコードで、R言語で書かれている。注目すべき点は、power オプションは負の整数にも対応し、modが素数ならpower=-1を入力することで、与えられたbaseの乗算に対する逆元を求めることができる。

FPM<-function(base,power,mod) #It is equal to (base^power)%%mod
{
  i<-0
  if (power<0) {
    while((base*i)%%mod != 1) {i=i+1}
    base<-i
    power<-(-power)}
  
  if (power==0) {return(1)}
  if (power==1) {return(base%%mod)}
  
  n<-0
  while(power>=2^n) {n=n+1}
  
  A<-rep(1,n)
  A[1]=base
  
  for(i in 1:(n-1)) {A[i+1]=(A[i]^2)%%mod}
  
  for(i in n:1) {
    if(power>=2^(i-1)) {power=power-2^(i-1)}
    else {A[i]=1} }
  
  for(i in 2:n) {A[1]=(A[1]*A[i])%%mod}
  
  return(A[1])
}
 
FPM(7,327,853)
FPM(7,-1,11)