SICP 問題 2.1(マイナスを考慮した有理数生成)

さぁ、2章の「データによる抽象の構築」に突入だ!!
まだまだ仕事が忙しくて帰ってくるのは遅いが、地道に進めるぜ!!

【問題】

正負両方の引数を扱う改良版 make-rat を定義せよ。
make-rat は符号を正規化し、有理数が正なら、分子、分母とも正、有理数が負なら分子だけ負とする。

【解答】

とりあえず、この問題に至るまでに定義されていた、いくつかの手続きを記載する。

;有理数を生成する
(define (make-rat n d)
  (let ((g (gcd n d)))
    (cons (/ n g) (/ d g))))

;有理数の分子を取得する
(define (numer x)
  (car x))

;有理数の分母を取得する
(define (denom x)
  (cdr x))

;有理数を加算する
(define (add-rat x y)
  (make-rat (+ (* (numer x) (denom y))
	       (* (numer y) (denom x)))
	    (* (denom x) (denom y))))

;有理数を減算する
(define (sub-rat x y)
  (make-rat (- (* (numer x) (denom y))
	       (* (numer y) (denom x)))
	    (* (denom x) (denom y))))

;有理数を乗算する
(define (mul-rat x y)
  (make-rat (* (numer x) (numer y))
	    (* (denom x) (denom y))))

;有理数を除算する
(define (div-rat x y)
  (make-rat (* (numer x) (denom y))
	    (* (denom x) (numer y))))

;有理数を比較する
(define (equal-rat? x y)
  (= (* (numer x) (denom y))
     (* (numer y) (denom y))))

;おまけ。
(define (gcd a b)
  (if (= b 0)
      a
      (gcd b (remainder a b))))

さて、この make-rat を負数を扱えるようにせよとのお達し。
普通に実装してみよう。

(define (make-rat n d)
  (let* ((g (gcd n d))
	 (n1 (/ n g))  ;分子
	 (d1 (/ d g))) ;分母
    ;プラスマイナスの掛け合わせだった場合、
    ;gcdを評価すると必ず分母側がマイナスになる。
    ;これを利用して分母がマイナスだった場合に分子分母に-1を掛けてしまう。
    (if (< d1 0)
	(cons (* -1 (/ n g)) (* -1 (/ d g)))
	(cons (/ n g) (/ d g)))))

実行してみましょ。


gosh> (make-rat 12 -60)
(-1 . 5)
gosh> (make-rat -12 60)
(-1 . 5)
gosh> (make-rat -12 -60)
(1 . 5)
gosh> (make-rat 12 60)
(1 . 5)
gosh>
おっけ〜。