SICP 第一章的练习

  没想到家里网欠费了,家人没回来,只能看书度日了….
  于是乎翻了图书馆借来快一个月的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

猜你喜欢

转载自blog.csdn.net/qq_21049875/article/details/79294743