CS2322

Laboratory Problem 1

Functions and their arguments

In this problem we explore the task of defining several functions which are designed to work together with one another. We also explore the evaluation of arguments to a function.

Consider the following functions to do square roots:

;____________________________________
;A function to square its argument
(define (square x)
  (* x x))

;____________________________________
;Here is the mathematical definition
(define (sqrt x)
  (the y (and (>= y 0)
              (= (square y) x))))

;____________________________________
;A helping function.  This function
; appears to be recursive, but,
; as its name implys, it is really
; iterative.
(define (sqrt-iter guess x)
  (if (good-enough? guess x)
      guess
      (sqrt-iter (improve guess x) x)))

;____________________________________
;Here is the function improve
(define (improve guess x)
  (average guess (/ x guess)))

;____________________________________
;Here is the function average
(define (average x y)
  (/ (+ x y) 2))

;____________________________________
;Here is the function good-enough?
; which is a predicate (note the ?)
(define (good-enough? guess x)
  (< (abs (- (square guess) x)) .001))

;____________________________________
;Finally, define sqrt by using
; sqrt-iter with a guess of 1
(define (sqrt x)
  (sqrt-iter 1 x))

Try this "mathematical" definition of the sqrt function using scm. What happens? Why?

Next, consider the question of the accuracy of the results which sqrt gives. Demonstrate how you can improve the accuracy of the sqrt function.

The good-enough? test used in computing square roots will not be very effective for finding the square roots of very small numbers. Also, on real computers, arithmetic operations are often performed imprecisely or with limited precision. This makes our test inadequate for very large numbers. Explain these statements, with examples showing how the test fails for small and large arguments.

An alternative strategy for implementing good-enough? is to watch how guess changes from one iteration to the next and to stop when the change is a very small fraction of the guess. Design a square root procedure which uses this kind of end test. Does this work better for small and large arguments?

Alyssa P. Hacker doesn't see why if needs to be provided as a special word. "Why can't I just define it as an ordinary procedure in terms of cond?" she asks. Alyssa's friend Eva Lu Ator claims this can indeed be done, and she defines a new version of if:

;____________________________________
;A new definition for the form "if"
(define (new-if
         predicate
         then-clause
         else-clause)
  (cond (predicate then-clause)
        (else else-clause)))

Eva demonstrates the program for Alyssa:

>>> (new-if (= 2 3) 0 5)
5
>>> (new-if (= 1 1) 0 5)
0

Delighted, Alyssa uses new-if to rewrite the square root program:

;____________________________________
;Now, redefine sqrt-iter using new-if
(define (sqrt-iter guess x)
  (new-if (good-enough? guess x)
      guess
      (sqrt-iter (improve guess x) x)))

What happens when Alyssa attempts to use this to compute square roots? Explain your answer.

Lab1 Scheme Code