SICP ex1-20 ex1-22

来源:互联网 发布:dnf装备数据查询 编辑:程序博客网 时间:2024/05/19 22:02
1-20题意,有人认为既然我们已经知道了fast-exp的计算方式,那么我们的expmod就显得多余,我们可以直接计算fast-exp mod n代替expmod 他这样想对吗
直接上代码
(define (reminder x y) (if (< x y) x (reminder (- x y) y)))(define (expmod base Exp div)(define (square x) (* x x) )(define (is-even? x) (= (reminder x 2) 0))(cond ((= Exp 0) 1)((is-even? Exp) (reminder (square (expmod base (/ Exp 2) div) ) div ) )(else (reminder (* base (expmod base (- Exp 1) div) ) div ) ) ) )(define (fast-exp b n )(define (square x)(* x x))(define (is-even? x) (= (reminder n 2) 0))(define (reminder x n) (if (> x n) (reminder (- x n) n) x))(cond ((= n 0 ) 1)((is-even? n) (fast-exp b (/ n 2)))(else (* b (fast-exp b (- n 1))))))(define (expmod2 base Exp m)(reminder (fast-exp base Exp) m))

第二张图我等了老半天就是不出来结果
然后我们分析一下,第一张图显然结果是正确的,但是第二张图一目了然的结果计算机却始终无法给出答案,
我们在一联想,计算机表示数是有限制的,也就是说,当数值超过这个限制,计算机就无法表达或者正确表达
因此虽然fast-exp确实可以提高运算速度,但是,指数运算很容易超过限制,expmod2就显得有些鸡肋了
ex1-21 比较简单
用square 以及 (* (expmod b (/ e 2) m) (expmod b (/ e 2) m))在于 square只要计算一次递归 而后式则相当于二分再乘二即什么都没干,所以O(n)
ex1-22 利用费马测试变式来降低欺骗
(define (variant-fermat-test n)(define starttime (runtime))(define (reminder x y) (cond ((< x 0) (reminder (+ x y ) y))(else (if (< x y) x (reminder (- x y ) y) ))))(define (Gcd a b)(if (= b 0)  a  (Gcd b (reminder a b))))(define (Geta) (define a (+ (random (- n 2)) 2))(if (= (Gcd a n) 1) a(Geta)))(define a (Geta))(display "*")(define (symbol n) (cond ((= (reminder n 2) 0) 1) (else -1)))(define (J a n) (cond((= a 1) 1)((= (reminder a 2) 0) (* (J (/ a 2) n) (symbol (/ (- (* n n) 1)8)) ))(else (* (J (reminder n a) a) (symbol (/ (* (- a 1) (- n 1)) 4)) ) )))(define (expmod base Exp div)(define (reminder x y) (if (< x y) x (reminder (- x y) y)))(define (square x) (* x x) )(define (is-even? x) (= (reminder x 2) 0))(cond ((= Exp 0) 1)((is-even? Exp) (reminder (square (expmod base (/ Exp 2) div) ) div ) )(else (reminder (* base (expmod base (- Exp 1) div) ) div ) ) ) )(define z (J a n))(display "\n")(define endtime3 (runtime))(display (- endtime3 starttime))(define x (reminder z n))(display "\n")(define endtime1 (runtime))(display (- endtime1 starttime))(define y (expmod a (/ (- n 1) 2) n) )(display "\n")(define endtime2 (runtime))(display (- endtime2 starttime))(define flag (= x y))(display "\n")(define endtime (runtime))(display (- endtime starttime))flag)
首先,我们可以看出(J a n)占了绝大多数的时间,现在我们来分析(J a n)的时间
当a=even时,该式=符号*(J a/2 n) 显然,由于最终给出条件a=1 1 这类似于二分法递归
当a!=1 &&a!=even 该式=符号*(reminder (n a) a) 这里我们进行讨论:
n<2a 相当于(J (n-a) a) 将第一个参数变为偶数,类似于二分操作处理奇数情况
n>2a 假设取完模结果变为偶数,则类似于上一部分的情况, 至于其他则最多可能多一步还原到n<2a 这里具体时间不太会算,请会的人教一下(谢谢)
另外这个测试只是保证一半以上概率正确

以上纯属个人分析,如有错误,请纠正,感谢~~~
0 0
原创粉丝点击