1.1
10
,
12
,
8
,
3
,
10
6,
a
,
b
,
19
,
#f
,
4
,
16
,
6
,
16
1.2
(/(+
5
4
(-
2
(-
3
(+
6
(/
4
5
)))))(*
3
(-
6
2
)(-
2
7
)))
or
(/(+
5
4
(-
2
(-
3
(+
6
4
/
5
))))(*
3
(-
6
2
)(-
2
7
)))
1.3
这个问题中文版的翻译是错的,参看原文是求平方和而不是“和”。
(define (square(x)(* x x)))
(define (max x y)(if (< x y) y x))
(define (func x y z)
(+ (square (max x y))
(square (max (min x y) z))))
(define (max x y)(if (< x y) y x))
(define (func x y z)
(+ (square (max x y))
(square (max (min x y) z))))
1.4
a+|b|
<=>
1
#
in python
2 def a_plus_abs_b(a,b):
3 if b > 0 :
4 x = a + b
5 else :
6 x = a - b
7 return x
2 def a_plus_abs_b(a,b):
3 if b > 0 :
4 x = a + b
5 else :
6 x = a - b
7 return x
1.5
而对于“应用序”的实现,则会这样展开
(if (= 0 0) 0 (p))
(if #t 0 (p))
; 0
解决这个问题主要是“正则序”(Normal order)以及“应用序”(Applicative order)展开一个组合式的规则,仔细研究了MIT 6.001课程讲义,网上的各种答案,以及中英文版。我认为,正则序以类似广度优先的方式进行展开。而应用序优先计算子表达式,类似与深度优先。那么对于这个问题, 正则序 会展开为
=
> (if (
=
0
0
)
0
(p))
= > (if #t 0 (p))
接着,由于这是一个if的special form(特殊形式),就会被展开为
= > (if #t 0 (p))
0
而应用序,由于(p)一直可以递归代换,从一开始就会进入一个无限递归中去。
简言之,由于应用序的原因,在 test 表达式 还没有展开为 if 特殊形式(special forms)时, (p)已经陷入了无限递归。
会递归直到堆栈溢出。
原因是 在 new-if 还没有展开为 cond special forms 时,else-clause 子式已经陷入了无限递归。 做了以下实验,可以验证
(define (new-if pred thenc elsec)
(cond (pred thenc)
(else elsec)))
(define (iter x y)
(new-if ( = x y)
0
(iter (+ x 1 ) y)))
(define (iter-if x y)
(if ( = x y)
0
(iter-if (+ x 1 ) y)))
(define (iter-cond x y)
(cond (( = x y) 0 )
(else (iter-cond (+ x 1 ) y))))
(cond (pred thenc)
(else elsec)))
(define (iter x y)
(new-if ( = x y)
0
(iter (+ x 1 ) y)))
(define (iter-if x y)
(if ( = x y)
0
(iter-if (+ x 1 ) y)))
(define (iter-cond x y)
(cond (( = x y) 0 )
(else (iter-cond (+ x 1 ) y))))
对于 (iter 1 10), (iter-if 1 10), (iter-cond 1 10)
其中 iter 会 导致堆栈溢出,而 iter-cond 和 iter-if 并不会。
此题同1.5
在1.5中,由于应用序的原因,在 test 表达式 还没有展开为 if 特殊形式(special forms)时, (p)已经陷入了无限递归。
> (sqrt (square
0.1
))
0.10032578510960607
> (sqrt (square 0.05 ))
0.054237622808967656
> (sqrt (square 0.01 ))
0.03230844833048122
> (sqrt (square 0.005 ))
0.031515954454847304
> (sqrt (square 0.001 ))
0.031260655525445276
> (sqrt (square 0.0001 ))
0.03125010656242753
>
0.10032578510960607
> (sqrt (square 0.05 ))
0.054237622808967656
> (sqrt (square 0.01 ))
0.03230844833048122
> (sqrt (square 0.005 ))
0.031515954454847304
> (sqrt (square 0.001 ))
0.031260655525445276
> (sqrt (square 0.0001 ))
0.03125010656242753
>
因为 guess^2 < c + x, 当 x < c 时,guess 就更多的依赖于 c 了。
对于特别大的数,由于浮点数在特别大时,离散性非常明显,相邻的两个数之间的差距会非常大,导致 |guess^2 - x| 始终 大于 c,计算便进入了 无限循环。
比如计算 (sqrt 1e300)
使用变化率改进后的代码如下:
(define (sqrt-new x)
(sqrt-iter-new x 1.0 x))
(define (sqrt-iter-new s1 s2 x)
(if (enuf-new? s1 s2)
s2
(sqrt-iter-new s2 (improve s2 x) x)))
(define (enuf-new? s1 s2)
(< (/ (abs (- s1 s2)) s1) 0.001 ))
(sqrt-iter-new x 1.0 x))
(define (sqrt-iter-new s1 s2 x)
(if (enuf-new? s1 s2)
s2
(sqrt-iter-new s2 (improve s2 x) x)))
(define (enuf-new? s1 s2)
(< (/ (abs (- s1 s2)) s1) 0.001 ))
可以测算几个数,验证结果还是比较好的。
> (sqrt-new (square
1e150
))
1.0000000000084744e+150
> (sqrt-new (square 1e-150 ))
1.0000000000084744e-150
1.0000000000084744e+150
> (sqrt-new (square 1e-150 ))
1.0000000000084744e-150
(define (cube-root x)
(cube-root-iter x 1.0 x))
(define (cube-root-iter last-guess guess x)
(if (enuf? last-guess guess)
guess
(cube-root-iter guess (improve guess x) x)))
(define (enuf? x y)
(< (/ (abs (- x y)) y) 0.001 ))
(define improve (lambda (y x)
(/ (+ (/ x (* y y)) (* 2 y)) 3 )))
很显然,第一个是递归的,第二个是迭代的。(cube-root-iter x 1.0 x))
(define (cube-root-iter last-guess guess x)
(if (enuf? last-guess guess)
guess
(cube-root-iter guess (improve guess x) x)))
(define (enuf? x y)
(< (/ (abs (- x y)) y) 0.001 ))
(define improve (lambda (y x)
(/ (+ (/ x (* y y)) (* 2 y)) 3 )))
(+
4
5
)
(if ( = 4 0 ) 5 (inc (+ (dec 4 ) 5 )))
(inc (+ 3 5 ))
(inc (if ( = 3 0 ) 5 (inc (+ 2 5 ))))
(inc (inc (if ( = 2 0 ) 5 (inc (+ 1 5 )))))
(inc (inc (inc (if ( = 1 0 ) 5 (inc (+ 0 5 ))))))
(inc (inc (inc (inc (if ( = 0 0 ) 5 (inc (+ (dec 0 ) 5 )))))))
(inc (inc (inc (inc 5 ))))
(inc (inc (inc 6 )))
(inc (inc 7 ))
(inc 8 )
9
(+ 4 5 )
(if ( = 4 0 ) 5 (+ 3 6 ))
(if ( = 3 0 ) 6 (+ 2 7 ))
(if ( = 2 0 ) 7 (+ 1 8 ))
(if ( = 1 0 ) 8 (+ 0 9 ))
(if ( = 0 0 ) 9 (+ (dec 0 ) (inc 9 )))
9
(if ( = 4 0 ) 5 (inc (+ (dec 4 ) 5 )))
(inc (+ 3 5 ))
(inc (if ( = 3 0 ) 5 (inc (+ 2 5 ))))
(inc (inc (if ( = 2 0 ) 5 (inc (+ 1 5 )))))
(inc (inc (inc (if ( = 1 0 ) 5 (inc (+ 0 5 ))))))
(inc (inc (inc (inc (if ( = 0 0 ) 5 (inc (+ (dec 0 ) 5 )))))))
(inc (inc (inc (inc 5 ))))
(inc (inc (inc 6 )))
(inc (inc 7 ))
(inc 8 )
9
(+ 4 5 )
(if ( = 4 0 ) 5 (+ 3 6 ))
(if ( = 3 0 ) 6 (+ 2 7 ))
(if ( = 2 0 ) 7 (+ 1 8 ))
(if ( = 1 0 ) 8 (+ 0 9 ))
(if ( = 0 0 ) 9 (+ (dec 0 ) (inc 9 )))
9
0
,
y
=
0
;
f(x , y) = 2y , x = 0 ;
2 , y = 1 ;
f(x- 1 , f(x , y- 1 )) ;
f(x , y) = 2y , x = 0 ;
2 , y = 1 ;
f(x- 1 , f(x , y- 1 )) ;
那么,对于 f(0,n), n>=0
当 n >= 1 时, f(0,n) = 2n ,
而当 n = 0 时, f(0,0) = 0 = 2*0, 也满足 2n ,
故 f(0,n) = 2n, n>=0.
对于f(1,n), n>=1
当 n > 1 时,有 f(1,n) = f(0, f(1, n-1)) = 2*f(1,n-1),
设 f(1,n) = 2^n
if n = 1, f(1,1) = 2 = 2^1
when n > 1, if f(1,n-1) = 2^(n-1)
then f(1,n) = 2*f(1,n-1) = 2*(2^(n-1)) = 2^n
故 f(1,n) = 2^n, n>0.
对于f(2,n), n>0
if n > 1 ,then f(2,n) = f(1, f(2, n-1)) = 2^f(2,n-1),
设 f(2,n) = 2^(2^(... (n 个 2)
if n = 1, then f(2,1) = 2
when n > 1, if f(2, n-1) = 2^(2^(... (n-1)
then f(2,n) = 2^f(2,n-1) = 2^(2^(
这样我们对于 (A 1 10) = 2^10 = 1024, (A 2 4) = 2^(2^(2^2)) = 2^16 = 65536
而 (A 3 3) = (A 2 A(3 2)) = A(2 A(2 A(2 1))) = (A 2 4) = 2^16 = 65536
(f n) = (A 0 n) = 2n
(g n) = (A 1 n) = 2^n
(h n) = (A 2 n) = 2^(2^(... (n个2)
---------------------------------------------
在网上可以找到关于 Ackermann 函数的讨论,主要是针对这个双递归如何用迭代来实现,Ackermann 函数是 德国数学家W.Ackermann 在1928年提出的。在 WikiPedia 英文版上可以搜索 Ackermann function词条,有详细介绍,不过这个Ackermann function略有不同。
1.11
递归计算过程为
(define func-recu
(lambda(n)
(cond ((< n 3 ) n)
(else (+ (func-recu (- n 1 ))
(* 2 (func-recu (- n 2 )))
(* 3 (func-recu (- n 3 ))))))))
迭代计算过程为
(lambda(n)
(cond ((< n 3 ) n)
(else (+ (func-recu (- n 1 ))
(* 2 (func-recu (- n 2 )))
(* 3 (func-recu (- n 3 ))))))))
方法(1)
(define (func n)
(fun 1 2 3 n))
(define (fun fir sed thi mun)
(cond ((= mun 1) fir)
((= mun 2) sed)
((= mun 3) thi)
(else (fun sed
thi
(+ (* 3 fir)
(* 2 sed)
(* 1 thi))
(- mun 1)))))
方法(2)
(define func-iter
(lambda(a b c n)
(if ( = n 0 )
a
(func-iter b c (+ (* 3 a) (* 2 b) c) (- n 1 )))))
(define (func n) (func-iter 0 1 2 n))
(define (func n)
(fun 1 2 3 n))
(define (fun fir sed thi mun)
(cond ((= mun 1) fir)
((= mun 2) sed)
((= mun 3) thi)
(else (fun sed
thi
(+ (* 3 fir)
(* 2 sed)
(* 1 thi))
(- mun 1)))))
方法(2)
(define func-iter
(lambda(a b c n)
(if ( = n 0 )
a
(func-iter b c (+ (* 3 a) (* 2 b) c) (- n 1 )))))
(define (func n) (func-iter 0 1 2 n))
1.12
中文版原题翻译有误,应为计算pascal三角中的元素。
;
pas(n,k)
; if (k=1) or (k=n), then pas(n,k) = 1
; else pas(n,k) = pas(n-1,k-1) + pas(n-1,k)
(define pas (lambda(n k)
(if (or ( = k 1 ) ( = k n))
1
(+ (pas (- n 1 ) (- k 1 ))
(pas (- n 1 ) k)))))
; if (k=1) or (k=n), then pas(n,k) = 1
; else pas(n,k) = pas(n-1,k-1) + pas(n-1,k)
(define pas (lambda(n k)
(if (or ( = k 1 ) ( = k n))
1
(+ (pas (- n 1 ) (- k 1 ))
(pas (- n 1 ) k)))))
1.13
中文版原题翻译遗漏 提示 :ψ=(1-√5)/2
已知,φ^2 = φ + 1, 那么 φ^n = φ^(n-1) + φ^(n-2)
同理, ψ^2 = ψ + 1, 那么 ψ^n = ψ^(n-1) + ψ^(n-2)
又 φ-ψ = (1+√5)/2 - (1-√5)/2 = √5
when n=0, Fib(0) = 0 = (φ^0-ψ^0)/ √5
when n=1, Fib(1) = 1 = √5 / √5 = (φ-ψ)/ √5
when n>2, Fib(n) = Fib(n-1) + Fib(n-2) = (φ^(n-1)-ψ^(n-1))/ √5 + (φ^(n-2)-ψ^(n-2))/ √5
= (( φ^(n-1)+(φ^(n-2))) - ( ψ^(n-1) +ψ^(n-2)))/ √5
= ( φ^n - ψ^n)/ √5
又 -1< ψ < 0, 故 -0.5< -1/ √5 < ψ^n/ √5 < 1 / √5 <0.5, 而 φ^n /√5 = ψ^n/√5 + Fib(n)
可知 | φ^n /√5 - Fib(n)| < 0.5, Fib(n)是最接近 φ^n /√5的整数。
1.14
计算过程的树如下:
很容易看出,计算过程的空间需求,也就是树的深度,取决于最左边的子树,即(n 1),它的深度是n+6,O(n).
然后对于计算步数,也就是树的节点数,我们知道对于一个二叉树,树的节点数 = 左子树节点数 + 右子树节点数 + 1.
先来看 (n 1) 子树,设它的节点数是f(n), 而且总有,非叶节点左子树节点数为1
当 n=1,f(1) = 3
n>1, f(n) = 1 + f(n-1) + 1 = f(n-1) + 2 = f(n-2) + 2*2
= f(n-(n-1)) + 2*(n-1) = 2n + 1
= O(n)
再来看 (n 2) 子树,设它的节点数 g(n), 设 ┌ n/5 ┐ = A
g(n) = f(n) + g(n-5) + 1 = f(n) + f(n-5) + g(n-5*2) + 2
= f(n) + ... + f(n-5*(A-1)) + g(n-5*A) + 2A
= O(n^2)
依此类推,可以得出结论 (n 5) 的计算步数增长的阶 为 O(n^5)
1.15
a) 12.15 连除 5次 3 小于 0.1 ,所以是 5次
b) 可以看出每调用一次 p 过程,需要递归1次 sine ,空间加1,计算步数加2,关键是p的次数:
对于a,调用次数t,那么 a*3^(-t) < 0.1 , 即 10a < 3^t ==> lg(10a)/lg3 < t,
所以增长阶 空间和时间 都为 O(log a)
1.16
(define (fast-expt x n)
(fast-expt-iter x n 1 ))
(define (fast-expt-iter x n a)
(cond (( = n 0 ) a)
((even? n) (fast-expt-iter (square x)
(/ n 2 )
a))
(else (fast-expt-iter x
(- n 1 )
(* a x)))))
(fast-expt-iter x n 1 ))
(define (fast-expt-iter x n a)
(cond (( = n 0 ) a)
((even? n) (fast-expt-iter (square x)
(/ n 2 )
a))
(else (fast-expt-iter x
(- n 1 )
(* a x)))))
1.17
(define (multi x y)
(if ( = y 0 )
0
(+ x (multi x (- y 1 )))))
(define (fast-multi x y)
(cond (( = y 0 ) 0 )
((even? y) (double (fast-multi x
(half y))))
(else (+ x (fast-multi x (- y 1 ))))))
(define (double x) (+ x x))
(define (half y) (/ y 2 ))
(if ( = y 0 )
0
(+ x (multi x (- y 1 )))))
(define (fast-multi x y)
(cond (( = y 0 ) 0 )
((even? y) (double (fast-multi x
(half y))))
(else (+ x (fast-multi x (- y 1 ))))))
(define (double x) (+ x x))
(define (half y) (/ y 2 ))
1.18
(define (double x) (+ x x))
(define (half y) (/ y 2 ))
(define (fast-multi x y)
(fast-multi-iter x y 0 ))
(define (fast-multi-iter x y p)
(cond (( = y 0 ) p)
((even? y) (fast-multi-iter (double x)
(half y)
p))
(else (fast-multi-iter x (- y 1 ) (+ p x)))))
(define (half y) (/ y 2 ))
(define (fast-multi x y)
(fast-multi-iter x y 0 ))
(define (fast-multi-iter x y p)
(cond (( = y 0 ) p)
((even? y) (fast-multi-iter (double x)
(half y)
p))
(else (fast-multi-iter x (- y 1 ) (+ p x)))))
1.19
;
T(pq):(a,b)=>(bq+aq+ap, bp+aq)
; T(pq):(bq+aq+ap, bp+aq)=>((bp+aq)q + (bq+aq+ap)q + (bq+aq+ap)p,
; (bp+aq)p + (bq+aq+ap)q)
; => (2bpq+2aqq+bqq+2apq+app, bpp+2apq+bqq+aqq)
; => (b(2pq+qq)+a(2pq+qq)+a(qq+pp), b(qq+pp)+a(2pq+qq))
; q' = 2pq+qq
; p' = qq+pp
;
(define (fib n)
(fib-iter 1 0 0 1 n))
(define (fib-iter a b p q count)
(cond (( = count 0 ) b)
((even? count)
(fib-iter a
b
(+ (* p p) (* q q))
(+ (* 2 p q ) (* q q))
(/ count 2 )))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1 )))))
1.20; T(pq):(bq+aq+ap, bp+aq)=>((bp+aq)q + (bq+aq+ap)q + (bq+aq+ap)p,
; (bp+aq)p + (bq+aq+ap)q)
; => (2bpq+2aqq+bqq+2apq+app, bpp+2apq+bqq+aqq)
; => (b(2pq+qq)+a(2pq+qq)+a(qq+pp), b(qq+pp)+a(2pq+qq))
; q' = 2pq+qq
; p' = qq+pp
;
(define (fib n)
(fib-iter 1 0 0 1 n))
(define (fib-iter a b p q count)
(cond (( = count 0 ) b)
((even? count)
(fib-iter a
b
(+ (* p p) (* q q))
(+ (* 2 p q ) (* q q))
(/ count 2 )))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1 )))))
下面用 % 表示过程 remainder,那么正则序的过程如下:
(gcd
206
40
)
(if ( = 40 0 ) 206 (gcd 40 (% 206 40 )))
(gcd 40 (% 206 40 ))
(if ( = (% 206 40 ) 0 ) ; <## 1> [6]
40
(gcd (% 206 40 ) (% 40 (% 206 40 ))
(gcd (% 206 40 ) (% 40 (% 206 40 )))
(if ( = (% 40 (% 206 40 )) 0 ) ; <## 2> [4]
(% 206 40 )
(gcd (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 )))))
(gcd (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 ))))
(if ( = (% (% 206 40 ) (% 40 (% 206 40 ))) 0 ) ; <## 4>[2]
(% 40 (% 206 40 ))
(gcd (% (% 206 40 ) (% 40 (% 206 40 )))
(% (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 ))))))
(gcd (% (% 206 40 ) (% 40 (% 206 40 )))
(% (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 ))))))
(if ( = (% (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 ))))) 0 ) ; <## 7>[0]
(% (% 206 40 ) (% 40 (% 206 40 )))
(gcd ...)
(% (% 206 40 ) (% 40 (% 206 40 ))) ; <## 4>[2]
(if ( = 40 0 ) 206 (gcd 40 (% 206 40 )))
(gcd 40 (% 206 40 ))
(if ( = (% 206 40 ) 0 ) ; <## 1> [6]
40
(gcd (% 206 40 ) (% 40 (% 206 40 ))
(gcd (% 206 40 ) (% 40 (% 206 40 )))
(if ( = (% 40 (% 206 40 )) 0 ) ; <## 2> [4]
(% 206 40 )
(gcd (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 )))))
(gcd (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 ))))
(if ( = (% (% 206 40 ) (% 40 (% 206 40 ))) 0 ) ; <## 4>[2]
(% 40 (% 206 40 ))
(gcd (% (% 206 40 ) (% 40 (% 206 40 )))
(% (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 ))))))
(gcd (% (% 206 40 ) (% 40 (% 206 40 )))
(% (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 ))))))
(if ( = (% (% 40 (% 206 40 )) (% (% 206 40 ) (% 40 (% 206 40 ))))) 0 ) ; <## 7>[0]
(% (% 206 40 ) (% 40 (% 206 40 )))
(gcd ...)
(% (% 206 40 ) (% 40 (% 206 40 ))) ; <## 4>[2]
可以看出需要调用 remainder 共 1+2+4+7+4 = 18 次。
应用序计算过程如下:
(gcd
206
40
)
(if ( = 40 0 ) 206 (gcd 40 (% 206 40 ))) ; <##>
(gcd 40 6 )
(if ( = 6 0 ) 40 (gcd 6 (% 40 6 ))) ; <##>
(gcd 6 4 )
(if ( = 4 0 ) 6 (gcd 4 (% 6 4 ))) ; <##>
(gcd 4 2 )
(if ( = 2 0 ) 4 (gcd 2 (% 4 2 ))) ; <##>
(gcd 2 0 )
(if ( = 0 0 ) 2 (gcd 0 (% 2 0 )))
2
(if ( = 40 0 ) 206 (gcd 40 (% 206 40 ))) ; <##>
(gcd 40 6 )
(if ( = 6 0 ) 40 (gcd 6 (% 40 6 ))) ; <##>
(gcd 6 4 )
(if ( = 4 0 ) 6 (gcd 4 (% 6 4 ))) ; <##>
(gcd 4 2 )
(if ( = 2 0 ) 4 (gcd 2 (% 4 2 ))) ; <##>
(gcd 2 0 )
(if ( = 0 0 ) 2 (gcd 0 (% 2 0 )))
2
可以看出共需 4 次。
1.21
> (smallest-divisor
199
)
199
> (smallest-divisor 1999 )
1999
> (smallest-divisor 19999 )
7
>
199
> (smallest-divisor 1999 )
1999
> (smallest-divisor 19999 )
7
>
1.22
在 DrScheme 中没有对应的 runtime 过程,我们用内建的 current-milliseconds来代替,这个过程返回的是系统的 ms 数。
同时,在 Windows 下无法精确表示 16ms 以下的精度(可能时间片的大小是 16ms ),所以这里用比较大的数来测试。
代码如下
(define (even? x) (
=
(remainder x
2
)
0
))
(define (runtime) (current-milliseconds))
(define (start-prime-test n start-time)
(and (prime? n)
(report-prime (- (runtime) start-time))))
(define (report-prime elapsed-time)
(display " *** " )
(display elapsed-time))
(define (search-iter cur-num index start-time)
(newline)
(display cur-num)
(if (not ( = index 0 ))
(if (start-prime-test cur-num start-time)
(search-iter (+ cur-num 2 ) (- index 1 ) start-time)
(search-iter (+ cur-num 2 ) index start-time))))
(define (search-for-primes start-number)
(if (even? start-number)
(search-iter (+ start-number 1 ) 3 (runtime))
(search-iter start-number 3 (runtime))))
(define (runtime) (current-milliseconds))
(define (start-prime-test n start-time)
(and (prime? n)
(report-prime (- (runtime) start-time))))
(define (report-prime elapsed-time)
(display " *** " )
(display elapsed-time))
(define (search-iter cur-num index start-time)
(newline)
(display cur-num)
(if (not ( = index 0 ))
(if (start-prime-test cur-num start-time)
(search-iter (+ cur-num 2 ) (- index 1 ) start-time)
(search-iter (+ cur-num 2 ) index start-time))))
(define (search-for-primes start-number)
(if (even? start-number)
(search-iter (+ start-number 1 ) 3 (runtime))
(search-iter start-number 3 (runtime))))
这里用到了 prime? 谓词,代码不再复述。
|------+--------+--------+-------|
|10^9 | 10^10 | 10^11 | 10^12 | => start-number
|------+--------+--------+-------|
|31 | 250 | 609 | 1953 | (ms)
|47 | 406 | 1203 | 3844 |
|78 | 625 | 1859 | 5719 |
|------+--------+--------+-------|
从上表可以看出,除了前两列之间,后列的数字都是前列数字的 3 倍左右,近似于 √10 ≈ 3.16。实际上,随着 n 的不断增大,这个数会逐渐逼近 √10。
1.23
(define (next n)
(if ( = n 2 ) 3 (+ n 2 )))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (next test-divisor)))))
(if ( = n 2 ) 3 (+ n 2 )))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (next test-divisor)))))
计算结果如下:
|--------+--------+-------|
| 10^10 | 10^11 | 10^12 | => start-number
|--------+--------+-------|
| 141 | 297 | 1078 | (ms)
| 219 | 609 | 2093 |
| 313 | 984 | 3140 |
|--------+--------+-------|
可以看出这个比值大约在 1.8(1/0.55) 左右,可能原因是其它的计算需要时间,但当 n 不断增大,其它计算是常数阶,这个比值会不断接近2。
1.24
对于Fermat检查,因为具有log n 的增长阶,所以对于 n^2 和 n 的检查的时间比 理论上应该是 2:1, 实际上,经过测试也比较接近,当n比较大时。
若与预计不符,可能因为 n 比较小,或者字长发生变化,比如 n > 2^32 (参见下题)
1.25
仅从理论分析,Alyssa 的改动不会引起增长阶的变化,但实际上当 Fermat 检查的 n 稍微大一点,速度就会很慢。主要原因 就是 base^exp 是一个非常大的数,可能远远超过 一个32位机字的表示范围 2^32 ,在 scheme 里可能用若干个 32-bit 靠软件实现运算,这将导致计算急速增长。无论是传递、运算还是求模。
实际上 1.22、1.23、1.24 的几个题目可能都会遇到字长变化引起的计算速度突变。
1.26
Fermat 检查正是因为 连续求平方的求幂方法,使得的增长阶变为 log n, 而这均来源于 b^(2n) = (b^n)^2,Louis 的方法让求幂又变成了连乘,b^(2n) = b^n*b^n = (b*b*...*b)*(b*b*...*b),求幂的增长阶变成了 O(n),Fermat 检查的增长阶自然也变成了 O(n)。
1.27
(define (fermat-test n)
(fermat-iter (- n 1 ) n))
(define (fermat-iter a n)
(cond (( = a 0 ) #t)
(( = (expmod a n n) a) (fermat-iter (- a 1 ) n))
(else #f)))
(fermat-iter (- n 1 ) n))
(define (fermat-iter a n)
(cond (( = a 0 ) #t)
(( = (expmod a n n) a) (fermat-iter (- a 1 ) n))
(else #f)))
1.28
首先来看,Fermat 小定理的一个变形:
p 是素数, 1<a<p, 有 a^p % p = a
==> a^p = kp + a ==> a^p - a = kp ==> a(a^(p-1)-1) = kp ==> a^(p-1) -1 = k'p
==> a^(p-1) % p = 1
这个变形就是题目中提到的,这个形式和费马小定理是等价的(但是奇怪的是,我没有发现已知的几个Carmichael数能够躲过这个变形的检查,有待研究 ①)
再来看,miller-rabin 素性测试的原理:
p 是素数, 1<a<p, 且 a^2 % p = 1
==> (a^2-1) % p = 0 ==> (a+1)(a-1) % p =0
那么 a+1 % p = 0 或者 a-1 % p =0,
又 a<p 且 p 是素数,所以
a = 1 或者 a = p-1 (这两个叫做 1模n的平凡平方根)
代码如下:
(define (check-nontrivial-sqrt-of-one a n)
(define (check- 1? t)
(if (and (> a 1 )
(< a (- n 1 ))
( = t 1 ))
0 t))
(check- 1 ? (remainder (square a) n)))
(define (expmod base exp m)
(cond (( = exp 0 ) 1 )
((even? exp)
; (remainder (square (expmod base (/ exp 2) m)) m))
(check-nontrivial-sqrt-of-one (expmod base (/ exp 2 ) m) m))
(else
(remainder (* base (expmod base (- exp 1 ) m)) m))))
(define (miller-rabin-test n)
(define (iter x n)
(cond (( = x 0 ) #t)
(( = (expmod x (- n 1 ) n) 1 ) (iter (- x 1 ) n))
(else #f)))
(iter (- n 1 ) n))
(define (check- 1? t)
(if (and (> a 1 )
(< a (- n 1 ))
( = t 1 ))
0 t))
(check- 1 ? (remainder (square a) n)))
(define (expmod base exp m)
(cond (( = exp 0 ) 1 )
((even? exp)
; (remainder (square (expmod base (/ exp 2) m)) m))
(check-nontrivial-sqrt-of-one (expmod base (/ exp 2 ) m) m))
(else
(remainder (* base (expmod base (- exp 1 ) m)) m))))
(define (miller-rabin-test n)
(define (iter x n)
(cond (( = x 0 ) #t)
(( = (expmod x (- n 1 ) n) 1 ) (iter (- x 1 ) n))
(else #f)))
(iter (- n 1 ) n))
① 对于 Carmichael 数 n ,实际上不能完全通过 a^(n-1)%n = 1 的检查 ,除非 a 与 n 互素,当 a 为 n 的素因子时,不能通过,比如 Carmichael 第一个 561 = 3*11*17, 而 3^560%561 = 375 ≠ 1 。可以程序验证这个。 所以我认为,a^(n-1)%n = 1 的检查比 a^n%n = a 的检查更严格,是不是不存在合数通过完全的 a^(n-1)%n = 1 的检查呢?我不敢说。但把这个结论暂时记在这里,希望能得到帮助或者反驳。2008-04-02 23:56
1.29
(define (simpson f a b n)
(define (get-h) (/ (- b a) n))
(define (get-y k) (f (+ a (* k (get-h)))))
(define (simpson-term k)
(cond (( = k 0 ) (get-y k))
(( = k n) (get-y k))
(( = (remainder k 2 ) 0 ) (* 2.0 (get-y k)))
(else (* 4.0 (get-y k)))))
(define (simpson-next k) (+ k 1 ))
(* (/ (get-h) 3.0 ) (sum simpson-term 0 simpson-next n)))
(define (get-h) (/ (- b a) n))
(define (get-y k) (f (+ a (* k (get-h)))))
(define (simpson-term k)
(cond (( = k 0 ) (get-y k))
(( = k n) (get-y k))
(( = (remainder k 2 ) 0 ) (* 2.0 (get-y k)))
(else (* 4.0 (get-y k)))))
(define (simpson-next k) (+ k 1 ))
(* (/ (get-h) 3.0 ) (sum simpson-term 0 simpson-next n)))
1.30
(define (sum term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (+ (term a) result))))
(iter a 0 ))
(define (iter a result)
(if (> a b)
result
(iter (next a) (+ (term a) result))))
(iter a 0 ))
1.31
;
;递归
(define (product-re term a next b)
(if (> a b)
1
(* (term a)
(product-re term (next a) next b))))
; ;迭代
(define (product term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (* result (term a)))))
(iter a 1 ))
(define (pi-product b)
(define (pi-term k) (/ (* (- k 1 ) (+ k 1 )) k k))
(define (pi-next k) (+ k 2 ))
; ;(* 4.0 (product-re pi-term 3.0 pi-next b))) ;;递归
(* 4.0 (product pi-term 3.0 pi-next b))) ; ;迭代
(define (product-re term a next b)
(if (> a b)
1
(* (term a)
(product-re term (next a) next b))))
; ;迭代
(define (product term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (* result (term a)))))
(iter a 1 ))
(define (pi-product b)
(define (pi-term k) (/ (* (- k 1 ) (+ k 1 )) k k))
(define (pi-next k) (+ k 2 ))
; ;(* 4.0 (product-re pi-term 3.0 pi-next b))) ;;递归
(* 4.0 (product pi-term 3.0 pi-next b))) ; ;迭代
1.32
(define (sum term a next b)
(accumulate + 0 term a next b))
(define (product term a next b)
(accumulate * 1 term a next b))
; ;递归
(define (accumulate-re combiner null-value term a next b)
(if (> a b)
null-value
(combiner (term a)
(accumulate-re combiner null-value term (next a) next b))))
; ;迭代
(define (accumulate combiner null-value term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (combiner (term a) result))))
(iter a null-value))
(accumulate + 0 term a next b))
(define (product term a next b)
(accumulate * 1 term a next b))
; ;递归
(define (accumulate-re combiner null-value term a next b)
(if (> a b)
null-value
(combiner (term a)
(accumulate-re combiner null-value term (next a) next b))))
; ;迭代
(define (accumulate combiner null-value term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (combiner (term a) result))))
(iter a null-value))
1.33
(define (filtered-accumulate combiner null-value term a next b filter?)
(define (iter a result)
(if (> a b)
result
(if (filter? (term a))
(iter (next a) (combiner (term a) result))
(iter (next a) result))))
(iter a null-value))
(define (sum-prime a b)
(define (sum-prime-term k) k)
(define (sum-prime-next k) (+ k 1 ))
(filtered-accumulate + 0 sum-prime-term a sum-prime-next b prime?))
(define (relatively-prime-product n)
(define (relatively-prime? k) ( = (gcd k n) 1 ))
(define (term k) k)
(define (next k) (+ k 1 ))
(filtered-accumulate * 1 term 2 next (- n 1 ) relatively-prime?))
(define (iter a result)
(if (> a b)
result
(if (filter? (term a))
(iter (next a) (combiner (term a) result))
(iter (next a) result))))
(iter a null-value))
(define (sum-prime a b)
(define (sum-prime-term k) k)
(define (sum-prime-next k) (+ k 1 ))
(filtered-accumulate + 0 sum-prime-term a sum-prime-next b prime?))
(define (relatively-prime-product n)
(define (relatively-prime? k) ( = (gcd k n) 1 ))
(define (term k) k)
(define (next k) (+ k 1 ))
(filtered-accumulate * 1 term 2 next (- n 1 ) relatively-prime?))
1.34
这个展开过程为:
(f f)
(f 2)
(2 2)
解释器将报错,‘2’是一个未定义过程。
1.35
若 φ=0 , 则 φ^2=φ+1 不成立 , 故 φ≠0
φ^2 = φ+1 ==>
φ = (φ+1)/φ = 1 + (1/φ)
(fixed-point (lambda(x) (+ 1 (/ 1 x))) 1.0)
1.36
(define tolerance
0.00001
)
(define (fixed-point f first-guess)
(define (close-enough? x y)
(< (abs (- x y)) tolerance))
(define (try guess)
(let ((next (f guess)))
(display next)
(newline)
(if (close-enough? guess next)
next
(try next))))
(try first-guess))
(define (fixed-point f first-guess)
(define (close-enough? x y)
(< (abs (- x y)) tolerance))
(define (try guess)
(let ((next (f guess)))
(display next)
(newline)
(if (close-enough? guess next)
next
(try next))))
(try first-guess))
平均阻尼法和不用平均阻尼分别如下,它们步数分别为 9 和 34 。
(fixed-point (lambda(x) (/ (+ x (/ (log
1000
) (log x)))
2
))
2.0
)
(fixed-point (lambda(x) (/ (log 1000 ) (log x))) 2.0 )
(fixed-point (lambda(x) (/ (log 1000 ) (log x))) 2.0 )
1.37
(define (cont-frac-r n d k)
(define (redu i)
(if ( = i k)
(/ (n i) (d i))
(/ (n i) (+ (d i) (redu n d (+ i 1 ))))))
(redu 1 ))
(define (cont-frac n d k)
(define (iter i result)
(if ( = i 0 )
result
(iter (- i 1 ) (/ (n i) (+ (d i) result)))))
(iter k 0 ))
(define (get-phai k)
(/ 1 (cont-frac (lambda(i) 1.0 ) (lambda(i) 1.0 ) k)))
(define (get-k)
(define (iter i)
(if (< (abs (- (get-phai i) 1.6180 )) 0.00005 )
i
(iter (+ i 1 ))))
(iter 1 ))
(define (redu i)
(if ( = i k)
(/ (n i) (d i))
(/ (n i) (+ (d i) (redu n d (+ i 1 ))))))
(redu 1 ))
(define (cont-frac n d k)
(define (iter i result)
(if ( = i 0 )
result
(iter (- i 1 ) (/ (n i) (+ (d i) result)))))
(iter k 0 ))
(define (get-phai k)
(/ 1 (cont-frac (lambda(i) 1.0 ) (lambda(i) 1.0 ) k)))
(define (get-k)
(define (iter i)
(if (< (abs (- (get-phai i) 1.6180 )) 0.00005 )
i
(iter (+ i 1 ))))
(iter 1 ))
k = 11 时,精度满足 4 位 十进制数。
1.38
(define (euler-d i)
(cond (( = i 2 ) 2.0 )
((and (> i 2 ) ( = 0 (remainder (- i 2 ) 3 )))
(* (/ (+ i 1 ) 3.0 ) 2.0 ))
(else 1.0 )))
(define (get-e k)
(+ 2 (cont-frac (lambda(i) 1.0 ) euler-d k)))
(cond (( = i 2 ) 2.0 )
((and (> i 2 ) ( = 0 (remainder (- i 2 ) 3 )))
(* (/ (+ i 1 ) 3.0 ) 2.0 ))
(else 1.0 )))
(define (get-e k)
(+ 2 (cont-frac (lambda(i) 1.0 ) euler-d k)))
1.39
(define (tan-cf x k)
(define (tan-n i)
(if ( = 1 i)
x
(- (* x x))))
(cont-frac tan-n (lambda(i) (- (* i 2.0 ) 1.0 )) k))
;
;;;;;;;;;;
(define (tan-n i)
(if ( = 1 i)
x
(- (* x x))))
(cont-frac tan-n (lambda(i) (- (* i 2.0 ) 1.0 )) k))
; 1.41
(define (double f)
(lambda(x) (f (f x))))
; ;(((double (double double)) inc) 5) = 5+16 =21
; ;;;;;;;;;;;;
; 1.42
(define (compose f g)
(lambda(x) (f (g x))))
; ;;;;;;;;;;;;;;
; 1.43
(define (repeated f n)
(if( = n 1 ) f
(compose f (repeated f (- n 1 )))))
; ;;;;;;;;;;;;;;;
; 1.44
(define (smooth f)
(lambda(x) (/ (+ (f (- x dx))
(f x)
(f (+ x dx)))
3 )))
(define (smooth-n f)
(repeated f n))
(define (smooth-n f n)
((repeated smooth n) f))
2.01
(define (make-rat x y)
(let ((g (gcd x y)))
(if (< y 0 )
(cons (/ (- x) g) (/ (- y) g))
(cons (/ x g) (/ y g)))))
(let ((g (gcd x y)))
(if (< y 0 )
(cons (/ (- x) g) (/ (- y) g))
(cons (/ x g) (/ y g)))))
2.02
(define (make-point x y) (cons x y))
(define (x-point p) (car p))
(define (y-point p) (cdr p))
(define (make-segment p1 p2) (cons p1 p2))
(define (start-seg line) (car line))
(define (end-seg line) (cdr line))
(define (midpoint-segment line)
(make-point (/ (+ (x-point (start-seg line)) (x-point (end-seg line))) 2.0 )
(/ (+ (y-point (start-seg line)) (y-point (end-seg line))) 2.0 )))
(define (x-point p) (car p))
(define (y-point p) (cdr p))
(define (make-segment p1 p2) (cons p1 p2))
(define (start-seg line) (car line))
(define (end-seg line) (cdr line))
(define (midpoint-segment line)
(make-point (/ (+ (x-point (start-seg line)) (x-point (end-seg line))) 2.0 )
(/ (+ (y-point (start-seg line)) (y-point (end-seg line))) 2.0 )))
2.04
;
;;;;;;;;;;;;;;;;;;;;;;;;
; (cdr+ (cons+ x y) = ((cons+ x y) (lambda(p q) p)))
; = (lambda(m)(m x y) (lambda(p q) p)))
; = ((lambda(p q) p) x y)
; = x
(define (cons+ x y)
(lambda(m) (m x y)))
(define (car+ z)
(z (lambda(p q) p)))
(define (cdr+ z)
(z (lambda(p q) q)))
; (cdr+ (cons+ x y) = ((cons+ x y) (lambda(p q) p)))
; = (lambda(m)(m x y) (lambda(p q) p)))
; = ((lambda(p q) p) x y)
; = x
(define (cons+ x y)
(lambda(m) (m x y)))
(define (car+ z)
(z (lambda(p q) p)))
(define (cdr+ z)
(z (lambda(p q) q)))
2.05
2
^a *
3
^b
=
2
^c *
3
^d (a!
=
c && b!
=
d)
2 ^a/ 2 ^c = 3 ^d/ 3 ^b
2 ^(a-c) = 3 ^(d-b)
a = c && d = b
2 ^a/ 2 ^c = 3 ^d/ 3 ^b
2 ^(a-c) = 3 ^(d-b)
a = c && d = b
2.06
(define one (lambda(f) (lambda(x) (f x))))
(define two (lambda(f) (lambda(x) (f (f x)))))
(define two (lambda(f) (lambda(x) (f (f x)))))
2.07
(define (upper-bound pair)
(if (> (car pair) (cdr pair))
(car pair)
(cdr pair)))
(define (lower-bound pair)
(if (> (car pair) (cdr pair))
(cdr pair)
(car pair)))
(if (> (car pair) (cdr pair))
(car pair)
(cdr pair)))
(define (lower-bound pair)
(if (> (car pair) (cdr pair))
(cdr pair)
(car pair)))
2.08
(define (sub-interval x y)
(add-interval x (make-interval (- (upper-bound y))
(- (lower-bound y)))))
2.17
(add-interval x (make-interval (- (upper-bound y))
(- (lower-bound y)))))
(define (last-pair lst)
(if (null? (cdr lst))
(list (car lst))
(last-pair (cdr lst))))
(if (null? (cdr lst))
(list (car lst))
(last-pair (cdr lst))))
2.18
(define (reverse lst)
(define (iter lst-o lst-d)
(if (null? lst-o)
lst-d
(iter (cdr lst-o) (cons (car lst-o) lst-d))))
(iter lst null))
(define (iter lst-o lst-d)
(if (null? lst-o)
lst-d
(iter (cdr lst-o) (cons (car lst-o) lst-d))))
(iter lst null))
2.20
(define (same-parity x . lst)
(define (filter lst ok?)
(if (null? lst)
()
(if (ok? (car lst))
(cons (car lst) (filter (cdr lst) ok?))
(filter (cdr lst) ok?))))
(if (even? x)
(cons x (filter lst (lambda(x) (= 0 (remainder x 2)))))
(cons x (filter lst (lambda(x) (= 1 (remainder x 2)))))))
(define (filter lst ok?)
(if (null? lst)
()
(if (ok? (car lst))
(cons (car lst) (filter (cdr lst) ok?))
(filter (cdr lst) ok?))))
(if (even? x)
(cons x (filter lst (lambda(x) (= 0 (remainder x 2)))))
(cons x (filter lst (lambda(x) (= 1 (remainder x 2)))))))
2.21
(define (square-list- items)
(if (null? items)
()
(cons (* (car items) (car items))
(square-list- (cdr items)))))
(define (square-list items)
(map (lambda(x) (* x x)) items))
(if (null? items)
()
(cons (* (car items) (car items))
(square-list- (cdr items)))))
(define (square-list items)
(map (lambda(x) (* x x)) items))
2.22
第一种每次取出首元素平方后前插到新表,象reverse过程类似,所以是反的。
第二种只不过是把新表前插到元素前,得到的甚至不是一个list,而是
((((() . 1) . 4) . 9) . 16)
2.23
(define (for-each proc items)
(if (not (null? items))
((lambda() (proc (car items))
(for-each proc (cdr items))))))
(if (not (null? items))
((lambda() (proc (car items))
(for-each proc (cdr items))))))
2.25
(car (cdaddr (list
1
3
(list
5
7
)
9
)))
(caar (list (list 7 )))
(cadadr (cadadr(cadadr (list 1 (list 2 (list 3 (list 4 (list 5 (list 6 7 )))))))))
(caar (list (list 7 )))
(cadadr (cadadr(cadadr (list 1 (list 2 (list 3 (list 4 (list 5 (list 6 7 )))))))))
2.26
(
1
2
3
4
5
6
)
(( 1 2 3 ) 4 5 6 )
(( 1 2 3 ) ( 4 5 6 ))
2.27(( 1 2 3 ) 4 5 6 )
(( 1 2 3 ) ( 4 5 6 ))
(define (deep-reverse lst)
(define (iter lst-o lst-d)
(cond ((null? lst-o)
lst-d)
((not (pair? (car lst-o)))
(iter (cdr lst-o)
(cons (car lst-o) lst-d)))
(else
(iter (cdr lst-o)
(cons (deep-reverse (car lst-o))
lst-d)))))
(iter lst null))
(define (iter lst-o lst-d)
(cond ((null? lst-o)
lst-d)
((not (pair? (car lst-o)))
(iter (cdr lst-o)
(cons (car lst-o) lst-d)))
(else
(iter (cdr lst-o)
(cons (deep-reverse (car lst-o))
lst-d)))))
(iter lst null))
2.28
(define (fringe x)
(define (iter tree lst)
(cond ((null? tree) lst)
((not (pair? tree)) (cons tree lst))
(else (iter (car tree) (iter (cdr tree) lst)))))
(iter x null))
(define (iter tree lst)
(cond ((null? tree) lst)
((not (pair? tree)) (cons tree lst))
(else (iter (car tree) (iter (cdr tree) lst)))))
(iter x null))
2.30
(define (square-tree- x)
(cond ((null? x) null)
((not (pair? x)) (* x x))
(else (cons (square-tree- (car x))
(square-tree- (cdr x))))))
(define (square-tree x)
(map (lambda(subtree)
(if (pair? subtree)
(square-tree subtree)
(* subtree subtree)))
x))
(cond ((null? x) null)
((not (pair? x)) (* x x))
(else (cons (square-tree- (car x))
(square-tree- (cdr x))))))
(define (square-tree x)
(map (lambda(subtree)
(if (pair? subtree)
(square-tree subtree)
(* subtree subtree)))
x))
2.31
(define (tree-map proc tree)
(map (lambda(subtree)
(if (pair? subtree)
(tree-map proc subtree)
(proc subtree)))
tree))
(define (square-tree+ tree)
(tree-map (lambda(x) (* x x)) tree))
(map (lambda(subtree)
(if (pair? subtree)
(tree-map proc subtree)
(proc subtree)))
tree))
(define (square-tree+ tree)
(tree-map (lambda(x) (* x x)) tree))
2.32
(define (subsets s)
(if (null? s)
(list null)
(let ((rest (subsets (cdr s))))
(append rest (map (lambda(x) (cons (car s) x)) rest)))))
(if (null? s)
(list null)
(let ((rest (subsets (cdr s))))
(append rest (map (lambda(x) (cons (car s) x)) rest)))))
和换零钱问题的思路是一样的,对于一个集合的所有子集的集合,可以分为两部分,含有第一个元素和不含第一个元素的集合。而且含第一个元素的所有子集除去第一个元素,恰好正是所有不含第一个元素的子集。
也可以换个思路,对于集合A,设它可以表示为 (a1)∪(a2,...,an) ,而 (a2,...,an) 的所有子集的集合是 B=(B1,...Bm),那么可以证明A的所有子集的集合 C=B∪((A1)∪B1,(A1)∪B2,...,(A1)∪Bm);
证明:设 X 是 A 的一个子集,那么如果 a1∈X,那么 X ∈ ((A1)∪B1,(A1)∪B2,...,(A1)∪Bm),否则 X ∈B,所以
X ∈C
2.33
(define (map+ p seque)
(accumulate (lambda(x y) (cons (p x) y)) null seque))
(define (append seq1 seq2)
(accumulate cons seq2 seq1))
(define (length seque)
(accumulate (lambda(x y) (+ 1 y)) 0 seque))
(accumulate (lambda(x y) (cons (p x) y)) null seque))
(define (append seq1 seq2)
(accumulate cons seq2 seq1))
(define (length seque)
(accumulate (lambda(x y) (+ 1 y)) 0 seque))
2.34
(define (horner-eval x coeff-seque)
(accumulate (lambda(this-coeff higher-coeff)
(+ this-coeff (* x higher-coeff)))
0 coeff-seque))
(accumulate (lambda(this-coeff higher-coeff)
(+ this-coeff (* x higher-coeff)))
0 coeff-seque))
2.35
(define (count-leaves+ t)
(accumulate + 0 (map (lambda(x)
(if (pair? x) (count-leaves+ x) 1 ))
t)))
2.36(accumulate + 0 (map (lambda(x)
(if (pair? x) (count-leaves+ x) 1 ))
t)))
(define s (list (list
1
2
3
)(list
4
5
6
)(list
7
8
9
)(list
10
11
12
)))
(define (accumulate-n op init seqs)
(if (null? (car seqs)) null
(cons (accumulate op init (map# (lambda(x) (car x)) seqs))
(accumulate-n op init (map# (lambda(x) (cdr x)) seqs)))))
(define (accumulate-n op init seqs)
(if (null? (car seqs)) null
(cons (accumulate op init (map# (lambda(x) (car x)) seqs))
(accumulate-n op init (map# (lambda(x) (cdr x)) seqs)))))
2.38
;
> (fold-right / 1 (list 1 2 3))
; 3/2
; > (fold-left / 1 (list 1 2 3))
; 1/6
; > (fold-right list null (list 1 2 3))
; (1 (2 (3 ())))
; > (fold-left list null (list 1 2 3))
; (((() 1) 2) 3)
; (fold-right op i (a b c)) = (op a (op b (op c i)))
; (fold-left op i (a b c)) = (op (op (op i a) b) c)
; 3/2
; > (fold-left / 1 (list 1 2 3))
; 1/6
; > (fold-right list null (list 1 2 3))
; (1 (2 (3 ())))
; > (fold-left list null (list 1 2 3))
; (((() 1) 2) 3)
; (fold-right op i (a b c)) = (op a (op b (op c i)))
; (fold-left op i (a b c)) = (op (op (op i a) b) c)
要 fold-right 和 fold-left 得到相同的结果,显然需要 op 满足交换律。
2.39
(define (reverse-
1
seqs)
(fold-right (lambda(x y) (append y (list x))) null seqs))
(define (reverse- 2 seqs)
(fold-left (lambda(x y) (cons y x)) null seqs))
(fold-right (lambda(x y) (append y (list x))) null seqs))
(define (reverse- 2 seqs)
(fold-left (lambda(x y) (cons y x)) null seqs))