diff --git a/ex-1.09.txt b/ex-1.09.txt new file mode 100644 index 0000000..8536ea2 --- /dev/null +++ b/ex-1.09.txt @@ -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. diff --git a/ex-1.10.scm b/ex-1.10.scm new file mode 100644 index 0000000..8d3a1e5 --- /dev/null +++ b/ex-1.10.scm @@ -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)))))) diff --git a/ex-1.10.txt b/ex-1.10.txt new file mode 100644 index 0000000..f0b85c7 --- /dev/null +++ b/ex-1.10.txt @@ -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 diff --git a/ex-1.11.scm b/ex-1.11.scm new file mode 100644 index 0000000..9aec952 --- /dev/null +++ b/ex-1.11.scm @@ -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 \ No newline at end of file diff --git a/ex-1.12.scm b/ex-1.12.scm new file mode 100644 index 0000000..4860e83 --- /dev/null +++ b/ex-1.12.scm @@ -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))))) diff --git a/ex-1.13.txt b/ex-1.13.txt new file mode 100644 index 0000000..d379210 --- /dev/null +++ b/ex-1.13.txt @@ -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. diff --git a/ex-1.14.txt b/ex-1.14.txt new file mode 100644 index 0000000..21b03b1 --- /dev/null +++ b/ex-1.14.txt @@ -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) +.................................. diff --git a/ex-1.15.txt b/ex-1.15.txt new file mode 100644 index 0000000..d3031b2 --- /dev/null +++ b/ex-1.15.txt @@ -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 diff --git a/ex-1.16.scm b/ex-1.16.scm new file mode 100644 index 0000000..8a3928e --- /dev/null +++ b/ex-1.16.scm @@ -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)) diff --git a/ex-1.17.scm b/ex-1.17.scm new file mode 100644 index 0000000..d988638 --- /dev/null +++ b/ex-1.17.scm @@ -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)) diff --git a/ex-1.18.scm b/ex-1.18.scm new file mode 100644 index 0000000..c66a194 --- /dev/null +++ b/ex-1.18.scm @@ -0,0 +1 @@ +; Actually, this was already solved in the previous exercise diff --git a/ex-1.19.scm b/ex-1.19.scm new file mode 100644 index 0000000..8d50684 --- /dev/null +++ b/ex-1.19.scm @@ -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))))) diff --git a/ex-1.20.txt b/ex-1.20.txt new file mode 100644 index 0000000..8311025 --- /dev/null +++ b/ex-1.20.txt @@ -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. diff --git a/ex-1.21.scm b/ex-1.21.scm new file mode 100644 index 0000000..4e7b170 --- /dev/null +++ b/ex-1.21.scm @@ -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 \ No newline at end of file diff --git a/ex-1.22.scm b/ex-1.22.scm new file mode 100644 index 0000000..9a2e328 --- /dev/null +++ b/ex-1.22.scm @@ -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() diff --git a/ex-1.23.scm b/ex-1.23.scm new file mode 100644 index 0000000..baf4c74 --- /dev/null +++ b/ex-1.23.scm @@ -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 diff --git a/ex-1.24.scm b/ex-1.24.scm new file mode 100644 index 0000000..0520a9c --- /dev/null +++ b/ex-1.24.scm @@ -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)))) diff --git a/ex-1.25.txt b/ex-1.25.txt new file mode 100644 index 0000000..461e086 --- /dev/null +++ b/ex-1.25.txt @@ -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. diff --git a/ex-1.26.txt b/ex-1.26.txt new file mode 100644 index 0000000..972ee9f --- /dev/null +++ b/ex-1.26.txt @@ -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. diff --git a/ex-1.27.scm b/ex-1.27.scm new file mode 100644 index 0000000..284a8a5 --- /dev/null +++ b/ex-1.27.scm @@ -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 +;> diff --git a/ex-1.28.scm b/ex-1.28.scm new file mode 100644 index 0000000..f733d3b --- /dev/null +++ b/ex-1.28.scm @@ -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))))))