问题描述
Section 1.2.6 of SICP给出以下过程:
(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))))
作者声称它“ 计算另一个模的数字的指数”。例如(expmod 5 3 n)
应该返回(5 ^ 3)mod n。
但是,从数学的角度来看,我只是看不到它是如何工作的。如footnote 46所强调的那样,它打算对以下任意正整数a,b和n使用以下属性:(ab)mod n = [(a mod n)(b mod n)] mod n,但是我看不到它是如何实际使用的。考虑(expmod 5 3 3)
:
- 首先,我们叫
(expmod 5 3 3)
。从数学上讲,这意味着我们要的是(5 ^ 3)mod 3。 - 由于第二个参数为奇数,因此我们计算
(remainder (* 5 (expmod 5 (- 3 1) 3)) 3)
,即(remainder (* 5 (expmod 5 2 3)) 3)
。从数学上讲,这是[5 * [(5 ^ 2)mod 3]] mod3。由于此表达式中的开头5没有附加mod 3,因此(ab中的 not )mod n = [(a mod n)(b mod n)] mod n形式,因此它无法使用预期的属性。
因此,鉴于这似乎没有使用预期的属性,为什么该算法起作用?我忽略了模块化算术的什么特性?
解决方法
(ab) mod n = [a (b mod n)] mod n
也是如此。
这是对a
的归纳证明。
基本情况:当a = 0
,(0b) mod n = 0 mod n = [0 (b mod n)] mod n
时。
归纳案例:
根据归纳假设,假设(ab) mod n = [a (b mod n)] mod n
为真。我们需要证明((a+1) b) mod n = [(a + 1) (b mod n)] mod n
。
((a+1) b) mod n
= (ab + b) mod n
= (ab mod n) + (b mod n)
= [a (b mod n)] mod n + (b mod n) by induction hypothesis
= [a (b mod n)] mod n + (b mod n) mod n
= [a (b mod n) + (b mod n)] mod n
= [(a + 1) (b mod n)] mod n
根据需要。
得出结论,证明
(ab) mod n = [a (b mod n)] mod n
事实上,您可以看到
(ab) mod n = [(a mod n) (b mod n)] mod n
是其后的结果。这是一个证明:
(ab) mod n
= [a (b mod n)] mod n by what we just proved
= [(b mod n) a] mod n
= [(b mod n) (a mod n)] mod n by what we just proved
= [(a mod n) (b mod n)] mod n
,
这是来自1.2.4的fast-exp的定义,引用如下:
(define (fast-expt b n)
(cond ((= n 0) 1)
((even? n) (square (fast-expt b (/ n 2))))
(else (* b (fast-expt b (- n 1))))))
如果我们将事物重命名为更匹配expmod,则它看起来像这样:
(define (expt base exp)
(cond ((= exp 0) 1)
((even? exp)
(square (expt base (/ exp 2))))
(else
(* base (expt base (- exp 1))))))
要获得朴素的expmod
,我们现在可以仅计算每个子句的其余部分:
(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(remainder (square (expt base (/ exp 2))) m))
(else
(remainder (* base (expt base (- exp 1))) m))
到目前为止,我们还没有使用脚注(ab) mod m = ((a mod m)(b mod m) mod m)
。当然,其中的一个特殊情况是(aa) mod m = ((a mod m)(a mod m) mod m)
,它得到(remainder (square a) m) = (remainder (sqaure (remainder a m)) m)
。我们可以在even
子句中使用它,这样
(remainder (square (expt base (/ exp 2))) m)
成为:
(remainder (square (remainder (expt base (/ exp 2)) m))
m)
在此过程中,我们有一个指数的余数,所以它等效于:
(remainder (square (expmod base (/ exp 2) m)) m)
使用新的even
子句
(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(remainder (square (expmod base (/ exp 2) m))
m))
(else
(remainder (* base (expt base (- exp 1))) m))
为简化奇数子句,现在暂时使用E
代替(expt base (- exp 1))
。
通过使用mod
的定义属性,我们可以说任意数量的a
:
a = (+ (* (quotient a m) m) (remainder a m))
所以也确实如此:
E = (+ (* (quotient E m) m) (remainder E m))
将其替换为我们的odd
子句:
(remainder (* base E) m)
给予:
(remainder (* base (+ (* (quotient E m) m) (remainder E m))) m)
我们可以忽略(* (quotient E m) m)
,因为包含该术语的任何术语都可以被m
整除,因此在做外部0
时将得出remainder
,因此等效于:
(remainder (* base (remainder E m)) m)
将E扩展为原始值:
(remainder (* base (remainder (expt base (- exp 1)) m)) m)
再一次,在中间,我们有一个指数的余数,所以变成了:
(remainder (* base (expmod base (- exp 1) m)) m)
我们的expmod
现在是:
(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))))