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

問題処理 (懐

単体試験の方で確認してみると、gcd-terms で符号が逆転しているのを昨晩確認済み。
以下のような試験を書いて

  ("2.97's gcd-terms"
   (let ((L1 '((5 1) (3 -1) (2 -1) (0 1)))
         (L2 '((4 1) (3 1) (2 1) (1 -2) (0 -1))))
     (assert-equal '((1 1) (0 -1))
                   (gcd-terms L1 L2))
     (assert-equal '((1 1) (0 -1))
                   (gcd-terms L2 L1)))
   )

確認してみると

$ test/run-test.scm -vv
- (test suite) 2.5.3
-- (test case) gcd-terms: .F
 expected:<((1 1) (0 -1))>
 but was:<((1 -1) (0 1))> in 2.97's gcd-terms
F
 expected:<((1 1) (0 -1))>
 but was:<((1 -1) (0 1))> in 2.97's gcd-terms

-- (test case) first-term: .
-- (test case) max-order: .
-- (test case) int-fct is 1?: .
-- (test case) mul-term-by-all-terms: .
-- (test case) div-terms: .
-- (test case) result's GCD: .
-- (test case) result: .
-- (test case) retuce-terms: .

10 tests, 17 assertions, 15 successes, 2 failures, 0 errors
Testing time: 0.035490999999999995
$

との事。

gcd-terms を見てると

 (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)))

ってなっていたのを発見したんですが、修正しても変化ナシ。

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

再帰呼び出しで gcd-terms-iter を呼ばずに gcd-terms (外のガワ) を呼び出していた。ただ、修正して試験しても挙動は変わらず。何故にこうなるか、が全然把握できてない (ため息

置き換え勝負なリキは無いなぁ ...
とは言えやってみないとワケワカなんで頑張れ自分。

(gcd-terms '((5 1) (3 -1) (2 -1) (0 1)) '((4 1) (3 1) (2 1) (1 -2) (0 -1)))

(div-by-gcd (gcd-terms-iter '((5 1) (3 -1) (2 -1) (0 1))
			    '((4 1) (3 1) (2 1) (1 -2) (0 -1))))

(div-by-gcd (gcd-terms-iter
            '((4 1) (3 1) (2 1) (1 -2) (0 -1))
            (pseudoremainder-terms '((5 1) (3 -1) (2 -1) (0 1))
                                   '((4 1) (3 1) (2 1) (1 -2) (0 -1)))))

pseudoremainder-terms ん中

(cadr (div-terms
      (mul-term-by-all-terms
       (make-term
        0
        (expt (coeff (first-term
                      '((4 1) (3 1) (2 1) (1 -2) (0 -1))))
              (+ 1 (- (order
                       (first-term
                        '((5 1) (3 -1) (2 -1) (0 1))))
                      (order
                       (first-term
                        '((4 1) (3 1) (2 1) (1 -2) (0 -1))))))))
       '((5 1) (3 -1) (2 -1) (0 1)))
      '((4 1) (3 1) (2 1) (1 -2) (0 -1))))

(cadr (div-terms
      (mul-term-by-all-terms '(0 (expt (coeff '(4 1))
                                       (+ 1 (- (order '(5 1))
                                               (order '(4 1))))))
                             '((5 1) (3 -1) (2 -1) (0 1)))
      '((4 1) (3 1) (2 1) (1 -2) (0 -1))))

(cadr (div-terms
      (mul-term-by-all-terms '(0 1)
                             '((5 1) (3 -1) (2 -1) (0 1)))
      '((4 1) (3 1) (2 1) (1 -2) (0 -1))))

(cadr (div-terms '((5 1) (3 -1) (2 -1) (0 1))
		 '((4 1) (3 1) (2 1) (1 -2) (0 -1))))

(cadr '(((1 1) (0 -1)) ((3 -1) (2 2) (1 -1))))

'((3 -1) (2 2) (1 -1))

むむ。続きを。(cadr と car を間違えてました)

(div-by-gcd (gcd-terms-iter
            '((4 1) (3 1) (2 1) (1 -2) (0 -1))
            (pseudoremainder-terms '((5 1) (3 -1) (2 -1) (0 1))
                                   '((4 1) (3 1) (2 1) (1 -2) (0 -1)))))

(div-by-gcd (gcd-terms-iter
            '((4 1) (3 1) (2 1) (1 -2) (0 -1))
            '((3 -1) (2 2) (1 -1))))

(div-by-gcd (gcd-terms-iter
            '((3 -1) (2 2) (1 -1))
            (pseudoremainder-terms '((4 1) (3 1) (2 1) (1 -2) (0 -1))
                                   '((3 -1) (2 2) (1 -1)))))

で又 pseudoremainder-terms の中

(pseudoremainder-terms '((4 1) (3 1) (2 1) (1 -2) (0 -1))
                      '((3 -1) (2 2) (1 -1)))

(cadr (div-terms
      (mul-term-by-all-terms
       (make-term
        0
        (expt (coeff (first-term
                      '((3 -1) (2 2) (1 -1))))
              (+ 1 (- (order
                       (first-term
                        '((4 1) (3 1) (2 1) (1 -2) (0 -1))))
                      (order
                       (first-term
                        ((3 -1) (2 2) (1 -1))))))))
       '((4 1) (3 1) (2 1) (1 -2) (0 -1)))
      '((3 -1) (2 2) (1 -1))))

(cadr (div-terms
      (mul-term-by-all-terms (make-term 0 (expt -1 2))
                             '((4 1) (3 1) (2 1) (1 -2) (0 -1)))
      '((3 -1) (2 2) (1 -1))))

(cadr (div-terms
      (mul-term-by-all-terms (make-term 0 1)
                             '((4 1) (3 1) (2 1) (1 -2) (0 -1)))
      '((3 -1) (2 2) (1 -1))))

(cadr (div-terms '((4 1) (3 1) (2 1) (1 -2) (0 -1)) '((3 -1) (2 2) (1 -1))))

(cadr '(((1 -1) (0 -3)) ((2 6) (1 -5) (0 -1))))

'((2 6) (1 -5) (0 -1))

再度戻る

(div-by-gcd (gcd-terms-iter
            '((3 -1) (2 2) (1 -1))
            (pseudoremainder-terms '((4 1) (3 1) (2 1) (1 -2) (0 -1))
                                   '((3 -1) (2 2) (1 -1)))))

(div-by-gcd (gcd-terms-iter
            '((3 -1) (2 2) (1 -1))
            '((2 6) (1 -5) (0 -1))))

(div-by-gcd (gcd-terms-iter
            '((2 6) (1 -5) (0 -1))
            (psedoremainder-terms '((3 -1) (2 2) (1 -1))
                                  '((2 6) (1 -5) (0 -1)))))

再び psedoremainder-terms

(psedoremainder-terms '((3 -1) (2 2) (1 -1))
                     '((2 6) (1 -5) (0 -1)))

(cadr (div-terms
      (mul-term-by-all-terms (make-term
                              0
                              (expt (coeff (first-term
                                            '((2 6) (1 -5) (0 -1))))
                                    (+ 1 (- (order
                                             (first-term
                                              '((3 -1) (2 2) (1 -1))))
                                            (order
                                             (first-term
                                              '((2 6) (1 -5) (0 -1))))))))
                             '((3 -1) (2 2) (1 -1)))
      '((2 6) (1 -5) (0 -1))))

(cadr (div-terms
      (mul-term-by-all-terms (make-term 0 (expt 6 2))
                             '((3 -1) (2 2) (1 -1)))
      '((2 6) (1 -5) (0 -1))))

(cadr (div-terms '((3 -36) (2 72) (1 -36)) '((2 6) (1 -5) (0 -1))))

(cadr '(((1 -6) (0 7)) ((1 -7) (0 7))))

'((1 -7) (0 7))

そして戻る

(div-by-gcd (gcd-terms-iter
            '((2 6) (1 -5) (0 -1))
            (psedoremainder-terms '((3 -1) (2 2) (1 -1))
                                  '((2 6) (1 -5) (0 -1)))))

(div-by-gcd (gcd-terms-iter '((2 6) (1 -5) (0 -1)) '((1 -7) (0 7))))

(div-by-gcd (gcd-terms-iter
            '((1 -7) (0 7))
            (psedoremainder-terms '((2 6) (1 -5) (0 -1)) '((1 -7) (0 7)))))

だんだんリストが短くなってきたんですが、これでは原因の特定が (以下略

(psedoremainder-terms '((2 6) (1 -5) (0 -1)) '((1 -7) (0 7)))

(cadr (div-terms
      (mul-term-by-all-terms (make-term
                              0
                              (expt (coeff (first-term
                                            '((1 -7) (0 7))))
                                    (+ 1 (- (order
                                             (first-term
                                              '((2 6) (1 -5) (0 -1))))
                                            (order
                                             (first-term
                                              '((1 -7) (0 7))))))))
                             '((2 6) (1 -5) (0 -1)))
      '((1 -7) (0 7))))

(cadr (div-terms
      (mul-term-by-all-terms (make-term 0 (expt -7 2))
                             '((2 6) (1 -5) (0 -1)))
      '((1 -7) (0 7))))

(cadr (div-terms '((2 294) (1 -245) (0 -49)) '((1 -7) (0 7))))

(cadr '(((1 -42) (0 -7)) ()))

'()

やた。'() が戻るぞ。どうなるんだ。

(div-by-gcd (gcd-terms-iter
            '((1 -7) (0 7))
            (psedoremainder-terms '((2 6) (1 -5) (0 -1)) '((1 -7) (0 7)))))

(div-by-gcd (gcd-terms-iter
            '((1 -7) (0 7)) '()))

(div-by-gcd '((1 -7) (0 7)))

'((1 -1) (0 1))

うーん。見事に符号逆転。div-terms が悪いのかなぁ。ここでは置き換えせずに gosh でいきなり答えを出してますので、div-terms を上から順に置き換えてみる。まずは最初のソレから。ちなみに実装によれば商が ((1 1) (0 -1)) で余りが ((3 -1) (2 2) (1 -1)) になっています。

(div-terms '((5 1) (3 -1) (2 -1) (0 1))
	   '((4 1) (3 1) (2 1) (1 -2) (0 -1)))

;; t1 は '(5 1)
;; t2 は '(4 1)
;; (> (order t2) (order t1)) は #f

;; new-o は 1 new-c は 1
;; L2 に (1 1) を掛けると
;; '((5 1) (4 1) (3 1) (2 -2) (1 -1))
;; neg して '((5 -1) (4 -1) (3 -1) (2 2) (1 1))
;; L1 に add

(add-terms '((5 -1) (4 -1) (3 -1) (2 2) (1 1)) '((5 1) (3 -1) (2 -1) (0 1)))
;; 結果は ((4 -1) (3 -2) (2 1) (1 1) (0 1))
;; これを L2 で割る
(div-terms '((4 -1) (3 -2) (2 1) (1 1) (0 1))
	   '((4 1) (3 1) (2 1) (1 -2) (0 -1)))

;; t1 は '(4 -1)
;; t2 は '(4 1)
;; (> (order t2) (order t1)) は #f

;; new-o は 0 new-c は -1
;; L2 に (0 -1) を掛けると
;; ((4 -1) (3 -1) (2 -1) (1 2) (0 1))
;; neg して(とほほ)元に戻ります
;; L1 に add
(add-terms '((4 -1) (3 -2) (2 1) (1 1) (0 1))
	   '((4 1) (3 1) (2 1) (1 -2) (0 -1)))
;; 結果は ((3 -1) (2 2) (1 -1) (0 0))
;; これを L2 で割る
(div-terms '((3 -1) (2 2) (1 -1) (0 0))
	   '((4 1) (3 1) (2 1) (1 -2) (0 -1)))

;; t1 は '(3 -1)
;; t2 は '(4 1)
;; (> (order t2) (order t1)) は #t

;; L1 を返却
'((3 -1) (2 2) (1 -1))

最終的に返却されるのは '(((1 1) (0 -1)) ((3 -1) (2 2) (1 -1))) になる。

うーん。大体コード見て置き換えてるからその通りになって当然なんだよね。gcd-terms で符号が逆になってる、という事は 2.96 の試験が足らないのか。