#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