SICP 問題2.1

2017/09/04

正と負の両方の引数を扱うことができる改良版 make-rat を定義せよ。
make-rat は符号を正規化し、正の有理数であれば分子と分母の両方が正となり、負の有理数であれば分子のみが負になるようにする。

改良前の make-rat はこちら。

(define (make-rat n d)
  (let ((g (gcd n d)))
  (cons (/ n g) (/ d g))))

nd 両方負の数だったら正の数、どちらか片方が負の数だったら負の数にするのだと思う。とりあえず愚直に書いてみる。

(define (make-rat n d)
  (let ((g (gcd n d)))
    (cond
      ((and (> n 0) (> d 0)) (cons (/ n g) (/ d g)))
      ((and (< n 0) (< d 0)) (cons (/ n g) (/ d g)))
      ((and (> n 0) (< d 0)) (cons (- (/ n g)) (- (/ d g))))
      ((and (< n 0) (> d 0)) (cons (- (/ n g)) (- (/ d g)))))))

[両方正or負]のグループと[片方正で片方負]のグループで返すものがそれぞれ一緒なので、まとめる。

(define (make-rat n d)
  (let ((g (gcd n d)))
    (cond
      ((or (and (> n 0) (< d 0)) (and (< n 0) (> d 0)))
        (cons (- (/ n g)) (- (/ d g))))
      (else
        (cons (/ n g) (/ d g))))))

合ってるのかな・・・

答え

(define (make-rat n d)
  (let ((g (abs (gcd n d))))
     (if (< d 0)
         (cons (/ (- n) g) (/ (- d) g))
         (cons (/ n g) (/ d g)))))

なるほど、確かに・・・