SICP 読み (92) 2.5.3 例: 記号代数

全係数を最大公約数で割る (その 2)

あ、pseudoremainder-terms 呼び出しを wrap すりゃ良いの??

 (define (gcd-terms L1 L2)
  (if (empty-termlist? L2)
      L1
      (gcd-terms L2 (div-by-gcd (pseudoremainder-terms L1 L2)))))

ってカンジ??
多分置き換えなソレを見るに上記で問題無いはず。(アマ
リストの中の gcd を得る手続きってどうすりゃ良いのか。

(define (gcd-list l)
 (if (null? (cdr l))
    (car l)
    (gcd (car l) (gcd-list (cdr l)))))

なんとなく動いている感じ。

div-by-gcd の実装は以下のような感じか。

 (define (div-by-gcd L)
  (define (get-coeff-gcd L)
    (let f ((L L) (result (coeff (car L))))
      (if (null? L)
          result
          (f (cdr L) (gcd result (coeff (car L)))))))

  (let ((n (get-coeff-gcd L)))
    (let f ((L L) (result '()))
      (if (null? L)
          result
          (let ((top (car L)))
            (f (cdr L) (cons (make-term (order top)
                                        (/ (coeff top) n))
                               result)))))))

で、試験してみたんですが動かない。ループしてる感じ。体調不良により中断。次の日になってよくよく見てみりゃ、gcd-terms ん中でやっちゃ駄目だろ、と。恥ずかしいんですが、以下のような実装になってマシタ。(とほほほ

 (define (gcd-terms L1 L2)
   (if (empty-termlist? L2)
       L1
       (div-by-gcd (gcd-terms L2 (pseudoremainder-terms L1 L2)))))

で、以下の場所な形で修正。

 (define (gcd-poly p1 p2)
   (if (same-variable? (variable p1) (variable p2))
       (make-poly (variable p1)
                  (div-by-gcd (gcd-terms (term-list p1)
                                         (term-list p2))))
       (error "Polys not in same var --- GCD-POLY"
              (list p1 p2)))
   )

無論、gcd-terms ん中では div-by-gcd は呼ばない。全部終わって戻ってきてからやんねぇと駄目だろ。

で、試験してみたんですが NG。リストが逆になっている。(駄目
修正した div-by-gcd を以下に。

 (define (div-by-gcd L)
  (define (get-coeff-gcd L)
    (let f ((L L) (result (coeff (car L))))
      (if (null? L)
          result
          (f (cdr L) (gcd result (coeff (car L)))))))

  (let ((n (get-coeff-gcd L)))
    (let f ((L L) (result '()))
      (if (null? L)
          result
          (let ((top (car L)))
            (f (cdr L) (append result
                               (list (make-term (order top)
                                                (/ (coeff top) n))))))))))

どうも cons を適当に使ってしまう悪い癖があるなぁ。
このケースだと名前付き let は使わない方がわかりやすそげではある。それだと cons 使えて視覚的にも直感的になる、というか。

この状態で以下の試験にパスしています。

 ("2-95,96"
  (setup (lambda ()
           (install-rational-package)
           (install-scheme-number-package)
           (install-polynomial-package)))
  ("not equall"
   (let ((p1 (make-polynomial 'x '((2 1) (1 -2) (0 1))))
         (p2 (make-polynomial 'x '((2 11) (0 7))))
         (p3 (make-polynomial 'x '((1 13) (0 5)))))
     (let ((q1 (mul p1 p2))
           (q2 (mul p1 p3)))
       (assert-equal q1
                     '(polynomial x (4 11) (3 -22) (2 18) (1 -14) (0 7)))
       (assert-equal q2
                     '(polynomial x (3 13) (2 -21) (1 3) (0 5)))
;       (assert-not-equal p1 (greatest-common-divisor q1 q2))))
       (assert-equal p1 (greatest-common-divisor q1 q2))))
   )

  ("pseudoremainder-terms"
   (let ((p1 (make-polynomial 'x '((2 1) (1 -2) (0 1))))
         (p2 (make-polynomial 'x '((2 11) (0 7))))
         (p3 (make-polynomial 'x '((1 13) (0 5)))))
     (let ((q1 (mul p1 p2))
           (q2 (mul p1 p3)))
;       (assert-equal '(polynomial x (2 18954) (1 -37908) (0 18954))
;                     (greatest-common-divisor q1 q2))))
       (assert-not-equal '(polynomial x (2 18954) (1 -37908) (0 18954))
                         (greatest-common-divisor q1 q2))))
   )
  )

2 章終わりまであと一問。

追記

テキスト見るとやっぱり gcd-terms に、と書いてある。しかも昨晩のエントリでも (多分忘れないように) gcd-terms に、とある。悔しいので実装してみた。以下、変更部分のみ。

 (define (gcd-poly p1 p2)
   (if (same-variable? (variable p1) (variable p2))
       (make-poly (variable p1)
                  (gcd-terms (term-list p1)
                             (term-list p2)))
       (error "Polys not in same var --- GCD-POLY"
              (list p1 p2)))
   )

gcd-poly は元に戻して

 (define (gcd-terms L1 L2)
   (define (gcd-terms-iter L1 L2)
     (if (empty-termlist? L2)
         L1
         (gcd-terms L2 (pseudoremainder-terms L1 L2))))
   (div-by-gcd (gcd-terms-iter L1 L2)))

gcd-terms の中で wrap した。よく考えりゃ簡単じゃん、みたいな??
# ってか、ループの中に wrap カマす方が駄目スギ

あるいは、div-by-gcd を修正。

 (define (div-by-gcd L)
  (define (get-coeff-gcd L)
    (let f ((L L) (result (coeff (car L))))
      (if (null? L)
          result
          (f (cdr L) (gcd result (coeff (car L)))))))
  (define (div-by-gcd-iter L n)
    (if (null? L)
        '()
        (let ((top (car L)))
          (cons (make-term (order top) (/ (coeff top) n))
                (div-by-gcd-iter (cdr L) n)))))

  (div-by-gcd-iter L (get-coeff-gcd L)))

これはこれでどうなんだろう、という感じもするなぁ。