読書会

今年最初の、でした。
残の問題 1.40 から 1.46 まで鮮かなお手並みを拝見させて頂く。問題 1.40 とか 1.44 から 1.46 までは全然スルーだったんですが、頭の回転も出てきた解も誠にアザヤか。おそらくは sw@mac にてエントリが入るはず。
で、そのまま 2 章に突入。最初の 2.1 でも鮮かなアタマの回転を見せてくれたんですが、帰宅中に自分てきな解を検討してみた。

問題2.1

アタマの回転の良さについてけてなかったんですが、よく考えてみたら分母は常に正になるはずで、分母が負で分子が正の場合のみ分子の符号を反転すれば良いだけな事に帰宅中に気づく。成程ね、と言いつつ試験から書く。
最初はこんなカンジで。

(use gauche.test)

(add-load-path ".")
(load "2.1")

(test-start "rational")
(test-section "make-rat")
(test-section "add-rat")
(test-section "sub-rat")
(test-section "mul-rat")
(test-section "div-rat")
(test-section "equal-rat")
(test-end)

順次追加。まず、make-rat な試験。てか、面倒なので問題 2.1 の実装も含め、ってコトで以下。しかも試験自体がパクり気味だったりして (を
make-rat の試験が以下。

(test-section "make-rat")
(test* "3/3"
       '(1 . 1)
       (make-rat 3 3))

(test* "-3/3"
       '(-1 . 1)
       (make-rat -3 3))

(test* "3/-3"
       '(-1 . 1)
       (make-rat 3 -3))

(test* "-3/-3"
       '(-1 . 1)
       (make-rat -3 -3))

で、実装が以下。

(define (gcd a b)
  (if (= b 0)
      a
      (gcd b (remainder a b))))

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

実は以前の自分の実装を見ようとしたんですが、検索できず。キーワードが悪かったのかどうかは知りませんが、上記のアイデアは sw@mac の中のヒトとナニしないと気がつかんかっただろうな。
で、以下な add-rat をでっち上げて

(define (add-rat x y)
  (make-rat (+ (* (numer x) (denom y))
	       (* (numer y) (denom x)))
	    (* (denom x) (denom y))))

以下な試験を書いたんですがパスしない。

(test-section "add-rat")
(test* "(+ 1/2 1/3)"
       '(5 . 6)
       (add-rat (make-rat 1 2) (make-rat 1 3)))

(test* "(+ -1/2 1/3)"
       '(-1 . 6)
       (add-rat (make-rat -1 2) (make-rat 1 3)))

下の試験、(1 . -6) が戻ってくるとの事。これは make-rat が微妙なのか。そういえば abs が云々で gcd 手続きに実装してたな、と。
make-rat を以下に修正。

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

いいのかなぁ。とりあえずへろへろなので続きは別途現実トウヒな予定。