1

多項式を単純化するプログラムを書いていますが、今のところ足し算と掛け算だけです。

私は何時間もキーボードに頭をぶつけていて、助けを求める時が来たと思っています。

(defun simplify (lis)
    (if (eq (car lis) '+)
        (cons '+ (simplify-addition (cdr lis)))
        (if (eq (car lis) '*)
            (cons '* (simplify-multiplication (cdr lis))) 
        )
    )
)
(defun simplify-addition (lis)
    (if (not (null lis))
        (if (listp (car lis))
            (list (simplify (car lis)) (simplify-addition (cdr lis)))
            (if (numberp (car lis))
                (if (eq (car lis) 0)
                    (simplify-addition (cdr lis))
                    (if (null (cdr lis))
                        lis
                        (cons (car lis) (simplify-addition (cdr lis)))
                    )
                )
                (if (eq (car lis) '+)
                    (list (car lis) (simplify-addition (cdr lis)))
                    (if (eq (car lis) '*)
                        (list (car lis) (simplify-addition (cdr lis)))
                        lis
                    )
                )
            )
        )
    )
)

(defun simplify-multiplication (lis)
    (if (not (null lis))
        (if (listp (car lis))
            (if (find 0 (car lis))
                0
                (list (simplify (car lis)) (simplify-multiplication (cdr lis)))
            )
            (if (numberp (car lis))
                (if (null (cdr lis))
                    lis
                    (cons (car lis) (simplify-multiplication (cdr lis)))
                )
                (if (eq (car lis) '+)
                    (list (car lis) (simplify-multiplication (cdr lis)))
                    (if (eq (car lis) '*)
                        (list (car lis) (simplify-multiplication (cdr lis)))
                        lis
                    )
                )
            )
        )
    )
)

これが起こるべきことです:

(simplify ‘(+  x  ( + 0 3 )  ( * 1 5 )  ( * ( * x  y  z ) 0 )  ))  -->  ( + x 3 5 )
(simplify ‘(* (+ 6  0)  (* 1 6 2)))  -------------------------------->  (* 6 (* 6 2))

しかし、代わりに、送信したのと同じ多項式を取得するか、何か完全にオフになります

編集:私が必要とする単純化は、追加から 0 を削除することです。

(+ 3 0)   --> 3
(+ 4 0 6) --> (+ 4 6)

ゼロとの乗算は削除されます

(* 6 0 7) --> 0 
4

2 に答える 2

2

まず、コーディング スタイルを少し改善して、読みやすくすることをお勧めします。

  • 独自の行に括弧を入れないでください。これはスペースを無駄にするだけで、まったく役に立ちません。

  • ドメイン固有のコードで CAR と CDR を使用しないでください。ドメインは数学です。式を使用します(operator arg1 arg2)。代わりに、関数を使用CARして定義し、それらを使用します。CDROPERATORARGUMENTS

  • CASECONDおよびその他のマルチウェイ条件式を、ネストの代わりに使用しIFます - 便利な場合。

  • ドメインコードからデータ構造のトラバーサルを抽出しようとします。MAP再帰 ( 、REDUCE、 ...)の代わりに高階関数を使用します。

例:

いくつかの基本的なドメイン機能:

(defun operator (expression)
  (first expression))

(defun arguments (expression)
  (rest expression))

(defun make-expression (operator arguments)
  (if (= (length arguments) 1)
      (first arguments)
    (cons operator arguments)))

(defun is-zero? (expression)
  (and (numberp expression)
       (= expression 0)))

今単純化:

(defun simplify (expression)
  (if (atom expression)
      expression
    (case (operator expression)
      (+ (make-expression '+ (simplify-addition       (arguments expression))))
      (* (make-expression '* (simplify-multiplication (arguments expression)))))))

(defun simplify-addition (expressions)
  (remove-if #'is-zero?
             (mapcar #'simplify
                     (remove-if #'is-zero? expressions))))

(defun simplify-multiplication (expressions)
  (if (member-if #'is-zero? expressions)
      (list 0)
    (let ((expressions1 (mapcar #'simplify expressions)))
      (if (member-if #'is-zero? expressions1)
          (list 0)
        expressions1))))

ほら、コードがどれほど読みやすくなったでしょうか? もうCAR、、。LIS_ CDR再帰呼び出しの意図も、より明確に理解できます。

まだ最適ではありませんが、うまくいくはずです。

于 2012-12-01T08:08:39.700 に答える
1

私は見ただけですsimplify-multiplicationが、ここには多くの問題があります。

一般的な注意として、最初に再帰的に単純化し、その後で特定の定数を確認します。(注文後のトラバーサルだと思います。)

第二に、どこにもチェックして1いないので、どのように機能するのかわかりません(* 1 5) ==> 5

(simplify '(* (+ 2 0) 3))3 番目に、少し手順を追ってみましょう。

(defun simplify-multiplication (lis)
; lis = '((+ 2 0) 3)
    (if (not (null lis))
    ; ==> t
        (if (listp (car lis))
        ; (car lis) = '(+ 2 0), so (listp '(+ 2 0)) ==> t
            (if (find 0 (car lis))
            ; succeeds because '(+ 2 0) contains 0
            ; this is completely wrong! you're not supposed to check sublists of lis
                0
                ; ... yeah, you just returned 0 just because there was a 0 *somewhere*
                (list (simplify (car lis)) (simplify-multiplication (cdr lis)))
            )
            ...

または(simplify '(* 0 2)):

(defun simplify-multiplication (lis)
; lis = '(0 2)
    (if (not (null lis))
    ; ==> t
        (if (listp (car lis))
        ; (car lis) = 0, so (listp 0) ==> nil
            (if (find 0 (car lis))
                0
                (list (simplify (car lis)) (simplify-multiplication (cdr lis)))
            )
            (if (numberp (car lis))
            ; (numberp 0) ==> t
                (if (null (cdr lis))
                ; (cdr lis) = '(2), so (null '(2)) ==> nil
                    lis
                    (cons (car lis) (simplify-multiplication (cdr lis)))
                    ; ... wait, what?
                    ; you're just recursively walking through the list without
                    ; checking what numbers you actually got. this won't simplify
                    ; anything.
                )
                (if (eq (car lis) '+)
                ; what is this branch for? it can only succeed if you have code of the form
                ;   (* 1 + 2)
                ; which is a syntax error
                    (list (car lis) (simplify-multiplication (cdr lis)))
                    (if (eq (car lis) '*)
                    ; this branch is for code like (* * *). huh???
                        (list (car lis) (simplify-multiplication (cdr lis)))
                        lis
                    )
                )
            )
        )
    )
)
于 2012-12-01T01:38:27.337 に答える