commit bdfff4a9a2594575d2d9e11d5edbd4207b7e7358 Author: Oliver Payne Date: Mon May 10 21:57:13 2021 +0100 Initial commit diff --git a/1_10.sch b/1_10.sch new file mode 100644 index 0000000..6c08dec --- /dev/null +++ b/1_10.sch @@ -0,0 +1,21 @@ +(define (A x y) + (cond ((= y 0) 0) + ((= x 0) (+ 2 y)) + ((= y 1) 2) + (else (A (- x 1) + (A x (- y 1)))))) + +; 2+n +(define (f n) + (A 0 n)) + +; 2*n +(define (g n) + (A 1 n)) + +; 2^n +(define (h n) + (A 2 n)) + +(define (k n) + (* 5 n n)) diff --git a/1_11.sch b/1_11.sch new file mode 100644 index 0000000..273bcf1 --- /dev/null +++ b/1_11.sch @@ -0,0 +1,23 @@ +; f(n) = n, n < 3, f(n) = f(n-1) + 2f(n-2) + 3f(n-3) n >= 3 + +(define (f1 n) + (if (< n 3) + n + (+ (f1 (- n 1)) + (* 2 (f1 (- n 2))) + (* 3 (f1 (- n 3)))))) + +(define (f2 n) + (if (< n 3) + n + (f-iter 2 1 0 n))) + +; a = f(2), b = f(1), c = f(0) +; a <- a + 2b + 3c, b <- a, c <- b +(define (f-iter a b c count) + (if (< count 3) + a + (f-iter (+ a (* 2 b) (* 3 c)) + a + b + (- count 1)))) diff --git a/1_12.sch b/1_12.sch new file mode 100644 index 0000000..c0d6524 --- /dev/null +++ b/1_12.sch @@ -0,0 +1,6 @@ +(define (pascal row col) + (cond + ((= col 1) 1) + ((or (= col 1) (= col row)) 1) + (else (+ (pascal (- row 1) (- col 1)) + (pascal (- row 1) col))))) diff --git a/1_16.sch b/1_16.sch new file mode 100644 index 0000000..9a51660 --- /dev/null +++ b/1_16.sch @@ -0,0 +1,11 @@ +(define (expt1 b n) + (expt-iter b n 1)) + +(define (expt-iter b n a) + (cond ((= n 0) a) + ((odd? n) + (expt-iter b (- n 1) (* a b))) + (else (expt-iter (square b) (/ n 2) a)))) + +(define (square x) (* x x)) + diff --git a/1_17.sch b/1_17.sch new file mode 100644 index 0000000..92ee256 --- /dev/null +++ b/1_17.sch @@ -0,0 +1,17 @@ +(define (mult-rec a b) + (cond ((= b 0) 0) + ((even? b) (mult-rec (double a) (halve b))) + (else (+ a (mult-rec a (- b 1)))))) + +(define (mult-iter a b n) + (cond ((= b 0) n) + ((even? b) (mult-iter (double a) (halve b) n)) + (else (mult-iter a (- b 1) (+ a n))))) + +(define (mult a b) + (mult-iter a b 0)) + +(define (double a) (+ a a)) + +(define (halve a) (/ a 2)) + diff --git a/1_21.sch b/1_21.sch new file mode 100644 index 0000000..bfa3fc3 --- /dev/null +++ b/1_21.sch @@ -0,0 +1,125 @@ +(import chicken.time) ; for current-milliseconds +(import chicken.random) ; for pseudo-random-integer + +(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 (square x) (* x x)) + + +(define (timed-prime-test n) + ;(newline) + ;(display n) + (start-prime-test n (current-milliseconds))) + +(define (start-prime-test n start-time) + (if (prime? n) + (report-prime n (- (current-milliseconds) start-time)))) + +(define (report-prime n elapsed-time) + (display n) + (display " *** ") + (display elapsed-time) + (newline)) + + +(define (search-for-primes min max) + (if (<= min max) + (cond ((odd? min) (timed-prime-test min) + (search-for-primes (+ min 2) max)) + (else (search-for-primes (+ min 1) max))))) + + +; (search-for-primes 100000 100100): First 3 take 1 ms each +; (search-for-primes 1000000 1000100): First 3 take 4, 3, 5 ms each +; (search-for-primes 10000000 10000200): First 3 take 14, 12, 13 ms each + +; (sqrt 10) is 3.1622, so time increase is around sqrt(n), as expected. + + +(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))))) + +; Now (search-for-primes 10000000 10000200): takes 7, 7, 10 ms each. So approximately +; half for the first two but a bit more for the third. This will be quicker, if the +; procedure has to search through lots of candidate divisors. Each call to next is +; more expensive that adding 1, which may account for the difference. + +; Increase the size of the integers (to reduce noisy measurements): +; (search-for-primes 10000000000 10000000200) +; This takes ~141ms for the +1 case and ~87ms for the next case: A speedup of around +; 1.6. This must be accounted for by the extra comparison. + + +; 1.24 + +(define (fermat-test n) + (define (try-it a) + (= (expmod a n n) a)) + (try-it (+ 1 (pseudo-random-integer (- n 1))))) + +(define (expmod base exp m) + (cond ((= exp 0) 1) + ((even? exp) + (remainder (square (expmod base (/ exp 2) m)) + m)) + (else + (remainder (* (expmod base (- exp 1) m) base) + m)))) + +(define (fast-prime? n times) + (cond ((= times 0) #t) + ((fermat-test n) (fast-prime? n (- times 1))) + (else #f))) + +(define (prime? n) + (fast-prime? n 10)) + +; Now prime test as above takes 2-3 ms for the first three answers +; (search-for-primes (square 10000000000) (+ 500 (square 10000000000))) +; This should be about double, given the the algorithm is logarithmic in time. +; We get 6, 8, 8 ms (more like 3 times as long). Maybe this is from the higher +; overhead of the random number generator? Or more likely, because we are running +; the Fermat test 10 times. + +; 1.25: The answer should be the same if we take remainders after exponentiating, +; but exponentiating first keeps the numbers smaller, thus enabling testing of +; larger primes with less memory. + +; 1.26: Writing out the multiplication instead of using square means that the +; argument is computed twice (once for each argument to * rather than once for +; square. So we are no longer halving the number of steps needed. Hence, this is +; no longer a log n algorithm. + +; 1.27 + +; Test if a^n is congruent to a mod n for all a result 1) + ; (display "MR test failed: ") + ; (display result) + ; (newline) + #f) ; a^(n-1) not congruent 1 (n): not prime + (else (miller-rabin-test n (- count 1)))))) + + +(define (prime? n) + (miller-rabin-test n 25)) diff --git a/1_29.sch b/1_29.sch new file mode 100644 index 0000000..38a468a --- /dev/null +++ b/1_29.sch @@ -0,0 +1,17 @@ +(define (cube x) (* x x x)) + +(define (simpson-iter f a b n k) + (let* ((h (/ (- b a) n)) + (y (f (+ a (* k h)))) + (coeff + (cond ((= k 0) 1) + ((= k n) 1) + ((odd? k) 4) + ((even? k) 2)))) + (+ (* (/ h 3) (* coeff y)) + (if (= k n) + 0 + (simpson-iter f a b n (+ k 1)))))) + +(define (simpson-int f a b n) + (simpson-iter f a b n 0)) diff --git a/1_30.sch b/1_30.sch new file mode 100644 index 0000000..d5332bf --- /dev/null +++ b/1_30.sch @@ -0,0 +1,13 @@ +(define (sum-iter term a next b) + (define (iter a result) + (if (> a b) + result + (iter (next a) (+ result (term a))))) + (iter a 0)) + +(define (pi-sum a b) + (define (pi-term x) + (/ 1.0 (* x (+ x 2)))) + (define (pi-next x) + (+ x 4)) + (sum-iter pi-term a pi-next b)) diff --git a/1_31.sch b/1_31.sch new file mode 100644 index 0000000..802262a --- /dev/null +++ b/1_31.sch @@ -0,0 +1,33 @@ +(define (square x) (* x x)) + +(define (product-rec term a next b) + (if (> a b) + 1 + (* (term a) + (product term (next a) next b)))) + + +(define (product-iter term a next b) + (define (iter a result) + (if (> a b) + result + (iter (next a) (* result (term a))))) + (iter a 1)) + +(define product product-iter) +;(define product product-rec) + +(define (fact n) + (product + (lambda (x) x) + 1 + (lambda (x) (+ x 1)) + n)) + +; Approximation to pi/4 +(define (pi-prod n) + (product + (lambda (a) (/ (* a (+ a 2)) (square (+ a 1)))) + 2 + (lambda (a) (+ a 2)) + n)) diff --git a/1_32.sch b/1_32.sch new file mode 100644 index 0000000..edd88b5 --- /dev/null +++ b/1_32.sch @@ -0,0 +1,41 @@ +(define (accumulate-rec combiner null-value term a next b) + (if (> a b) + null-value + (combiner (term a) + (accumulate combiner null-value term (next a) next b)))) + +(define (accumulate-iter combiner null-value term a next b) + (define (iter a result) + (if (> a b) + result + (iter (next a) (combiner result (term a))))) + (iter a null-value)) + +;(define accumulate accumulate-rec) +(define accumulate accumulate-iter) + +(define (product term a next b) + (accumulate + (lambda (x y) (* x y)) + 1 + term + a + next + b)) + +(define (sum term a next b) + (accumulate + (lambda (x y) (+ x y)) + 0 + term + a + next + b)) + +(define (fact n) + (product + (lambda (x) x) + 1 + (lambda (x) (+ x 1)) + n)) + diff --git a/1_33.sch b/1_33.sch new file mode 100644 index 0000000..77c1304 --- /dev/null +++ b/1_33.sch @@ -0,0 +1,38 @@ +(load "1_28.sch") ; for prime? + +(define (filtered-accumulate combiner null-value pred term a next b) + (if (> a b) + null-value + (combiner + (if (pred a) (term a) null-value) + (filtered-accumulate combiner null-value pred term (next a) next b)))) + +(define (square x) (* x x)) + +(define (gcd a b) + (if (= b 0) + a + (gcd b (remainder a b)))) + +(define (rel-prime a b) + (= (gcd a b) 1)) + +(define (sum-squares-primes a b) + (filtered-accumulate + (lambda (x y) (+ x y)) + 0 + prime? + square + a + (lambda (x) (+ 1 x)) + b)) + +(define (prod-rel-prime n) + (filtered-accumulate + (lambda (x y) (* x y)) + 1 + (lambda (x) (rel-prime x n)) + (lambda (x) x) + 1 + (lambda (x) (+ 1 x)) + n)) diff --git a/1_35.sch b/1_35.sch new file mode 100644 index 0000000..73cd34b --- /dev/null +++ b/1_35.sch @@ -0,0 +1,15 @@ +(define tolerance 0.00001) + +(define (fixed-point f first-guess) + (define (close-enough? v1 v2) + (< (abs (- v1 v2)) tolerance)) + (define (try guess) + (let ((next (f guess))) + (if (close-enough? guess next) + next + (try next)))) + (try first-guess)) + +(define (f x) + (+ 1 (/ 1 x))) + diff --git a/1_36.sch b/1_36.sch new file mode 100644 index 0000000..78c54bb --- /dev/null +++ b/1_36.sch @@ -0,0 +1,23 @@ +(define tolerance 0.00001) + +(define (fixed-point f first-guess) + (define (close-enough? v1 v2) + (< (abs (- v1 v2)) tolerance)) + (define (try guess) + (let ((next (f guess))) + (display next) + (newline) + (if (close-enough? guess next) + next + (try next)))) + (try first-guess)) + +(define (f x) + (/ (log 1000) (log x))) + +(define (average x y) + (/ (+ x y) 2)) + +; Using average damping, converges about 4 times quicker +(define (f2 x) + (average x (f x))) diff --git a/1_37.sch b/1_37.sch new file mode 100644 index 0000000..fcea205 --- /dev/null +++ b/1_37.sch @@ -0,0 +1,21 @@ +(define (cont-frac-rec n d k) + (define (rec i) + (if (= i k) + (/ (n i) (d i)) + (/ (n i) + (+ (d i) (rec (+ i 1)))))) + (rec 1)) + +(define (cont-frac-iter n d k) + (define (iter i res) + (if (= i 0) + res + (iter (- i 1) + (/ (n i) (+ res (d i)))))) + (iter k 0)) + + +(define phi (/ (+ 1 (sqrt 5)) 2)) + +; 10 iterations needed to approximate phi using +; (lambda (i) 1.0) for n and d. diff --git a/1_38.sch b/1_38.sch new file mode 100644 index 0000000..f7769d5 --- /dev/null +++ b/1_38.sch @@ -0,0 +1,11 @@ +(load "1_37.sch") ; for cont-frac-rec and cont-frac-iter + +(define (n i) 1.0) + +(define (d i) + (if (= (remainder i 3) 2) + (* (+ (quotient i 3) 1) 2) + 1)) + +(define e + (+ 2 (cont-frac-rec n d 20))) diff --git a/1_39.sch b/1_39.sch new file mode 100644 index 0000000..8288456 --- /dev/null +++ b/1_39.sch @@ -0,0 +1,10 @@ +(load "1_37.sch") ; for cont-fram-rec + +(define (d i) (+ (* (- i 1) 2) 1)) + +(define (tan-cf x) + (define (n i) + (if (= i 1) + (* 1.0 x) + (* -1.0 (* x x)))) + (cont-frac-rec n d 50)) diff --git a/1_40.sch b/1_40.sch new file mode 100644 index 0000000..e69de29 diff --git a/1_8.sch b/1_8.sch new file mode 100644 index 0000000..2bc131e --- /dev/null +++ b/1_8.sch @@ -0,0 +1,16 @@ +(define (cbrt x) + (cbrt-iter 1.0 x)) + +(define (cbrt-iter guess x) + (if (good-enough? guess x) + guess + (cbrt-iter (improve guess x) x))) + +(define (improve guess x) + (/ + (+ (/ x (* guess guess)) (* 2 guess)) + 3)) + +(define (good-enough? guess x) + (< (abs (- (* guess guess guess) x)) 0.001)) + diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..1e73e86 --- /dev/null +++ b/notes.txt @@ -0,0 +1,86 @@ +1.9: + +(define (+ a b) + (if (= a 0) b (inc (+ (dec a) b)))) + +(+ 4 5) +(if (= 4 0) 4 (inc (+ (dec 4) 5))) +(inc (+ 3 5)) +(inc (inc (+ 2 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 + +Recursive + + +(define (+ a b) + (if (= a 0) b (+ (dec a) (inc b)))) + +(+ 4 5) +(+ 3 6) +(+ 2 7) +(+ 1 8) +(+ 0 9) +9 + +Iterative + + +1.10: + +(define (A x y) + (cond ((= y 0) 0) + ((= x 0) (+ 2 y)) + ((= y 1) 2) + (else (A (- x 1) + (A x (- y 1)))))) + +(A 1 10) +(A 0 (A 1 9)) +(A 0 (A 0 (A 1 8))) +(A 0 (A 0 (A 0 (A 1 7)))) +(A 0 (A 0 (A 0 (A 0 (A 1 6))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 1 5)))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 4))))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 3))))))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 2)))))))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 1))))))))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 2)))))))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 4)))))))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 6))))))))) +(A 0 (A 0 (A 0 (A 0 (A 0 (A 0 8))))))) +(A 0 (A 0 (A 0 (A 0 (A 0 10)))))) +(A 0 (A 0 (A 0 (A 0 12))))) +(A 0 (A 0 (A 0 14)))) +(A 0 (A 0 16))) +(A 0 18) +22 + +(A 2 4) = 16 +(A 3 3) = 16 + + +1.34 + +(define (f g) (g 2)) + +(f f) gives error Error: call of non-procedure: 2. This is because it is expecting the +second argument to be a procedure (implicitly from the fact that it applies it to 2). + + +1.35 + +Golden ratio: phi = (1 + sqrt(5))/2 + +Let x' be a fixed point of x |-> 1 + 1/x. Then + +x' = 1 + 1/x' = (x' + 1)/x' +x'^2 = x' + 1 +x'^2 - x' - 1 = 0 + +Solutions: (1 +- sqrt(1 + 4)) / 2. So phi is one of the fixed points.