没想到家里网欠费了,家人没回来,只能看书度日了….
于是乎翻了图书馆借来快一个月的SICP,开看…
(该记录,包含书中的大部分练习,以及一些书中内容的感受,做了85%~90%的代码题)
还有scheme的正则序、应用序求值,还有if、cond、define这些特殊形式等等知识。
代码慢慢整理,先贴上加上一些自己的理解,代码的顺序和练习的都差不多,所以有点懒得求标题号了(懒
(看了大概4天了,当然实际的时间并没那么多,刚好算是看完第一章,第一章大多都是数值计算,练习做完的感觉,从开始对递归与迭代的陌生,在高级语言如C++或者脚本python中有for while 之类的循环来写迭代,而在scheme(lisp的方言)上,都是以递归写,然后来写递归过程与迭代过程,感觉自己对递归的写法更加掌握以及理解,以及迭代的理解,在看的过程中,发现很多抽象思想很好,值得去学习,还算是复习到了一些数学知识以及了解一些数值计算方法,还有gcd的写法,以前傻不拉几的一步一步用循环迭代写,现在发现了短短几行的递归代码就能实现,也了解到了计算中数学的重要性)
#lang planet neil/sicp
(define (inc x)
(+ x 1))
(define (dec x)
(- x 1))
(define (square x)
(* x x))
(define (max x y z)
(define (max-iter x y)
(if (< x y) y x))
(if (= (max-iter x y) y) (max-iter y z) (max-iter x z)))
(define (sqrt x)
(define (sqrt-iter val rval)
(define (b-enough val rval) //bad-way
(< (abs (- (* val val) rval)) 0.0001))
(define (g-enough val rval) //good-way 与bad的区别在于是用前后比例,避免了要求的数小于误差
(< (/ (abs (- val (improve val rval))) (improve val rval)) 0.0001))
(define (average x y)
(/ (+ x y) 2))
(define (improve x y)
(average x (/ y x)))
(if (g-enough val rval)
val
(sqrt-iter (improve val rval) rval)))
(sqrt-iter 1.0 x))
(define (cube x) //求立方根
(define (cube-g-enough val rval)
(< (/ (abs (- val (c-improve val rval))) (c-improve val rval)) 0.0001))
(define (c-improve y x)
(/ (+ (/ x (* y y)) (* 2 y)) 3))
(define (cube-iter val rval)
(if (cube-g-enough val rval)
val
(cube-iter (c-improve val rval) rval)))
(cube-iter 1.0 x))
(define (Jc x) //求阶乘
(if (> x 0) (* x (Jc (- x 1))) 1))
(define (dd-Jc x) //迭代的方式
(define (iter result count n)
(cond ((= count (inc n)) result)
((= n 0) 1)
(else (iter (* result count) (inc count) n))))
(iter 1 1 x))
//下面两个函数是一个关于,把1美元=100美分,划分为1、5、10、25、50的种类个数
//如果让我不看题解,我直接想到的方法就是用5重循环,求解解的个数。
//当然如果仔细分析,你就会发现这是一个动态规划的问题
//我们把钱类排序,步骤一:不用第一种面值进行计算的划分数目,用另外几种划分钱。
// 步骤二:使用第一种面值后,用剩下的钱用所有面值划分的数目。
//然后这两个步骤加起来的就是所有可分配的种数。
//因为步骤一,不使用第一种面值划分,步骤二使用了第一种面值来划分,则两者数目相加就是总数。
//然后有递推公式 f(money,kinds)=f(money,kinds-1)+f(money-moneyKinds[kinds],kinds) 成立.
//这就是数学的魅力么..我开始看也是不太理解,不过仔细想这合理。
(define (moneyKinds kinds)
(cond ((= kinds 1) 1)
((= kinds 2) 5)
((= kinds 3) 10)
((= kinds 4) 25)
((= kinds 5) 50)))
(define (type-count money kinds)
(define (f m n)
(cond ((= m 0) 1)
((or (< m 0) (= n 0)) 0)
(else (+ (f m (- n 1)) (f (- m (moneyKinds n)) n)))))
(f money kinds))
//练习题 dg-递归 dd-迭代
(define (dg-f n)
(cond ((< n 3) n)
(else (+ (dg-f (dec n)) (* 2 (dg-f (dec (dec n)))) (* 3 (dg-f (dec (dec (dec n)))))))))
(define (dd-f n)
(define (iter x y z count n)
(if (= count n) x
(iter (+ x (* 2 y) (* 3 z)) x y (+ count 1) n)))
(iter 2 1 0 2 n))
//杨辉三角,二项式系数,即便你不会二项式通式,可以根据书上的三角形归纳
// f(m,n)=f(m-1)(n-1)+f(m)(n-1),n为三角形的序号,m为层数
(define (cc m n)
(if (or (= m 0) (= m n) ) 1
(+ (cc (dec m) (dec n)) (cc m (dec n)))))
//even偶数,remainder为计算余数
//本来想写一个求余数,但是没有取整的方法或者不知道,计算出来的要么是分数,要么是循环小数..
(define (is-even n)
(= (remainder n 2) 0))
// b^n=(b^(n/2))^2 (n偶数)
// b*b^(n-1) (奇数)
(define (fast-exp m n)
(define (iter result m n)
(cond ((= n 0) 1)
((= n 1) (* m result))
((is-even n) (iter result (* m m) (/ n 2)))
(else (iter (* result m) m (dec n)))))
(iter 1 m n))
//bad 这是没看懂题意写的,而且计算的规模是-1的速度,很慢
//good 折半,因为乘法可以用加法表示,a x b = (a * 2) x (b/2) b偶数
// a x b = a x (b - 1) + a b奇数
(define (fast-mulit m n)
(define (double x)
(+ x x))
(define (halve x)
(/ x 2))
(define (b-iter result a b) //bad
(cond ((= b 0) 0)
((= b 1) (+ a result))
(else (b-iter (+ result a) a (- b 1)))))
(define (g-iter result a b) //good
(cond ((= b 0) 0)
((= b 1) (+ a result))
((is-even b) (b-iter result (double a) (halve b)))
(else (g-iter (+ a result) a (- b 1)))))
(g-iter 0 m n))
// 根号n的检验素数
(define (prime n)
(define (div a b)
(= (remainder a b) 0))
(define (find-div n cheak )
(cond ((> (square cheak) n ) n)
((div n cheak) cheak)
(else (find-div n (+ cheak 2) ))))
(define (smallest-div n)
(find-div n 2)
(= (smallest-div n) n))
//快速检测素数,以及费马检测,若 n 是素数,则有a<n,a^n mod n =a
//若n不是素数,有部分依旧满足以上,有部分不满足,通过多次检验,若不符合则不是素数。。
(define (expmod m n p)
(cond ((= n 0) 1)
((is-even n) (remainder (square (expmod m (/ n 2) p)) p))
(else (remainder (* m (expmod m (- n 1) p)) p))))
(define (fermat-test n)
(define (try a)
(= (expmod a n n) a))
(try (+ (random (- n 1)) 1)))
//写这个想起了写timer..
(define (fermat-timer n times)
(cond ((= times 0) true)
((fermat-test n) (fermat-timer n (- times 1)))
(else false)))
//(fermat-timer 5 10) test
//上数值分析课的时候似乎碰见过,但是不认真听讲,用C/C++按公式打过一遍
//第一种m-的是我想不到怎么按书上例子,不使用sum编写的
//百度过别人的做法,似乎计算出错还是怎么
//辛普森解法结果为 0.25147191134420877,感觉100的步数,精确度比书上例子的差,不过1000步数的精度好用一些
(define (m-sympson f a b n)
(define h (/ (- b a) n))
(define (func k)
(f (+ a (* k h))))
(define (iter result k)
(if (> k n) result
(iter (+ result (func k)) (inc k))))
(* (/ h 3) (iter 0 0)))
//练习1.30叫填空...我就把上面的补充进去了,使用了例子的sum,算是对上面的一种完善..?
(define (c-sympson f a b n)
(define h (/ (- b a) n))
(define (func k)
(f (+ a (* k h))))
(define (next x)
(inc x))
(define (sum term a next b)
(define (iter result k)
(if (> k n)
result
(iter (+ result (func k)) (next k))))
(* (/ h 3) (iter 0 0)))
(sum func 0 next n))
//(c-sympson cube 0 1 100.0) test
//看规律有,会发现奇数项,分子比分母小1,偶数项,分子比分母大1
//根据这个规律推出一个递推式 a>b 则下一项 a=a,b=a+1,否则a=b+1 b=b, a b初始值是2 3
//通过判断n奇偶,来使用a b判断第n项
(define (pi-mulit n)
(define (iter a b result)
(cond ((and (is-even n) (= a (+ n 2))) (* result (/ a b)))
((and (not (is-even n)) (= b (+ n 2))) (* result (/ a b)))
((> a b) (iter a (inc a) (* result (/ a b))))
(else (iter (inc b) b (* result (/ a b))))))
(iter 2.0 3.0 1))
//(pi-mulit 2000) test
//递归方式重写上面
//重写的完成时候,对递归和迭代的理解相对之前明了许多(我感觉写的不太像递归过程..)
//对比两种方法:
//我们在迭代的时候,是使用初始值,根据规律,推到后面的每一项,且每计算完一项就保存从之前到现在的结果
//而递归,我们是从后面,也就是第n项,根据规律,往前推,不需要设置初始值,只需要保存当前项的结果
//递归展开后,就把之前的结果一层一层返回合并着算
//这两道解题并没有按照书上的要求写要给factorial来写(即写一个类似于书上sum的mulit)
(define (dg-pi-mulit n)
(define (iter n r)
(cond ((= n 0) r)
((is-even n) (* r (iter (dec n) (/ (+ n 2) (inc n)))))
((not (is-even n)) (* r (iter (dec n) (/ (inc n) (+ n 2)))))))
(iter n 1.0))
//(dg-pi-mulit 100) test
//关于上面中提出的sum和mulit,也就是[a,b]内求和与求积公式
//可以把他们写成下面两种形式
//term函数相当于把初始化a序号的数据格式,next就相当于是下一项
(define (plus-f term a next b)
(if (> a b)
0
(+ (term a) (plus-f term (next a) next b))))
(define (mulit-f term a next b)
(if (> a b)
1
(* (term a) (mulit-f term (next a) next b)))
//理解上面着两个,你就可以按照下面这样写,我昨天没理解大意
//上面两种就是递归求和,与求积的大概形式,我前面大多都是写迭代
//所以前面写的都不是基于着两种写的
//使用mulit-f :
(define (dg-mulit-pi n)
(define (next x)
(+ x 1))
(define (iter n)
(cond ((is-even n) (/ (+ n 2.0) (inc n)))
((not (is-even n)) (/ (inc n) (+ n 2.0)))))
(mulit-f iter 1 next n))
//(dg-mulit-pi 100) test
//因为plus-f与mulit-f代码相同的部分很多
//我们还可以进一步抽象化,让代码更简洁明了
//combiner可以看作逻辑符号、运算符之类,或者是两个参数的过程函数,value则是d对应combiner的一些数
(define (accumulate combiner value term a next b)
(if (> a b)
value
(combiner (term a) (accumulate combiner value term (next a) next b))))
//测试accumulate,还是上面算pi/4的值功能
(define (test-accul n)
(define (next x)
(+ x 1))
(define (iter n)
(cond ((is-even n) (/ (+ n 2.0) (inc n)))
((not (is-even n)) (/ (inc n) (+ n 2.0)))))
(accumulate * 1 iter 1 next n))
//添加过滤器版本的-accmulate
(define (filter-accul filter combiner value term a next b)
(if (> a b)
value
(combiner (filter (term a)) (filter-accul filter combiner value term (next a) next b))))
//[a,b)中所有素数的求和
(define (ss-sum a b)
(define (next x)
(inc x))
(define (filter x)
(if (prime x) x 0))
(define (iter x) x)
(filter-accul filter + 0 iter a next b))
//gcd
(define (gcd n m)
(if (= m 0)
n
(gcd m (remainder n m))))
//<n与n互素的正整数乘积
(define (mulit-hs n)
(define (next x)
(inc x))
(define (filter x)
(if (= (gcd x n) 1)
x
1))
(define (iter x) x)
(filter-accul filter * 1 iter 1 next n))
//(mulit-hs 5) test
(define (fixed-point f guess)
(define (is-enough v1 v2)
(< (/ (abs (- v1 v2)) v2) 0.0001))
(define (iter guess)
(let ((next (f guess)))
(newline)
(display next)
(if (is-enough guess next)
next
(iter next))))
(iter guess))
(define (gold-line x)
(+ 1 (/ 1 x)))
(define (test-sin x)
(sin x))
(define (test-log x)
(/ (+ x (/ (log 1000) (log x))) 2))
//无穷连式递归,写出函数,确定改变项,迭代或者递归次数
(define (cont-frac n d k)
(define (iter r k)
(let ((term (lambda (x) (/ n (+ d x)))))
(if (= k 0)
r
(iter (term r) (dec k)))))
(iter 2.0 k))
(define (dd-cont-frac n d k)
(define (iter c)
(let ((term (lambda (x) (/ n (+ d x)))))
(if (= c k)
2.0
(term (iter (inc c))))))
(iter 1))
//第一级状态
(define (cubic a b c)
(lambda (x) (+ (* x (square x)) (* a (square x)) (* b x) c)))
(define (f-double f)
(lambda (x) (f (f x))))
(define (compose f g)
(lambda (x) (f (g x))))
(define (repeated f n)
(define (iter n x)
(if (= n 1)
(f x)
(f (iter (dec n) x))))
(lambda (x) (iter n x)))
(define (smooth f)
(lambda (x) (/ (+ (f (- x 0.0001)) (f x) (f (+ x 0.0001))) 3)))
//((repeated (smooth (lambda (x) (square x))) 5) 5) test