Finish exercises for chapter 1 section 1 and 2

This commit is contained in:
2020-10-15 20:38:28 -04:00
parent f0bacd1582
commit 604cf09ccd
5 changed files with 567 additions and 8 deletions

View File

@@ -18,12 +18,12 @@
; (else -1))
; (+ a 1)) ->
(display "ex-1.2 - ")
(display "\nex-1.2 - ")
(display (/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5)))))
(* 3 (- 6 2) (- 2 7))))
(newline)
(display "ex-1.3 - ")
(display "\nex-1.3 - ")
(define (sum-squares a b) (+ (* a a) (* b b)))
@@ -35,11 +35,11 @@
(display (sum-squares-max 2 -6 1))
(newline)
(display "ex-1.4 - Operator becomes + or - depending on the value of b\n")
(display "\nex-1.4 - Operator becomes + or - depending on the value of b\n")
; (define (a-plus-abs-b a b)
; ((if (> b 0) + -) a b))
(display "ex-1.5 - Only normal-order terminates\n")
(display "\nex-1.5 - Only normal-order terminates\n")
;(define (p) (p))
;(define (test x y)
; (if (= x 0) 0 y))
@@ -47,7 +47,7 @@
; Will not terminate:
;(display (test 0 (p)))
(display "\n; Square roots via Newton's Method") (newline)
(display "\nexample - Square roots via Newton's Method") (newline)
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
@@ -131,3 +131,107 @@
(display (cbrt 27)) (newline)
(display (cbrt 0.001)) (newline)
(newline) (display "ex-1.9 - see comments in code\n")
;(define (+ a b)
; (if (= a 0)
; b
; (inc (+ (dec a) b))))
; + 3 2
; (inc (+ 2 2))
; (inc (inc (+ 1 2)))
; (inc (inc (inc (+ 0 2)))
; (inc (inc (inc 2)))
; -> recursive process
;(define (+ a b)
; (if (= a 0)
; b
; (+ (dec a) (inc b))))
; (+ 3 2)
; (+ 2 3)
; (+ 1 4)
; (+ 0 5)
; 5
; -> iterative process
(display "\nex-1.10 - Ackermann") (newline)
(define (A x y)
(cond ((= y 0) 0)
((= x 0) (* 2 y))
((= y 1) 2)
(else (A (- x 1)
(A x (- y 1))))))
(display (A 1 10)) (newline)
; (A 1 10)
; (A 0 (A 1 9))
; (* 2 (A 1 9))
; (* 2 (A 0 (A 1 8))
; (* 2 (* 2 (A 1 8))
; -> 2^10 = 1024
(display (A 2 4)) (newline)
; (A 2 4)
; (A 1 (A 2 3))
; (2 ^ (A 2 3))
; (2 ^ (A 1 (A 2 2))
; (2 ^ 2 ^ (A 2 2)
; -> 2^2^2^2 = 65536
(display (A 3 3)) (newline)
; (A 3 3)
; (A 2 (A 3 2))
; (2 ^* (A 3 2))
; (2 ^* (A 2 (A 3 1)))
; (2 ^* 2 ^* 2)
; (2 ^* (2^2))
; (2^2^2^2) = 65536
(define (f n) (A 0 n)) ; f(n)=2*n
(display (f 111)) (newline)
(define (g n) (A 1 n)) ; g(n)=2^n
(display (g 12)) (newline)
(define (h n) (A 2 n)) ; h(n)=2^2^2^... or 2^(h(n-1))
(display (h 4)) (newline)
(newline) (display "example - Couting Change") (newline)
(define (dec x) (- x 1))
(define (counting-change-iter amount current-coin)
(cond ((= amount 0) 1)
((= current-coin 0) 0)
((< amount 0) 0)
(else (+ (counting-change-iter (- amount (list-of-coins current-coin)) current-coin)
(counting-change-iter amount (dec current-coin)))
)))
(define (list-of-coins coin-index)
(cond ((= coin-index 1) 1)
((= coin-index 2) 5)
((= coin-index 3) 10)
((= coin-index 4) 25)
((= coin-index 5) 50)))
(define (count-change amount) (counting-change-iter amount 5))
(display "(count-change 100) = ")
(display (count-change 100)) (newline)
; Try to implement a better version. Worked in Python. See Euler.
;(define (counting-change-iter amount count-coin current-coin)
; (cond ((= current-coin 0) 0)
; ((<= amount 0) 0)
; (else (+ (counting-change-iter (- amount (list-of-coins current-coin)) (+ count-coin 1) current-coin)
; (if (and (= count-coin 0)(= (modulo amount (list-of-coins current-coin)) 0)) 1 0)
; (counting-change-iter amount 0 (- current-coin 1))
; ))))
;(display "(count-change 100) = ")
;(display (counting-change-iter 100 0 5)) (newline)

186
ex-1_11-20.scm Normal file
View File

@@ -0,0 +1,186 @@
(display "ex-1.11\n")
(define (f_rec n)
(cond ((< n 3) n)
(else (+ (f_rec (- n 1)) (* 2 (f_rec (- n 2))) (* 3 (f_rec (- n 3)))))))
(display "(f_rec 10) = ")
(display (f_rec 10)) (newline)
(define (f_iter_step n a b c count)
(cond ((= n count) c)
(else (f_iter_step n b c (+ (* 3 a) (* 2 b) c) (+ count 1)))))
(define (f_iter n)
(cond ((< n 3) n)
(else (f_iter_step n 0 1 2 2))))
(display "(f_iter 10) = ")
(display (f_iter 10)) (newline)
(newline) (display "ex-1.12") (newline)
(define (pascal row col)
(cond ((= row 1) 1)
((= col 1) 1)
((= col row) 1)
(else (+ (pascal (- row 1) (- col 1)) (pascal (- row 1) col)))))
(display "(pascal 6 2) = ")
(display (pascal 6 3)) (newline)
(newline) (display "ex-1.13") (newline)
(display "I was not able to prove this.\n")
(newline) (display "ex-1.14") (newline)
(display "I did that on paper. See page 92 Bullet Journal 2018.")
(newline)
(newline) (display "ex-1.15") (newline)
(define (cube x) (* x x x))
(define (p x) (- (* 3 x) (* 4 (cube x))))
(define (sine angle)
(if (not (> (abs angle) 0.1))
angle
(p (sine (/ angle 3.0)))))
; a) (/ 12.5 3) -> 4.16 -> 1.38888 -> 0.462 -> 0.154 -> 0.051 (count = 5)
; 12.5 / 3^n < 0.1 <=> 125 < 3^n <=> 4.39 < n
(define (count-sine-calls value count)
(if (> (abs value) 0.1) (count-sine-calls (/ value 3.0) (+ 1 count)) count))
(display "a) Calls for 12.5 = ") (display (count-sine-calls 12.5 0)) (newline)
(display (sine (* 3.14 0.5))) (newline)
; b. What is the order of growth in space and number of steps
; (as a function of a) used by the process generated by the sine procedure when (sine a) is evaluated?
; O(log_3 a)
(newline) (display "ex-1.16") (newline)
(define (expt-rec x n)
(cond ((= n 0) 1)
(else (* x (expt-rec x (- n 1))))))
(define (expt-iter b counter product)
(cond ((= counter 0) product)
(else (expt-iter b (- counter 1) (* product b)))))
(define (expt b n) (expt-iter b n 1))
(define (fast-expt b n)
(cond ((= n 0) 1)
((even? n) (square (fast-expt b (/ n 2))))
(else (* b (fast-expt b (- n 1))))))
(define (even? n)
(= (remainder n 2) 0))
(define (expt-fast b n)
(expt-iter-fast b n 1))
(define (expt-iter-fast b n a)
(cond ((= n 1) (* b a))
((even? n) (expt-iter-fast (* b b) (/ n 2) a))
(else (expt-iter-fast b (- n 1) (* a b)))))
(display "expt-fast 2 37 = ")
(display (expt-fast 2 37))
(newline)
(newline) (display "ex-1.17") (newline)
(define (mul a b)
(if (= b 0)
0
(+ a (mul a (- b 1)))))
(define (double x) (+ x x))
(define (half x) (/ x 2))
(define (mul-rec a b)
(cond ((= b 0) 0)
((even? b) (double (mul-rec a (half b))))
(else (+ a (mul-rec a (- b 1))))))
(display "mul-rec 17 53 = ")
(display (mul-rec 17 53)) (newline)
(newline) (display "ex-1.18") (newline)
(define (mul-fast-iter b n a)
(cond ((= n 0) a)
((even? n) (mul-fast-iter (double b) (half n) a))
(else (mul-fast-iter b (- n 1) (+ a b)))))
(define (mul-fast a b) (mul-fast-iter a b 0))
(display "mul-fast 17 53 = ")
(display (mul-fast 17 53))
(newline)
(newline) (display "ex-1.19") (newline)
(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
(+ (* q q) (* p p)) ; compute p'
(+ (* q q) (* 2 p q)) ; compute q'
(/ count 2)))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1)))))
(display "fib 19 = ")
(display (fib 19))
(newline)
(newline) (display "ex-1.20") (newline)
(define (gcd-naiv a b)
(cond ((= a b) a)
((> a b) (gcd-naiv (- a b) b))
(else (gcd-naiv a (- b a)))))
(display "gcd-naiv 60 14 = ")
(display (gcd-naiv 60 14))
(newline)
(define (gcd a b)
(if (= b 0)
a
(gcd b (remainder a b))))
(display "gcd 60 14 = ")
(display (gcd 60 14))
(newline)
; normaler order
; gcd 206 40
; gcd 40 (r 206 40)
; zero? (r 206 40)
; zero? 6
; gcd (r 206 40) (r 40 (r 206 40))
; zero? (r 40 (r 206 40))
; gcd (r 40 (r 206 40)) (r (r 206 40) (r 40 (r 206 40))))
; etc.
; applicative order
; gcd 206 40
; gcd 40 (r 206 40)
; gcd 40 6
; gcd 6 (r 40 6)
; gcd 6 4
; gcd 4 (r 6 4)
; gcd 4 2
; gcd 2 (r 4 2)
; gcd 2 0 -> 2

264
ex-1_21-28.scm Normal file
View File

@@ -0,0 +1,264 @@
(display "ex-1.21") (newline)
(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)))
(display "(smallest-divisor 33) = ")
(display (smallest-divisor 33))
(newline)
(display "(prime? 37) = ")
(display (prime? 37))
(newline)
;a^n = a (mod n) ; fermat's theorem
(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))))
(display "(expmod 11 23 3) = ")
(display (expmod 11 23 3))
(newline)
(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) #t)
((fermat-test n) (fast-prime? n (- times 1)))
(else #f)))
(display "(fast-prime? 11) = ")
(display (fast-prime? 11 1))
(display "\n\nex-1.22\n")
(display "(smallest-divisor 199) = ")
(display (smallest-divisor 199)) (newline)
(display "(smallest-divisor 1999) = ")
(display (smallest-divisor 1999)) (newline)
(display "(smallest-divisor 19999) = ")
(display (smallest-divisor 19999)) (newline)
(newline) (display "ex-1.23 - more tests in comments")
(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)
)
(define (search-for-primes n a)
(cond ((= a 3) 0)
((prime? n) (timed-prime-test n) (search-for-primes (+ n 1) (+ a 1)))
((search-for-primes (+ n 1) a))))
(newline) (display "search-for-primes 1000")
(search-for-primes 1000 0)
;(newline)(newline) (display "search-for-primes 100000000")
;(search-for-primes 100000000 0)
;
;(newline)(newline) (display "search-for-primes 1000000000")
;(search-for-primes 1000000000 0)
;
;(newline)(newline) (display "search-for-primes 10000000000")
;(search-for-primes 10000000000 0)
;
;(newline)(newline) (display "search-for-primes 100000000000")
;(search-for-primes 100000000000 0)
; It is amazing how exact the time represents the expected increase. If we
; increase n by factor 10 the time increase by factor sqrt(10) = 3.3. I knew
; this, but it is cool to see it.
; search-for-primes 1000000000
; 1000000007 *** 4.0000000000000036e-2
; 1000000009 *** .04999999999999999
; 1000000021 *** 5.0000000000000044e-2
;
; search-for-primes 10000000000
; 10000000019 *** .15000000000000002
; 10000000033 *** .1399999999999999
; 10000000061 *** .1399999999999999
;
; search-for-primes 100000000000
; 100000000003 *** .4500000000000002
; 100000000019 *** .43999999999999995
; 100000000057 *** .4299999999999997
(display "ex-1.23") (newline)
(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)))))
;(timed-prime-test 100000000003)
;(timed-prime-test 100000000019)
;(timed-prime-test 100000000057)
; I did not really expect the time to half, but to 2/3. That is because we skip
; one number per every three numbers. For example, instead of 3,4,5 we do 3,5
; 100000000003 *** .30000000000000004
; 100000000019 *** .29
; 100000000057 *** .28
(newline) (display "ex-1.24")
(define (prime? n) (fast-prime? n 100))
(define (start-prime-test n start-time)
(if (prime? n)
(report-prime (- (runtime) start-time))))
(newline)(newline) (display "search-for-primes 1000000000000")
(search-for-primes 1000000000000 0)
(newline)(newline) (display "search-for-primes 1000000000000000000000")
(search-for-primes 1000000000000000000000000 0)
; This very nicely shows that in order to double the execution time we have to
; square the input. For example:
;search-for-primes 1000000000000
; 1.9999999999999962e-2 / 9.999999999999981e-3 = 2
; I feel like all discrepancies must be explained by the random function. If
; the factor is bigger it takes more steps.
;1000000000039 *** 9.999999999999981e-3
;1000000000061 *** 9.999999999999981e-3
;1000000000063 *** 9.999999999999981e-3
;search-for-primes 1000000000000000000000
;1000000000000000000000007 *** 1.9999999999999962e-2
;1000000000000000000000049 *** .02999999999999997
;1000000000000000000000121 *** 3.0000000000000027e-2
(newline)(newline) (display "ex-1.25") (newline)
;(define (square m)
; (display "square ")(display m)(newline)
; (* m m))
(define (expmod-naiv base exp m)
(remainder (fast-expt base exp) m))
; Terminates quickly.
(display "(expmod 10000000000 1000000 100) ; runs quickly") (newline)
(expmod 10000000000 1000000 100)
; Scheme can handle arbitrary precision arithmetic. However,
; when the numbers get really big that takes more time. When
; using expmod the number to be squared stays lower than the
; prime to be tested.
; When we do the naiv approach the numbers become really big
; and the same call will not terminate.
(display "(expmod-naiv 10000000000 1000000 100) ; doesn't terminate")
;(expmod-naiv 10000000000 1000000 100)
(newline)(newline) (display "ex-1.26 - see comment") (newline)
; With that function for every of the log(n) steps the
; function is called twice which means the complexity
; grows exponantially which gives us log(n)^2 a O(n) process.
(newline) (display "ex-1.27") (newline)
; Do fermat tests for all a in [2, p - 1].
(define (fermat-test-all n) (fermat-test-all-iter 2 n))
(define (fermat-test-all-iter x n)
(cond ((= x n) #t)
((= (expmod x n n) x) (fermat-test-all-iter (+ x 1) n))
(else (display x)(newline) #f)))
; 561, 1105, 1729, 2465, 2821, and 6601
(display (fermat-test-all 561)) (newline)
(display (fermat-test-all 1105)) (newline)
(display (fermat-test-all 1729)) (newline)
(display (fermat-test-all 2465)) (newline)
(display (fermat-test-all 2821)) (newline)
(display (fermat-test-all 6601)) (newline)
; I am really unhappy with that exercise, because it wouldn't
; worked if we used the condition a ** (p - 1) = 1 (mod p) and
; I don't know the exact reason for that.
(newline) (display "ex-1.28") (newline)
; Exercise 1.28. One variant of the Fermat test that cannot be fooled is called
; the Miller-Rabin test (Miller 1976; Rabin 1980). This starts from an alternate
; form of Fermat's Little Theorem, which states that if n is a prime number and
; a is any positive integer less than n, then a raised to the (n - 1)st power is
; congruent to 1 modulo n. To test the primality of a number n by the
; Miller-Rabin test, we pick a random number a<n and raise a to the (n - 1)st
; power modulo n using the expmod procedure. However, whenever we perform the
; squaring step in expmod, we check to see if we have discovered a ``nontrivial
; square root of 1 modulo n,'' that is, a number not equal to 1 or n - 1 whose
; square is equal to 1 modulo n. It is possible to prove that if such a
; nontrivial square root of 1 exists, then n is not prime. It is also possible
; to prove that if n is an odd number that is not prime, then, for at least half
; the numbers a<n, computing an-1 in this way will reveal a nontrivial square
; root of 1 modulo n. (This is why the Miller-Rabin test cannot be fooled.)
; Modify the expmod procedure to signal if it discovers a nontrivial square root
; of 1, and use this to implement the Miller-Rabin test with a procedure
; analogous to fermat-test. Check your procedure by testing various known primes
; and non-primes. Hint: One convenient way to make expmod signal is to have it
; return 0.
(define (is-nontrivial-square n m)
(cond ((= n 1) n)
((= n (- m 1)) n)
((= (remainder (square n) m) 1) 0) ; non-trivial square root
(else n)))
(define (expmod-mr base exp m)
(cond ((= exp 0) 1)
((even? exp)
(remainder (square (is-nontrivial-square (expmod-mr base (/ exp 2) m) m))
m))
(else
(remainder (* base (expmod-mr base (- exp 1) m))
m))))
(define (miller-rabin-test n)
(define (try-it a)
(= (expmod-mr a (- n 1) n) 1))
(try-it (+ 1 (random (- n 1)))))
(define (fast-prime? n times)
(cond ((= times 0) #t)
((miller-rabin-test n) (fast-prime? n (- times 1)))
(else #f)))
(display (fast-prime? 17 10)) (newline)
(display (fast-prime? 561 10)) (newline)
(display (fast-prime? 1105 10)) (newline)
(display (fast-prime? 1729 10)) (newline)
(display (fast-prime? 231082301002031230 10)) (newline)
(display (fast-prime? 1000000000000000000000121 10)) (newline)
(display (fast-prime? 2 10)) (newline)
(display (fast-prime? 4 10)) (newline)

8
run Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
for a in "$@"
do
echo "run: $a"
mit-scheme --quiet < $a
done

3
run.sh
View File

@@ -1,3 +0,0 @@
#!/bin/sh
mit-scheme --quiet < $1