SICP学习笔记:最大公约数和素数检测
2016-03-27 17:12
344 查看
[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
,b
,第一次n = 0,所以
a = b[n-1](a是从上一层的b传过来的), b = 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.
相关文章推荐
- P1104采药
- code forces 630 N. Forecast
- jdbc连接失败,username被替换为PC用户名
- linux下搭建生成HLS所需的.ts和.m3u8文件
- 蓝桥杯单片机设计与开发笔记(一)
- 数据结构实验之栈三:后缀式求值
- 20145223《Java程序程序设计》第4周学习总结
- 敏捷开发方法综述
- Android中的MVP
- PHP-FPM子进程数量应该如何设置?
- .NET设计规范————命名规范
- 白话Spring(中级篇)---注解(3)
- 应用中Matlab语句学习笔记总结1
- 数据结构实验之栈一:进制转换
- 各种排序算法
- Java循环语句之 for
- [shell]Shell经常使用特殊符号
- 泛型编程之“函数模板和类模板”
- 游戏服务器架构的思考
- 编程打印所有的3位质数,质数特点:只能被1和其本身整除