Scheme 从数学上讲,为什么一个数的指数乘以另一个数的SICP算法有效?
给出了以下步骤:Scheme 从数学上讲,为什么一个数的指数乘以另一个数的SICP算法有效?,scheme,sicp,exponentiation,modular-arithmetic,Scheme,Sicp,Exponentiation,Modular Arithmetic,给出了以下步骤: (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))
(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
然而,从数学的角度来看,我就是看不出它是如何工作的。正如所强调的,它打算使用一个属性,即对于任何正整数a、b和n,(ab)mod n=[(a mod n)(b mod n)]mod n,但我看不出它实际上是如何使用它的。考虑<代码>(ExpMod 5 3 3)< /> >:
(expmod 5 3)
。从数学上来说,这意味着我们要求的是(5^3)mod 3(余数(*5(expmod 5(-3 1)3))3
,即(余数(*5(expmod 5 2 3))3
。从数学上讲,这是[5*[(5^2)mod 3]]mod 3。由于此表达式中的首字母5没有附加mod 3,因此此表达式在(ab)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
时
((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
为真。我们需要证明,((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))))))
如果我们将其重命名为closer match 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)
,它给出(余数(平方a)m)=(余数(平方m))m
。我们可以将它与偶数
子句一起使用,以便
(remainder (square (expt base (/ exp 2))) m)
变成:
(remainder (square (remainder (expt base (/ exp 2)) m))
m)
在这中间我们有一个指数的余数,所以这相当于:
(remainder (square (expmod base (/ exp 2) m)) m)
(remainder (* base (remainder E m)) m)
使用新的偶数
子句
(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))
为了简化odd子句,现在让我们使用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)
我们可以忽略(*(商em)m)
,因为包含此项的任何项都可以被m
整除,因此在执行外部余数时,计算结果将为0
,因此这相当于:
(remainder (square (expmod base (/ exp 2) m)) m)
(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))))
关于第2点,请注意,(a*(b mod n))mod n也等于(a*b)mod n.@molbdnilo奇怪,如果这样美好的事情是真的,我会期望它在前面和中间。我错过了吗?它是根据加法规则得出的。(大多数值得知道的事情在维基百科中根本没有提到。)@molbdnilo来自加法规则?如果它是琐碎的,我就不能这么容易地看到它。因此,最终,奇数分支不使用所讨论的属性?(余数(*base(余数em))m)
的形式似乎是[a*(b mod m)]mod m。由于这是从(余数(*base E)m)
中推导出来的,因此我得出的结论是否正确,即您提供了与Sorawe Porncharoenwase具有相同属性的证据?i、 e.(ab)mod n=[a(b mod n)]mod n?@J.Mini是的,我没有在奇数子句中使用它。当消除(*(商em)m)
时,可能有一种方法可以使用它,但我不够聪明,看不到它,而且在任何情况下,它似乎有点做作。我没有仔细看索拉维的答案,正忙着写我自己的:-),也许我会说这个答案是建立在他的基础上的?我很惊讶这不是。你已经证明的版本比他们提供的版本更强大。当有一个更强大的版本不需要额外的概念时,他们为什么要给出一个具体的例子?此外,我很惊讶SICP的脚注中没有这一点。这让我怀疑我是否误读了它。是吗?嗯,维基百科并不包含所有内容,而且,[(a mod n)(b mod n)]mod n
也没有什么问题。有人可能会说,SICP的错误在于他们没有准确地遵循方程式,而解决办法是使用(*(余数基数m)…)
而不是(*基数…)
。事实上,从性能的角度来看,最好使用(*(余数基数m)…)
。例如,请参阅以提高球拍中的模块化expt
的性能。