SICP ex1-20 ex1-22

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)

)

SICP ex1-20 ex1-22_第1张图片 SICP ex1-20 ex1-22_第2张图片

第二张图我等了老半天就是不出来结果
然后我们分析一下,第一张图显然结果是正确的,但是第二张图一目了然的结果计算机却始终无法给出答案,
我们在一联想,计算机表示数是有限制的,也就是说,当数值超过这个限制,计算机就无法表达或者正确表达
因此虽然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

)
SICP ex1-20 ex1-22_第3张图片
首先,我们可以看出(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 这里具体时间不太会算,请会的人教一下(谢谢)
另外这个测试只是保证一半以上概率正确
SICP ex1-20 ex1-22_第4张图片
以上纯属个人分析,如有错误,请纠正,感谢~~~

你可能感兴趣的:(SICP ex1-20 ex1-22)