SICP学习笔记:最大公约数和素数检测

时间:2022-12-01 00:30:27

[0]最大公约数:求最大公约数的一个简单办法是欧几里德算法.对于a,b,GCD(a,b)= GCD(b,r)。b是a/b的余数证明如下:

a = kb + r(1),设 m = GCD(a,b),a = m*a1,b = m*b1.所以 (1)可以变形: a1 = kb1 + r/m;显然r/m必然是一个整数,记为r1。得到a1 = kb1 + r1(2)。现在证明m也是b和r的最大公约数,只须证b1和r1已没有公约数了(除了1)

不妨采取反正法:假设b1,r1还有公约数m2,则(2)变形: a1/m2 = kb1/m2+r1/m2,那么a1/m2 = kb2+r2,a1/m2必然也是整数,那么a1/m2 = a2,得到 a2 = kb2 +r2,这说明m不是a,b的最大公约数,因为m*m2大于m,且m*m2也是a,b的公约数,这与假设矛盾!。从而得证!

(define (f a b)
( if ( = b 0) ;a%b == 0
a
(f b (remainder a b))
)

)

练习1.20:计算该程序分别采用正则序和应用序求值时调用了多少次reaminder。

[1]应用序,这个很简单,一共尾递归了5次,i1但是最后一次没有调用,所以调用了4次remainder。

[2]正则序比较麻烦:首先假设两个参数调用的次数分别是a[n],b[n],第一次n = 0,所以

a[n] = b[n-1](a是从上一层的b传过来的),
b[n] = a[n-1]+b[n-1]+1

(b是由reamainder a b计算出来的),再加上每一次if的判断.得到的结果是 b[0]+b[1]+b[2]+b[3]+b[4]+a[4](a[4]是返回a时的调用),最后结果是18次.

练习1.21,寻找最小因子:

(define (square a)( * a a))
(define (find-divsor k n )
( cond((> (square k) n) n)
((= (remainder n k) 0) k)
(else (find-divsor (+ k 1) n))
)

)

(define (smallest-divisor n)
(find-divsor 2 n)
)

练习1.22,寻找三个最小素数

 (define (next-odd n)
(if (odd? n)
(+ 2 n)
(+ 1 n))
)

(define (continue-primes n count)
(cond ((= count 0)
(display "are primes."))

((prime? n)
(display n)
(newline)
(continue-primes (next-odd n) (- count 1)))

(else
(continue-primes (next-odd n) count))
)
)

(define (search-for-primes n)
( let ((start-time (real-time-clock)))
(continue-primes n 3)
(- (real-time-clock) start-time)

)
)

练习1.23:

(define (next n) 
(if(= n 2) 3)
(+ n 2))

(define (find-divsor k n )
( cond((> (square k) n) n)
((= (remainder n k) 0) k)
(else (find-divsor (next k) n))
)

)

练习1.24,根据费马小定理来实现search-for-primes。

(define (expod base ex n) 
(cond ((= ex 0) 1)
((even? ex) (remainder (square (expod base (halve ex) n))
n)
)

(else (remainder (* base (expod base (- ex 1) n))
n)
)
)
)

(define (fermat-test n)
(define (try-it a)
(= (expod a n n) a))

(try-it (+ 1 (random (- n 1)))))


(define (fast-prime n times)
( cond ((= times 0)true)
((fermat-test n)(fast-prime n (- times 1)))
(else false)
)

)

练习1.27,写一个过程,以整数n为参数,对每个a

(define(do-one-fermat-test n k)
( cond ((= k n) 1);满足所有k<n,返回1
((= (expod k n n) k )(do-one-fermat-test n (+ k 1)));继续测试
(else 0 );不满足本次测试,返回0
)

)

(define(fermat-test-all n)
( do-one-fermat-test n 1)
)

练习1.28,费马检测的一种不会被欺骗的变形:MIller_rabin检测,如果n是素数,a是小于n的任何整数,则a^(n-1)%n恒等于1.同时,如果存在a!=1且a!=n-1,a^2%n=1,则可以断言n不是素数.请实现这样的检测过程.

(define (trival-squareroot-test a n)
( if ( and (not (= a 1))
(not (= a (- n 1)))
(= (remainder (square a) n) 1)
)

0

a
)

)

(define (expod base ex n)
(cond ((= ex 0) 1)
((even? ex) ( remainder (square (trival-squareroot-test (expod base (halve ex) n) n))n))
(else (remainder (* base (expod base (- ex 1) n))
n)
)
)
)


(define (fermat-test n)
(define (try-it a)
(= (expod a (- n 1) n) 1))

(try-it (+ 1 (random (- n 1)))))



(define (fast-prime n times)
( cond ((= times 0)true)
((fermat-test n)(fast-prime n (- times 1)))
(else false)
)

)

对于这个题目,比较巧妙的一点的是检测是否存在非平凡平凡根的时候,如果存在返回了0,这样expod最后的结果就是0。不需要做任何其他的判断,因为0肯定不等于1.