다항식 p(x) 를 1차 다항식 x - a 로 나눌 때의 몫과 나머지를 구하는 조립제법을
Common Lisp 언어로 구현해 보았다. 조립제법은 일명 Horner의 방법이라고도 불리우는데, 이는 x = a 에서 다항식 p(x)의 값 p(a)을 계산하는 가장 빠른 알고리즘이기도 하다.
p(x) = (x - a)q(x) + r
여기서 r은 나머지이며 r = p(a) 이다. 또 q(x)는 몫이다.
[참고]
* 온라인으로 조립제법 표 만들기 손으로 계산하는 조립제법 표
* 온라인으로 구하는 다항식의 도함수: 조립제법을 이용한 다항식의 도함수
아래의 소스파일은 Python용 소스파일 testSyntheticDivision.py를 Common Lisp용으로 수정한 것이다.
실행은 CLisp을 사용한다.
- #!/usr/bin/env clisp
- ;; Filename: testSyntheticDivision.lsp
- ;;
- ;; Purpose: Find the quotient and remainder when some polynomial is
- ;; divided by a monic polynomial of the first degree.
- ;;
- ;; Execute: clisp testSyntheticDivision.lsp -2 1 3 3 1
- ;;
- ;; Date: 201. 8. 31.
- ;; 사용법 표시
- (defun printUsage()
- (format t "사용법: python testSyntheticDivision.py [수] [피제식의 계수들]~%")
- (format t "조립제법(synthetic method)에 의한 다항식 나눗셈 결과를 보여준다.~%"))
- ;; 스트링을 부동소수점수로 변환하는 함수
- (defun parse-number (v)
- (with-input-from-string (s v) (read s)))
- ;; 부동소수점수의 표현이 .0 으로 끝나는 경우 이를 잘라낸다.
- ;; 전체 문자열 표시 너비는 매개변수 width 로 전달받아 처리한다.
- (defun simplify(v width)
- (setf tt (format nil "~F" v))
- (setf tlen (length tt))
- (if (> tlen 1) (progn
- (if (equal (substring tt (- tlen 2) tlen) ".0") (progn
- (setf tt (substring tt 0 (- tlen 2)))
- (setf tlen (length tt))
- )
- )
- ))
- (if (not (equal width nil)) (progn
- (if (< tlen width) (progn
- (setf tt (concatenate 'string (substring " " 0 (- width tlen)) tt)) ))
- )
- )
- tt )
- ;; 다항식을 내림차순의 스트링 표현으로 반환
- (defun toPolyString(c)
- (setf ttt "")
- (setf sc0 (simplify (nth 0 c) nil ))
- (setf sc0 (simplify (nth 0 c) nil ))
- (if (> (length c) 2)
- (cond
- ((equal sc0 "1") (setf ttt (concatenate 'string ttt (format nil "x^~D" (- (length c) 1)))))
- ((equal 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
- ((equal sc0 "1") (setf ttt (concatenate 'string ttt "x")))
- ((equal 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 (equal 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 (equal 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 (equal sc "1")
- (setf ttt (concatenate 'string ttt " + " "x"))
- (setf ttt (concatenate 'string ttt " + " sc " x"))
- ) )
- ((< (nth i c) 0.0)
- (if (equal sc "-1")
- (setf ttt (concatenate 'string ttt " - " "x"))
- (setf ttt (concatenate 'string ttt " - " (simplify (abs (nth i c)) nil) " 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)) nil) )) )
- )
- )
- )
- ;; 다항식 나눗셈 결과를
- ;; (피제식) = (제식)(몫) + (나머지)
- ;; 형태로 출력
- (defun printDivisionResult(a c b)
- (setf strLine (concatenate 'string " " (toPolyString c)))
- (format t "~A~%" strLine)
- (setf strLine (concatenate 'string " = ( " (toPolyString (list 1.0 (- 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 b) 1) b))
- (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 q)
- (setf strLine " | ")
- (setf strLine (concatenate 'string strLine (simplify (nth 0 c) 6) ))
- (loop for i from 1 below (length c) do
- (setf strLine (concatenate 'string strLine " " (simplify (nth i c) 6) )))
- (format t "~A~%" strLine)
- (setf strLine (concatenate 'string (simplify a 6) " |"))
- (setf strLine (concatenate 'string strLine " "))
- (setf strLine (concatenate 'string strLine (simplify (nth 1 s) 6)))
- (loop for i from 2 below (length s) do
- (setf strLine (concatenate 'string strLine " " (simplify (nth i s) 6) )))
- (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 q) 6)))
- (loop for i from 1 below (length q) do
- (setf strLine (concatenate 'string strLine " " (simplify (nth i q) 6) )))
- (format t "~A~%" strLine)
- )
- ;; 실행 시작 지점
- (if (< (length ext:*args*) 3) (progn
- (printUsage)
- (quit) ))
- ;; ----------------------------------------------------
- ;; 피제식은 c_0 x^n + c_1 x^(n -1) + ... + c_n
- ;; 제식은 x - a
- (setf a (parse-number (nth 0 ext:*args*)) )
- (setf c (make-list (- (length ext:*args*) 1) :initial-element 0.0) )
- (setf s (make-list (- (length ext:*args*) 1) :initial-element 0.0) )
- (setf b (make-list (- (length ext:*args*) 1) :initial-element 0.0) )
- (loop for i from 0 below (length c) do
- (setf (nth i c) (parse-number (nth (+ i 1) ext:*args*))))
- ;; ----------------------------------------------------
- ;; 조립제법의 주요 부분
- (setf (nth 0 s) 0.0)
- (setf (nth 0 b) (nth 0 c))
- (loop for i from 1 below (length c) do
- (setf (nth i s) (* (nth (- i 1) b) a))
- (setf (nth i b) (+ (nth i c) (nth i s))) )
- ;; ----------------------------------------------------
- ;; 몫의 계수와 나머지를 출력한다.
- (format t "몫의 계수는 ")
- (loop for i from 0 below (- (length b) 2) do
- (format t (concatenate 'string (simplify (nth i b) nil) ", ")))
- (format t (concatenate 'string (simplify (nth (- (length b) 2) b) nil) " "))
- (format t (concatenate 'string "이고, 나머지는 " (simplify (nth (- (length b) 1) b) nil) " 이다.~%"))
- (terpri)
- ;; ----------------------------------------------------
- ;; 조립제법 표를 출력한다.
- (printSyntheticTable a c s b)
- (terpri)
- ;; ----------------------------------------------------
- ;; (피제식) = (제식) x (몫) + (나머지)
- (printDivisionResult a c b)
실행> clisp testSyntheticDivision.lsp 1 2 3 4 5
몫의 계수는 2, 5, 9 이고, 나머지는 14 이다.
| 2 3 4 5
1 | 2 5 9
|---------------------------------
2 5 9 14
2 x^3 + 3 x^2 + 4 x + 5
= ( x - 1 )( 2 x^2 + 5 x + 9 ) + 14
'프로그래밍 > Common Lisp' 카테고리의 다른 글
황금비율(golden ratio) 구하기 with Common Lisp (0) | 2013.09.01 |
---|---|
현재 시각 알아내기 for Common Lisp (0) | 2013.08.31 |
80컬럼 컨솔에 19단표 출력하기 예제 for Common Lisp (0) | 2013.08.29 |
(최대공약수 구하기) while... 반복문 예제 for Common Lisp (0) | 2013.08.29 |
if...else... 조건문 사용 예제 for Common Lisp (0) | 2013.08.29 |