다항식 p(x) 를 1차 다항식 ax - b 로 나눌 때의 몫과 나머지를 구하는 조립제법을
Python 언어로 구현해 보았다. 조립제법은 일명 Horner의 방법이라고도 불리우는데, 이는
x = a 에서 다항식 p(x)의 값 p(a)을 계산하는 가장 빠른 알고리즘이기도 하다.
p(x) = (ax - b)q(x) + r
여기서 r은 나머지이며 r = p(b/a) 이다. 또 q(x)는 몫이다.
[참고]
* 온라인으로 조립제법 표 만들기 손으로 계산하는 조립제법 표
* 온라인으로 구하는 다항식의 도함수: 조립제법을 이용한 다항식의 도함수
아래의 소스파일은 이전에 작성했던 파일 testSyntheticDivision.lsp 를 수정한 것이다.
- ;; Filename: testSyntheticDivision2.lsp
- ;;
- ;; Purpose: Find the quotient and remainder when some polynomial is
- ;; divided by a monic polynomial of the first degree.
- ;;
- ;; Execute: clisp testSyntheticDivision2.lsp 5 -4 7 8 6 8
- ;;
- ;; Date: 2013. 9. 7.
- ;; 사용법 표시
- (defun printUsage()
- (format t "사용법: clisp testSyntheticDivision2.lsp [제식의 계수] [피제식의 계수들]~%")
- (format t "조립제법(synthetic method)에 의한 다항식 나눗셈 결과를 보여준다.~%")
- )
- ;; 부동소수점수의 표현이 .0 으로 끝나는 경우 이를 잘라낸다.
- ;; 전체 문자열 표시 너비는 매개변수 width 로 전달받아 처리한다.
- (defun simplify(v &optional width)
- (let* ((tt "")
- (slen 0))
- (setf tt (format nil "~A" v))
- (setf slen (length tt))
- (if (and (>= slen 2) (string= (substring tt (- slen 2) slen) ".0"))
- (setf tt (substring tt 0 (- slen 2))) )
- (setf slen (length tt))
- (if width
- (if (< slen width)
- (setf tt (concatenate 'string (make-string (- width slen) :initial-element #\Space) tt)) ))
- tt
- )
- )
- ;; "/수" 표시하기
- ;; 부동소수점수의 표현이 .0 으로 끝나는 경우 이를 잘라낸다.
- ;; 전체 문자열 표시 너비는 매개변수 width 로 전달받아 처리한다.
- (defun simplifyReciprocal(v &optional width)
- (let* ((tt "")
- (tlen 0))
- (setf tt (format nil "/~A" v))
- (setf tlen (length tt))
- (if (and (>= tlen 2) (string= (substring tt (- tlen 2) tlen) ".0"))
- (setf tt (substring tt 0 (- tlen 2))) )
- (setf tlen (length tt))
- (if width
- (if (< tlen width)
- (setf tt (concatenate 'string (make-string (- width tlen) :initial-element #\Space) tt)) ))
- tt
- )
- )
- ;; 다항식을 내림차순의 스트링 표현으로 반환
- (defun toPolyString(c)
- (let* ((ttt "")
- (sc0 "")
- (sc "")
- (k 0))
- (setf ttt "")
- (setf sc0 (simplify (nth 0 c) nil ))
- (if (> (length c) 2)
- (cond
- ((string= sc0 "1") (setf ttt (concatenate 'string ttt (format nil "x^~D" (- (length c) 1)))))
- ((string= sc0 "-1") (setf ttt (concatenate 'string ttt (format nil "-x^~D" (- (length c) 1)))))
- (t (setf ttt (concatenate 'string ttt sc0 (format nil " x^~D" (- (length c) 1)))))
- )
- )
- (if (= (length c) 2)
- (cond
- ((string= sc0 "1") (setf ttt (concatenate 'string ttt "x")))
- ((string= sc0 "-1") (setf ttt (concatenate 'string ttt "-x")))
- (t (setf ttt (concatenate 'string ttt sc0 " x")))
- )
- )
- (if (= (length c) 1)
- (setf ttt (concatenate 'string ttt sc0))
- )
- (loop for i from 1 below (length c) do
- (setf k (- (length c) 1 i))
- (setf sc (simplify (nth i c) nil))
- (if (> k 1) (progn
- (cond
- ((> (nth i c) 0.0)
- (if (string= sc "1")
- (setf ttt (concatenate 'string ttt " + " (format nil "x^~D" k)))
- (setf ttt (concatenate 'string ttt " + " sc (format nil " x^~D" k)))
- ) )
- ((< (nth i c) 0.0)
- (if (string= sc "-1")
- (setf ttt (concatenate 'string ttt " - " (format nil "x^~D" k)))
- (setf ttt (concatenate 'string ttt " - " (simplify (abs (nth i c)) nil) (format nil " x^~D" k)))
- ) )
- )
- )
- )
- (if (= k 1)
- (cond
- ((> (nth i c) 0.0)
- (if (string= sc "1")
- (setf ttt (concatenate 'string ttt " + " "x"))
- (setf ttt (concatenate 'string ttt " + " sc " x"))
- ) )
- ((< (nth i c) 0.0)
- (if (string= sc "-1")
- (setf ttt (concatenate 'string ttt " - " "x"))
- (setf ttt (concatenate 'string ttt " - " (simplify (abs (nth i c))) " x"))
- ) )
- )
- )
- (if (= k 0)
- (cond
- ( (> (nth i c) 0.0) (setf ttt (concatenate 'string ttt " + " sc)) )
- ( (< (nth i c) 0.0) (setf ttt (concatenate 'string ttt " - " (simplify (abs (nth i c))) )) )
- )
- )
- )
- ttt
- )
- )
- ;; 다항식 나눗셈 결과를
- ;; (피제식) = (제식)(몫) + (나머지)
- ;; 형태로 출력
- (defun printDivisionResult(a c d b)
- (let* ((strLine ""))
- (setf strLine (concatenate 'string " " (toPolyString c)))
- (format t "~A~%" strLine)
- (setf strLine (concatenate 'string " = ( " (toPolyString (list (nth 0 a) (- (nth 1 a)))) " )"))
- (setf tmp (make-list (- (length b) 1) :initial-element 0.0))
- (loop for i from 0 below (length tmp) do
- (setf (nth i tmp) (nth i b)) )
- (setf strLine (concatenate 'string strLine "( " (toPolyString tmp) " )"))
- (setf r (nth (- (length d) 1) d))
- (cond
- ((> r 0.0) (setf strLine (concatenate 'string strLine " + " (simplify r nil) )))
- ((< r 0.0) (setf strLine (concatenate 'string strLine " - " (simplify (abs r) nil) )))
- )
- (format t "~A~%" strLine)
- )
- )
- ;; 조립제법 계산표 출력 함수
- (defun printSyntheticTable(a c s d q)
- (let* ((strLine ""))
- (setf strLine " | ")
- (setf strLine (concatenate 'string strLine (simplify (nth 0 c) 10) ))
- (loop for i from 1 below (length c) do
- (setf strLine (concatenate 'string strLine " " (simplify (nth i c) 10) )))
- (format t "~A~%" strLine)
- (setf strLine (concatenate 'string (simplify (nth 1 a) 8) " |"))
- (setf strLine (concatenate 'string strLine " "))
- (setf strLine (concatenate 'string strLine (simplify (nth 1 s) 10)))
- (loop for i from 2 below (length s) do
- (setf strLine (concatenate 'string strLine " " (simplify (nth i s) 10) )))
- (format t "~A~%" strLine)
- (setf strLine " |")
- (loop for i from 0 below (length q) do
- (setf strLine (concatenate 'string strLine "------------")))
- (format t "~A~%" strLine)
- (setf strLine " | ")
- (setf strLine (concatenate 'string strLine (simplify (nth 0 d) 10)))
- (loop for i from 1 below (length d) do
- (setf strLine (concatenate 'string strLine " " (simplify (nth i d) 10))))
- (format t "~A~%" strLine)
- (setf strLine (concatenate 'string (simplifyReciprocal (nth 0 a) 8) " | "))
- (setf strLine (concatenate 'string strLine (simplify (nth 0 q) 10)))
- (loop for i from 1 below (1- (length q)) do
- (setf strLine (concatenate 'string strLine " " (simplify (nth i q) 10) )))
- (format t "~A~%" strLine)
- )
- )
- ;; 실행 시작 지점
- (if (< (length ext:*args*) 3) (progn
- (printUsage)
- (quit) ))
- ;; ----------------------------------------------------
- ;; 피제식은 c_0 x^n + c_1 x^(n -1) + ... + c_n
- ;; 제식은 a x - b
- (setf a (list (read-from-string (nth 0 ext:*args*)) (- (read-from-string (nth 1 ext:*args*)))) )
- (setf c (make-list (- (length ext:*args*) 2) :initial-element 0.0) )
- (setf s (make-list (- (length ext:*args*) 2) :initial-element 0.0) )
- (setf d (make-list (- (length ext:*args*) 2) :initial-element 0.0) )
- (setf b (make-list (- (length ext:*args*) 2) :initial-element 0.0) )
- (loop for i from 0 below (length c) do
- (setf (nth i c) (read-from-string (nth (+ i 2) ext:*args*))))
- ;; ----------------------------------------------------
- ;; 조립제법의 주요 부분
- (setf (nth 0 s) 0.0)
- (setf (nth 0 d) (nth 0 c))
- (setf (nth 0 b) (+ 0.0 (/ (nth 0 c) (nth 0 a))))
- (loop for i from 1 below (length c) do
- (setf (nth i s) (* (nth (- i 1) b) (nth 1 a)))
- (setf (nth i d) (+ (nth i c) (nth i s)))
- (setf (nth i b) (+ 0.0 (/ (nth i d) (nth 0 a)))) )
- ;; ----------------------------------------------------
- ;; 몫의 계수와 나머지를 출력한다.
- (format t "몫의 계수는 ")
- (loop for i from 0 below (- (length b) 2) do
- (format t (concatenate 'string (simplify (nth i b)) ", ")))
- (format t (concatenate 'string (simplify (nth (- (length b) 2) b)) " "))
- (format t (concatenate 'string "이고, 나머지는 " (simplify (nth (- (length d) 1) d)) " 이다.~%"))
- (terpri)
- ;; ----------------------------------------------------
- ;; 조립제법 표를 출력한다.
- (printSyntheticTable a c s d b)
- (terpri)
- ;; ----------------------------------------------------
- ;; (피제식) = (제식) x (몫) + (나머지)
- (printDivisionResult a c d b)
- (format t "~%")
실행> clisp testSyntheticDivision2.lsp 5 -4 7 8 6 8
'프로그래밍 > Common Lisp' 카테고리의 다른 글
Common Lisp 언어로 복소수 계산하기 (0) | 2013.09.07 |
---|---|
Common Lisp 를 이용한 간단한 수학식 계산하기 (0) | 2013.09.07 |
숫자 맞추기 게임 with Common Lisp (0) | 2013.09.07 |
스트링 리스트에서 스트링 찾기(find) with Common Lisp (0) | 2013.09.06 |
스트링 배열 정렬(sorting)하기 with Common Lisp (0) | 2013.09.06 |