Add solutions to exercises from section 1.2
To be noted: the drawing in exercise 1.14 is unfinished. I did it in a notebook, but haven't yet had the time to put it in a txt file.
This commit is contained in:
parent
16d2911936
commit
a697f52405
21 changed files with 525 additions and 0 deletions
25
ex-1.09.txt
Normal file
25
ex-1.09.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
For the first +:
|
||||
(+ 4 5)
|
||||
(inc (+ (dec 4) 5))
|
||||
(inc (+ 3 5))
|
||||
(inc (inc (+ (dec 3) 5)))
|
||||
..
|
||||
(inc (inc (inc (+ 1 5))))
|
||||
..
|
||||
(inc (inc (inc (inc (+ 0 5)))))
|
||||
(inc (inc (inc (inc 5))))
|
||||
(inc (inc (inc 6)))
|
||||
(inc (inc 7))
|
||||
(inc 8)
|
||||
9
|
||||
|
||||
For the second +:
|
||||
(+ 4 5)
|
||||
(+ (dec 4) (inc 5))
|
||||
(+ 3 6)
|
||||
(+ 2 7)
|
||||
(+ 1 8)
|
||||
(+ 0 9)
|
||||
9
|
||||
|
||||
First is recursive, second is iterative.
|
8
ex-1.10.scm
Normal file
8
ex-1.10.scm
Normal file
|
@ -0,0 +1,8 @@
|
|||
#lang sicp
|
||||
|
||||
(define (A x y)
|
||||
(cond ((= y 0) 0)
|
||||
((= x 0) (* 2 y))
|
||||
((= y 1) 2)
|
||||
(else (A (- x 1)
|
||||
(A x (- y 1))))))
|
17
ex-1.10.txt
Normal file
17
ex-1.10.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
(A 1 10)
|
||||
2**10
|
||||
|
||||
(A 2 4)
|
||||
(A 1 (A 2 3))
|
||||
(A 1 (A 1 (A 2 ))
|
||||
|
||||
2**2**2**2
|
||||
|
||||
(A 3 3)
|
||||
(A 2 (A 3 2))
|
||||
2P3
|
||||
2t(4)
|
||||
|
||||
(f n) == 2*n
|
||||
(g n) == 2**n
|
||||
(h n) == 2**2**...**2 <- n times
|
24
ex-1.11.scm
Normal file
24
ex-1.11.scm
Normal file
|
@ -0,0 +1,24 @@
|
|||
#lang sicp
|
||||
|
||||
; recursive process
|
||||
(define (f1 n)
|
||||
(if (< n 3)
|
||||
n
|
||||
(+ (f1 (- n 1))
|
||||
(* 2 (f1 (- n 2)))
|
||||
(* 3 (f1 (- n 3))))))
|
||||
|
||||
; iterative process
|
||||
|
||||
; loop for n >= 3
|
||||
(define (f-iter iter-count acc1 acc2 acc3)
|
||||
(let ((new-val (+ acc1 (* 2 acc2) (* 3 acc3))))
|
||||
(if (= iter-count 0)
|
||||
new-val
|
||||
(f-iter (- iter-count 1) new-val acc1 acc2))))
|
||||
|
||||
(define (f2 n)
|
||||
(if (< n 3)
|
||||
n
|
||||
(f-iter (- n 3) (f2 2) (f2 1) (f2 0))))
|
||||
; these are just 2,1,0 respectively, but I felt this looks cleaner
|
5
ex-1.12.scm
Normal file
5
ex-1.12.scm
Normal file
|
@ -0,0 +1,5 @@
|
|||
#lang sicp
|
||||
|
||||
(define (solution n k)
|
||||
(cond ((or (= n 1) (= k 1) (= k n)) 1)
|
||||
(else (+ (solution (- n 1) (- k 1)) (solution (- n 1) k)))))
|
11
ex-1.13.txt
Normal file
11
ex-1.13.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
Dokazemo indukcijom, prvo za Fib(0) i Fib(1), kao baze.
|
||||
|
||||
Zatim dokazemo da Fib(n), sto je Fib(n-1) + Fib(n-2) sto je (phi^(n-1) -
|
||||
psi^(n-1) + phi^(n-2) - psi^(n-2))/sqrt(5) da je to jednako (phi^n -
|
||||
psi^n)/sqrt(5), sto je ustv lako jer je: phi^n = phi^(n-1) + phi^(n-2), isto
|
||||
vazi i za psi, pa se to malo razbije i pretumba, i dobijemo: Fib(n) = (phi^n -
|
||||
psi^n)/sqrt(5), za svako n u N.
|
||||
|
||||
Razlog zasto ovo dokazuje da je Fib(n) uvek najblizi ceo broj jeste to da psi
|
||||
~=~ 0.36 < 0.5, a psi^n <<< psi, kad n>1. Dakle razlika između Fib(n) i
|
||||
phi^n/sqrt(5) je uvek manja od 0.5. Dakle najblizi je ceo broj.
|
10
ex-1.14.txt
Normal file
10
ex-1.14.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
It's a very big tree.....
|
||||
57 nodes, i'm not gonna type it out, around half of it is cases like:
|
||||
(cc 11 1)
|
||||
/ \
|
||||
(cc 11 0) (cc 10 1)
|
||||
/ \
|
||||
(cc 10 0) (cc 9 1)
|
||||
/ \
|
||||
(cc 9 0) (cc 8 1)
|
||||
..................................
|
5
ex-1.15.txt
Normal file
5
ex-1.15.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
Every time we call sine we end up calling
|
||||
(p (sine angle/3)), which becomes
|
||||
(p (p (sine angle/3/3))), etc.
|
||||
So we end up calling it once each time until angle reaches 0.1/
|
||||
In other words ceil(log3(12.15/0.1)) = 5
|
8
ex-1.16.scm
Normal file
8
ex-1.16.scm
Normal file
|
@ -0,0 +1,8 @@
|
|||
#lang sicp
|
||||
|
||||
(define (expt-aux b n a)
|
||||
(cond ((= n 0) a)
|
||||
((even? n) (expt-aux (* b b) (/ n 2) a))
|
||||
(else (expt-aux b (- n 1) (* a b)))))
|
||||
(define (solution b n)
|
||||
(expt-aux b n 1))
|
10
ex-1.17.scm
Normal file
10
ex-1.17.scm
Normal file
|
@ -0,0 +1,10 @@
|
|||
#lang sicp
|
||||
|
||||
(define (double x) (* 2 x))
|
||||
(define (halve x) (/ x 2))
|
||||
(define (*aux a b acc)
|
||||
(cond ((= b 0) acc)
|
||||
((even? b) (*aux (double a) (halve b) acc))
|
||||
(else (*aux a (- b 1) (+ acc a)))))
|
||||
(define (fast-mul a b)
|
||||
(*aux a b 0))
|
1
ex-1.18.scm
Normal file
1
ex-1.18.scm
Normal file
|
@ -0,0 +1 @@
|
|||
; Actually, this was already solved in the previous exercise
|
17
ex-1.19.scm
Normal file
17
ex-1.19.scm
Normal file
|
@ -0,0 +1,17 @@
|
|||
#lang sicp
|
||||
|
||||
(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)))))
|
52
ex-1.20.txt
Normal file
52
ex-1.20.txt
Normal file
|
@ -0,0 +1,52 @@
|
|||
(gcd 206 40)
|
||||
; 40 != 0
|
||||
(gcd 40 (remainder 206 40))
|
||||
; in the if, remainder is computed and it isn't zero - 1c
|
||||
; but I'm pretty sure this doesn't mean the remainder as the
|
||||
; argument to gcd is evaluated, so we get:
|
||||
(gcd (remainder 206 40) (remainder 40 (remainder 206 40)))
|
||||
; in the next if, the two nested remainders must be computed - 2c
|
||||
; and we're left with
|
||||
(gcd (remainder 40 (remainder 206 40))
|
||||
(remainder (remainder 206 40)
|
||||
(remainder 40 (remainder 206 40))))
|
||||
; in the next, the nested 4 are computed - 4c
|
||||
; and we have:
|
||||
(gcd (remainder (remainder 206 40)
|
||||
(remainder 40 (remainder 206 40)))
|
||||
(remainder (remainder 40 (remainder 206 40))
|
||||
(remainder (remainder 206 40)
|
||||
(remainder 40 (remainder 206 40)))))
|
||||
; and the nested 7 must be computed. This will actually return 0, and then the
|
||||
; first arg (4 nested remainder calls) must be evaluated, and that's it, but
|
||||
; let's generalize.
|
||||
|
||||
; counting n from 0:
|
||||
; notice in each n-th recursive pass, we evaluate remainder G(n+1) times.
|
||||
; But also our arguments (a, b) end up having G(n+1)-level and G(n+2)-level
|
||||
; indented applications of remainder, respectively, previously they had G(n)
|
||||
; and G(n+1)
|
||||
|
||||
; here G(0)=G(1)=0, and for n>1 G(n) = G(n-1) + G(n-2) + 1
|
||||
; so: G | n
|
||||
----+---
|
||||
; 0 | 0
|
||||
; 0 | 1
|
||||
; 1 | 2
|
||||
; 2 | 3
|
||||
; 4 | 4
|
||||
; 7 | 5
|
||||
|
||||
; this happens until n=4, which is the last function call because that's when
|
||||
; the right hand (G(5) calls) will evaluate to zero. And the final result, the
|
||||
left hand, (G(4) calls) will be evaluated, and return 2.
|
||||
|
||||
So ultimately, the number of calls that must happen is:
|
||||
G(1) + G(2) + ... + G(5) + G(4) (again)
|
||||
or, more generally, if it takes n steps to compute the GCD:
|
||||
Sum(G(1)..G(n+1)) + G(n) calls to remainder will be required.
|
||||
|
||||
In out situation, this will be 0+1+2+4+7+4 = 18 calls.
|
||||
|
||||
In the applicative order, the situation is far simpler, every recursive pass,
|
||||
except the last, requires 1 call to remainder, so 4 calls.
|
18
ex-1.21.scm
Normal file
18
ex-1.21.scm
Normal file
|
@ -0,0 +1,18 @@
|
|||
#lang sicp
|
||||
|
||||
(define (square x) (* x x))
|
||||
(define (smallest-divisor n)
|
||||
(find-divisor n 2))
|
||||
(define (find-divisor n test-divisor)
|
||||
(cond ((> (square test-divisor) n) n)
|
||||
((divides? test-divisor n) test-divisor)
|
||||
(else (find-divisor n (+ test-divisor 1)))))
|
||||
(define (divides? a b)
|
||||
(= (remainder b a) 0))
|
||||
|
||||
;> (smallest-divisor 199)
|
||||
;199
|
||||
;> (smallest-divisor 1999)
|
||||
;1999
|
||||
;> (smallest-divisor 19999)
|
||||
;7
|
171
ex-1.22.scm
Normal file
171
ex-1.22.scm
Normal file
|
@ -0,0 +1,171 @@
|
|||
#lang sicp
|
||||
|
||||
(define (square x) (* x x))
|
||||
|
||||
(define (smallest-divisor n)
|
||||
(find-divisor n 2))
|
||||
(define (find-divisor n test-divisor)
|
||||
(cond ((> (square test-divisor) n) n)
|
||||
((divides? test-divisor n) test-divisor)
|
||||
(else (find-divisor n (+ test-divisor 1)))))
|
||||
(define (divides? a b)
|
||||
(= (remainder b a) 0))
|
||||
|
||||
(define (prime? n)
|
||||
(= n (smallest-divisor n)))
|
||||
|
||||
(define (timed-prime-test n)
|
||||
(newline)
|
||||
(display n)
|
||||
(start-prime-test n (runtime)))
|
||||
|
||||
(define (start-prime-test n start-time)
|
||||
(if (prime? n)
|
||||
(report-prime (- (runtime) start-time))))
|
||||
|
||||
(define (report-prime elapsed-time)
|
||||
(display " *** ")
|
||||
(display elapsed-time))
|
||||
|
||||
#| BEGIN (Write your solution here) |#
|
||||
(define (search-for-primes a b)
|
||||
(cond ((> a b) '())
|
||||
((not (even? a))
|
||||
(timed-prime-test a)
|
||||
(search-for-primes (+ a 2) b))
|
||||
(else (search-for-primes (+ a 1) b))))
|
||||
#| END |#
|
||||
|
||||
|
||||
;;;; TESTED OUTPUT
|
||||
;> (search-for-primes 1000 2000)
|
||||
;
|
||||
;1001
|
||||
;1003
|
||||
;1005
|
||||
;1007
|
||||
;1009 *** 1
|
||||
;1011
|
||||
;1013 *** 1
|
||||
;1015
|
||||
;1017
|
||||
;1019 *** 1
|
||||
;1021 *** 1
|
||||
;1023
|
||||
;1025
|
||||
;1027
|
||||
;1029
|
||||
;1031 *** 2
|
||||
;1033 *** 1
|
||||
;1035
|
||||
;1037
|
||||
;1039 *** 2
|
||||
;1041
|
||||
;1043
|
||||
;1045
|
||||
|
||||
;> (search-for-primes 10000 10100)
|
||||
;
|
||||
;10001
|
||||
;10003
|
||||
;10005
|
||||
;10007 *** 7
|
||||
;10009 *** 5
|
||||
;10011
|
||||
;10013
|
||||
;10015
|
||||
;10017
|
||||
;10019
|
||||
;10021
|
||||
;10023
|
||||
;10025
|
||||
;10027
|
||||
;10029
|
||||
;10031
|
||||
;10033
|
||||
;10035
|
||||
;10037 *** 4
|
||||
;10039 *** 5
|
||||
;10041
|
||||
;10043
|
||||
;10045
|
||||
;10047
|
||||
;10049
|
||||
;10051
|
||||
;10053
|
||||
;10055
|
||||
;10057
|
||||
;10059
|
||||
;10061 *** 5
|
||||
;10063
|
||||
;10065
|
||||
;10067 *** 5
|
||||
;10069 *** 4
|
||||
;10071
|
||||
;10073
|
||||
;10075
|
||||
;10077
|
||||
;10079 *** 4
|
||||
;10081
|
||||
;10083
|
||||
;10085
|
||||
;10087
|
||||
;10089
|
||||
;10091 *** 5
|
||||
;10093 *** 9
|
||||
;10095
|
||||
;10097
|
||||
;10099 *** 7()
|
||||
|
||||
;> (search-for-primes 100000 100100)
|
||||
;
|
||||
;100001
|
||||
;100003 *** 16
|
||||
;100005
|
||||
;100007
|
||||
;100009
|
||||
;100011
|
||||
;100013
|
||||
;100015
|
||||
;100017
|
||||
;100019 *** 15
|
||||
;100021
|
||||
;100023
|
||||
;100025
|
||||
;100027
|
||||
;100029
|
||||
;100031
|
||||
;100033
|
||||
;100035
|
||||
;100037
|
||||
;100039
|
||||
;100041
|
||||
;100043 *** 15
|
||||
;100045
|
||||
;100047
|
||||
;100049 *** 17
|
||||
;100051
|
||||
;100053
|
||||
;100055
|
||||
;100057 *** 16
|
||||
;100059
|
||||
;100061
|
||||
;100063
|
||||
;100065
|
||||
;100067
|
||||
;100069 *** 16
|
||||
;100071
|
||||
;100073
|
||||
;100075
|
||||
;100077
|
||||
;100079
|
||||
;100081
|
||||
;100083
|
||||
;100085
|
||||
;100087
|
||||
;100089
|
||||
;100091
|
||||
;100093
|
||||
;100095
|
||||
;100097
|
||||
;100099()
|
26
ex-1.23.scm
Normal file
26
ex-1.23.scm
Normal file
|
@ -0,0 +1,26 @@
|
|||
#lang sicp
|
||||
|
||||
(define (square x) (* x x))
|
||||
;(define (next x)
|
||||
; (if (= x 2)
|
||||
; 3
|
||||
; (+ x 2)))
|
||||
(define (next x) (+ x 1))
|
||||
|
||||
(define (smallest-divisor n)
|
||||
(find-divisor 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)))))
|
||||
(define (divides? a b)
|
||||
(= (remainder b a) 0))
|
||||
|
||||
(define (time-sd n)
|
||||
(define start-time (runtime))
|
||||
(smallest-divisor n)
|
||||
(- (runtime) start-time))
|
||||
; comparing (time-sd 100069) with the new and old versions
|
||||
; it's roughly a 1.5 factor increase, likely because the if
|
||||
; statement checking is slightly more expensive than simply increasing
|
||||
; by one
|
54
ex-1.24.scm
Normal file
54
ex-1.24.scm
Normal file
|
@ -0,0 +1,54 @@
|
|||
#lang sicp
|
||||
|
||||
(define (square x) (* x x))
|
||||
|
||||
(define (expmod base exp m)
|
||||
(cond ((= exp 0) 1)
|
||||
((even? exp)
|
||||
(remainder (square (expmod base (/ exp 2) m))
|
||||
m))
|
||||
(else
|
||||
(remainder (* base (expmod base (- exp 1) m))
|
||||
m))))
|
||||
|
||||
(define (smallest-divisor n)
|
||||
(find-divisor n 2))
|
||||
(define (find-divisor n test-divisor)
|
||||
(cond ((> (square test-divisor) n) n)
|
||||
((divides? test-divisor n) test-divisor)
|
||||
(else (find-divisor n (+ test-divisor 1)))))
|
||||
(define (divides? a b)
|
||||
(= (remainder b a) 0))
|
||||
|
||||
(define (fermat-test n)
|
||||
(define (try-it a)
|
||||
(= (expmod 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)))
|
||||
|
||||
(define (prime? n)
|
||||
(= n (smallest-divisor n)))
|
||||
|
||||
(define (timed-prime-test n)
|
||||
(newline)
|
||||
(display n)
|
||||
(start-prime-test n (runtime)))
|
||||
|
||||
(define (start-prime-test n start-time)
|
||||
(if (fast-prime? n 10)
|
||||
(report-prime (- (runtime) start-time))))
|
||||
|
||||
(define (report-prime elapsed-time)
|
||||
(display " *** ")
|
||||
(display elapsed-time))
|
||||
|
||||
(define (search-for-primes a b)
|
||||
(cond ((> a b) '())
|
||||
((not (even? a))
|
||||
(timed-prime-test a)
|
||||
(search-for-primes (+ a 2) b))
|
||||
(else (search-for-primes (+ a 1) b))))
|
2
ex-1.25.txt
Normal file
2
ex-1.25.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
No, because it would produce extremely large exponentials, which
|
||||
would be computed more slowly. And computing the remainder would be extremely slow.
|
10
ex-1.26.txt
Normal file
10
ex-1.26.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
Essentially, instead of us halving the time of computation,
|
||||
every time we have an even number, we instead halve the expmod call
|
||||
but then, make that call twice, in other words, instead of
|
||||
(specifically for even number):
|
||||
T(n) = O(1) + T(n/2)
|
||||
we get:
|
||||
T(n) = O(1) + 2*T(n/2), which is going to give us roughly:
|
||||
O(n)
|
||||
We get a recursion tree, growing exponentially with at every recursive call,
|
||||
of which there are O(log n), so exp(log(n)) = n.
|
27
ex-1.27.scm
Normal file
27
ex-1.27.scm
Normal file
|
@ -0,0 +1,27 @@
|
|||
#lang sicp
|
||||
(define (square x) (* x x))
|
||||
(define (expmod-aux base exp n acc)
|
||||
(cond ((= 0 exp) acc)
|
||||
((even? exp) (expmod-aux (remainder (square base) n) (/ exp 2) n acc))
|
||||
(else (expmod-aux base (- exp 1) n (remainder (* acc base) n)))))
|
||||
(define (expmod base exp n)
|
||||
(expmod-aux base exp n 1))
|
||||
(define (carmichael-test-aux n a)
|
||||
(cond ((>= a n) #t)
|
||||
((= (expmod a n n) a) (carmichael-test-aux n (+ a 1)))
|
||||
(else #f)))
|
||||
(define (carmichael-test n)
|
||||
(carmichael-test-aux n 0))
|
||||
;> (carmichael-test 561)
|
||||
;#t
|
||||
;> (carmichael-test 1105)
|
||||
;#t
|
||||
;> (carmichael-test 1729)
|
||||
;#t
|
||||
;> (carmichael-test 2465)
|
||||
;#t
|
||||
;> (carmichael-test 2821)
|
||||
;#t
|
||||
;> (carmichael-test 6601)
|
||||
;#t
|
||||
;>
|
24
ex-1.28.scm
Normal file
24
ex-1.28.scm
Normal file
|
@ -0,0 +1,24 @@
|
|||
#lang sicp
|
||||
|
||||
(define (square n) (* n n))
|
||||
|
||||
(define (expmod-aux base exp n acc)
|
||||
(define sqr (remainder (square base) n))
|
||||
(cond ((= 0 exp) acc)
|
||||
((even? exp)
|
||||
(if (and (= sqr 1)
|
||||
(not (= base 1))
|
||||
(not (= base (- n 1))))
|
||||
0
|
||||
(expmod-aux sqr (/ exp 2) n acc)))
|
||||
(else (expmod-aux base (- exp 1) n (remainder (* acc base) n)))))
|
||||
|
||||
(define (expmod base exp n)
|
||||
(expmod-aux base exp n 1))
|
||||
|
||||
(define (miller-rabin-test n)
|
||||
(define (try-it a)
|
||||
(= (expmod a (- n 1) n) 1))
|
||||
(if (and (even? n) (not (= 2 n)))
|
||||
#f
|
||||
(try-it (+ 1 (random (- n 1))))))
|
Loading…
Add table
Reference in a new issue