expmod 모듈러 지수화 알고리즘 친절한 설명

모듈러 지수화 알고리즘이란

모듈러 지수화 알고리즘이란,
어떤 수를 지수연산한 결과를 다른 수로 나누어 나머지를 구하는 알고리즘입니다.
지수연산이 다 끝나기 전에 연산하는 수의 크기를 크게 줄여줘서 메모리 친화적인 알고리즘입니다.

아래의 식이 모듈러 지수화 알고리즘의 핵심인 모듈러 곱셈입니다.

abmodm=[(amodm)(bmodm)]modmab\mod{m}=[(a\mod{m})(b\mod{m})]\mod{m}
(amodba \mod b)는 a를 b로 나눈 나머지를 뜻합니다.

놀랍지 않습니까?
(abab의 나머지)를 구하려고 하는데,
이 값은 (aa의 나머지)와 (bb의 나머지)의 곱의 나머지와 같습니다.

모듈러 곱셈 증명

abmodm=[(amodm)(bmodm)]modmab\mod{m}=[(a\mod{m})(b\mod{m})]\mod{m}을 증명하겠습니다.

a=m×q+ra=m\times q'+r'
b=m×q+rb=m\times q''+r''
(qq'qq''는 몫, rr'rr''는 나머지)

abmodmab\mod{m}
=(m×q+r)(m×q+r)modm=(m\times q'+r')(m\times q''+r'')\mod{m}
=(m2qq+mqr+mqr+rr)modm=(m^2q'q''+mq''r+mq'r''+r'r'')\mod{m}

여기서 m을 인수로 포함한 항은 modm\mod m에 의해 지워집니다.

abmodmab\mod{m}
=rrmodm=r'r''\mod{m}

abmodm=[(amodm)(bmodm)]modm∴ ab\mod{m}=[(a\mod{m})(b\mod{m})]\mod{m}

모듈러 곰셈을 이용한 expmod

bnmodmb^n\mod{m}을 계산한다고 합시다.

n=2kn=2k라면, (짝수라면)

b2kmodmb^{2k}\mod{m}
=[(bkmodm)(bkmodm)]modm=[(b^k\mod{m})(b^k\mod{m})]\mod{m}
=(bkmodm)2modm=(b^k\mod{m})^2\mod{m}

n=2k+1n=2k+1이라면, (홀수라면)

b2k+1modmb^{2k+1}\mod{m}
=[(bmodm)(b2kmodm)]modm=[(b\mod{m})(b^{2k}\mod{m})]\mod{m}
=b(b2kmodm)modm=b(b^{2k}\mod{m})\mod{m}
(b=mq+rb=mq+r로 놓고 계산해 보면 m이 포함된 부분을 결국 사라지므로, (bmodm)(b\mod{m})bb로 대체 가능하다.)

위의 알고리즘을 사용한다면, 메모리를 초과하지 않고도 지수연산의 결과에 모듈러 연산을 할 수 있습니다.
구현된 프로시저를 스킴으로 나타내면 아래와 같습니다.

(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(remainder (square (expmod base (/ exp 2) m))
m))
(else
(remainder (* base (expmod base (- exp 1) m))
m))))

긴 글 읽어주셔서 감사합니다.