2012-02-04

SICP Exercise 2.80: Generic Zero Testing

Define a generic predicate =zero? that tests if its argument is zero, and install it in the generic arithmetic package. This operation should work for ordinary numbers, rational numbers, and complex numbers.

Well, we've just written equ?, so we could get away with simply adding procedures to each package that test for equality using the type-specific equ? procedure, setting one of the values to the type's equivalent of zero. I.e. 0 for scheme-number, (make-rat 0 1) for rational and either (make-complex-from-real-imag 0 0) or (make-complex-from-mag-ang 0 0) for complex.

However, for rational and complex numbers we can have a slightly simpler test. Note that any rational number that is equal to zero will have a numerator of 0. Similarly, any complex number that is equal to zero will have a magnitude of 0. Using this approach we don't need to test the denominator for rational numbers, or the angle (or rectangular form components) for complex numbers.

Here's the generic operation and the modifications I made to the packages:
(define (=zero? x) (apply-generic '=zero? x))

(define (install-scheme-number-package)
  …
  (put '=zero? '(scheme-number)
       (lambda (x) (= 0 x)))
  …
  'done)

(define (install-rational-package)
  ;; internal procedures
  …
  (define (=zero? x) (= (numer x) 0))
  …
  ;; interface to rest of the system
  …
  (put '=zero? '(rational) =zero?)
  …
  'done)

(define (install-complex-package)
  ;; imported procedures from rectangular and polar packages
  …
  ;; internal procedures
  …
  (define (=zero? x) (= (complex-magnitude x) 0))
  …
  ;; interface to rest of the system
  …
  (put '=zero? '(complex) =zero?)
  …
  'done)
Similar to the last exercise, if you're wondering about complex-magnitude then have a read of my solution to exercise 2.77.

Let's give it a spin:
> (=zero? (make-scheme-number 4))
#f
> (=zero? (sub (make-scheme-number 3) (make-scheme-number 3)))
#t
> (=zero? (sub (make-rational 1 2) (make-rational 3 2)))
#f
> (=zero? (add (make-rational 1 2) (make-rational -2 4)))
#t
> (=zero? (make-complex-from-real-imag 0 0))
#t
> (=zero? (make-complex-from-mag-ang 0 42))
#t

No comments:

Post a Comment