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)

)


第二張圖我等了老半天就是不出來結果
然後我們分析一下,第一張圖顯然結果是正確的,但是第二張圖一目瞭然的結果計算機卻始終無法給出答案,
我們在一聯想,計算機表示數是有限制的,也就是說,當數值超過這個限制,計算機就無法表達或者正確表達
因此雖然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 這裏具體時間不太會算,請會的人教一下(謝謝)
另外這個測試只是保證一半以上概率正確

以上純屬個人分析,如有錯誤,請糾正,感謝~~~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章