#lang racket
;; 1.1
10
;; 10
(+ 5 3 4)
;; 12
(- 9 1)
;; 8
(/ 6 2)
;; 3
(+ (* 2 4) (- 4 6))
;; 6
(define a 3)
(define b (+ a 1))
(+ a b (* a b))
;; 19
(= a b)
;; #f
(if (and (> b a) (< b (* a b)))
b
a)
;; 4
(cond ((= a 4) 6)
((= b 4) (+ 6 7 a))
(else 25))
;; 16
(+ 2 (if (> b a) b a))
;; 6
(* (cond ((> a b) a)
((< a b) b)
(else -1))
(+ a 1))
;; 16
;; 1.2
(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 1 5)))))
(* 3 (- 6 2) (- 2 7)))
;; 1.3
(define (sum-of-squares-of-biggest-two-of-three x y z)
(cond [(and (>= x z) (>= y z)) (+ (* x x) (* y y))]
[(and (>= x y) (>= z y)) (+ (* x x) (* z z))]
[else (+ (* y y) (* z z))]))
(sum-of-squares-of-biggest-two-of-three 3 4 2)
;; 25
(sum-of-squares-of-biggest-two-of-three 3 2 4)
;; 25
(sum-of-squares-of-biggest-two-of-three 2 3 4)
;; 25
;; 1.4
;; If b > 0, add b to a. If b <= 0, subtract b from a.
(define (a-plus-abs-b a b)
((if (> b 0) + -) a b))
;; 1.5
;; Procedure p produces an infinite loop. If the interpreter is using
;; applicative-order evaluation, the argument (p) to the function call will always
;; be evaluated, producing an infinite loop. If the interpreter is using
;; normal-order evaluation, then the arguments will only be evaluated as needed by
;; the if form, and since the predicate is true, the (p) in the alternate clause
;; will never get evaluated, avoiding the infinite loop.
;; The Racket repl is using applicative-order evaluation.
(define (p) (p))
(define (test x y)
(if (= x 0)
0
y))
;; (test 0 (p))
;; user break
;; 1.6
;; Using the new-if procedure instead of the if special form will produce an
;; infinte loop because the new-if procedure always evaluates the else-clause,
;; which calls sqrt-iter again.
(define (new-if predicate then-clause else-clause)
(cond [predicate then-clause]
[else else-clause]))
(define (average x y)
(/ (+ x y) 2))
(define (improve guess x)
(average guess (/ x guess)))
(define (good-enough? guess x)
(< (abs (- (sqr guess) x)) 0.001))
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
(define (my-sqrt x)
(sqrt-iter 1.0 x))
(define (sqrt-iter-new-if guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter-new-if (improve guess x)
x)))
(define (my-sqrt-new-if x)
(sqrt-iter-new-if 1.0 x))
(sqrt 2) ; using the racket built-in
;; 1.4142135623730951
(my-sqrt 2)
;; 1.4142156862745097
;; (my-sqrt-new-if 2)
;; user break
;; 1.7
;; For large numbers my-sqrt can be very inefficient.
(time (sqrt 1e13))
;; cpu time: 0 real time: 0 gc time: 0
;; 3162277.6601683795
;; (time (my-sqrt 1e13))
;; user break
;; For small numbers the margin of error obscures the answer.
(sqrt 0.000004)
;; 0.002
(my-sqrt 0.000004)
;; 0.03129261341049664 ; this is basically the sqrt of the margin of error
(sqrt 0.001)
;; 0.03162277660168379
(define (new-good-enough? new-guess old-guess)
(< (abs (/ (- new-guess old-guess)
old-guess))
0.001))
(define (new-sqrt-iter old-guess x)
(let ([new-guess (improve old-guess x)])
(if (new-good-enough? new-guess old-guess)
new-guess
(new-sqrt-iter new-guess x))))
(define (new-my-sqrt x)
(new-sqrt-iter 1.0 x))
;; For large numbers new-my-sqrt is more efficient but less accurate.
(time (new-my-sqrt 1e13))
;; cpu time: 0 real time: 0 gc time: 0
;; 3162277.6640104805
;; For small numbers the margin of error no longer hides the answer.
(new-my-sqrt 0.000004)
;; 0.0020000003065983023
;; 1.8
(define (cbrt-improve guess x)
(/ (+ (/ x (sqr guess)) (* 2 guess)) 3))
(define (cbrt-iter old-guess x)
(let ([new-guess (cbrt-improve old-guess x)])
(if (new-good-enough? new-guess old-guess)
new-guess
(cbrt-iter new-guess x))))
(define (my-cbrt x)
(cbrt-iter 1.0 x))
(my-cbrt 8)
;; 2.000000000012062
(my-cbrt 27)
;; 3.0000005410641766
(my-cbrt 1e24)
;; 100000000.00081353
Comments