프로그래밍/Julia

조립제법(Horner의 방법) 예제 for Julia

Scripter 2013. 3. 3. 22:25

다항식 p(x) 를 1차 다항식 x - a 로 나눌 때의 몫과 나머지를 구하는 조립제법을
Python 언어로 구현해 보았다. 조립제법은 일명 Horner의 방법이라고도 불리우는데, 이는
x = a 에서 다항식 p(x)의 값 p(a)을 계산하는 가장 빠른 알고리즘이기도 하다.

         p(x) = (x - a)q(x) + r

여기서 r은 나머지이며 r = p(a) 이다. 또 q(x)는 몫이다.

[참고]
    * 온라인으로 조립제법 표 만들기 손으로 계산하는 조립제법 표 
    * 온라인으로 구하는 다항식의 도함수: 조립제법을 이용한 다항식의 도함수


아래의 소스파일은 Python 용 소스파일 testSyntheticDivision.py 를 Julia 용으로 수정한 것이다.


  1. ##  Filename: testSyntheticDivision.jl
  2. ##
  3. ##  Purpose:  Find the quotient and remainder when some polynomial is
  4. ##            divided by a monic polynomial of the first degree.
  5. ##
  6. ##  Execute:  julia testSyntheticDivision.jl -2 1 3 3 1
  7. ##
  8. ##      Date:  2013. 3. 4.
  9. # 사용법 표시
  10. function printUsage()
  11.     println("사용법: python testSyntheticDivision.py [수] [피제식의 계수들]")
  12.     println("조립제법(synthetic method)에 의한 다항식 나눗셈 결과를 보여준다.")
  13. end
  14. # 부동소수점수의 표현이 .0 으로 끝나는 경우 이를 잘라낸다.
  15. # 전체 문자열 표시 너비는 매개변수 width 로 전달받아 처리한다.
  16. function simplify(v, width)
  17.     t = "$v"
  18.     tlen = length(t)
  19.     if tlen >1 && t[tlen-1:tlen] == ".0"
  20.         t = t[1:tlen-2]
  21.     end
  22.     if width > 0
  23.         if tlen < width
  24.             t = string( "              "[1: width - tlen], t)
  25.         end
  26.     end
  27.     return t
  28. end
  29. # 다항식을 내림차순의 스트링 표현으로 반환
  30. function toPolyString(c)
  31.     t = ""
  32.     sc0 = simplify(c[1], 0)
  33.     if length(c) > 2
  34.         if sc0 == "1"
  35.             t = string(t,  "x^$(length(c)-1)")
  36.         elseif sc0 == "-1"
  37.             t = string(t,  "-x^$(length(c)-1)")
  38.         else
  39.             t = string(t, sc0 , " x^$(length(c)-1)")
  40.         end
  41.     elseif length(c) == 2
  42.         if sc0 == "1"
  43.             t = string(t, "x")
  44.         elseif sc0 == "-1"
  45.             t = string(t, "-x")
  46.         else
  47.             t = string(t, sc0, " x")
  48.         end
  49.     elseif length(c) == 1
  50.         t = string(t, sc0)
  51.     end
  52.     for i = 2: length(c)
  53.         k = length(c)  - i
  54.         sc = simplify(c[i], 0)
  55.         if k > 1
  56.             if c[i] > 0.0
  57.                 if sc == "1"
  58.                     t = string(t, " + ", "x^$(k)")
  59.                 else
  60.                     t = string(t, " + ", sc, " x^$(k)")
  61.                 end
  62.             elseif c[i] < 0.0
  63.                 if sc == "-1"
  64.                     t = string(t, " - ", "x^$(k)")
  65.                 else
  66.                     t = string(t, " - ", simplify(abs(c[i]), 0), " x^$(k)")
  67.                 end
  68.             end
  69.         elseif k == 1
  70.             if c[i] > 0.0
  71.                 if sc == "1"
  72.                     t = string(t, " + ", "x")
  73.                 else
  74.                     t = string(t, " + ", sc, " x")
  75.                 end
  76.             elseif c[i] < 0.0
  77.                 if sc == "-1"
  78.                     t = string(t, " - ", "x")
  79.                 else
  80.                     t = string(t, " - ", simplify(abs(c[i]), 0), " x")
  81.                 end
  82.             end
  83.         elseif k == 0
  84.             if c[i] > 0.0
  85.                 t = string(t, " + ", sc)
  86.             elseif c[i] < 0.0
  87.                 t = string(t, " - ", simplify(abs(c[i]), 0))
  88.             end
  89.         end
  90.     end
  91.     return t
  92. end
  93. # 다항식 나눗셈 결과를
  94. #     (피제식) = (제식)(몫) + (나머지)
  95. # 형태로 출력
  96. function printDivisionResult(a, c, b)
  97.     strLine = string("  ", toPolyString(c))
  98.     println( strLine )
  99.     strLine = string("    = ( ", toPolyString( [1.0, -a] ), " )")
  100.     tmp = [0.0 for i = 1:(length(b) - 1) ]
  101.     for i = 1:length(tmp)
  102.         tmp[i] = b[i]
  103.     end
  104.     strLine = string(strLine, "( ", toPolyString(tmp), " )")
  105.     r = b[length(b)]
  106.     if r > 0.0
  107.         strLine = string(strLine, " + ", simplify(r), 0)
  108.     elseif r < 0.0
  109.         strLine = string(strLine, " - ", simplify(abs(r, 0)))
  110.     end
  111.     println( strLine )
  112. end
  113. # 조립제법 계산표 출력 함수
  114. function printSyntheticTable(a, c, s, q)
  115.     strLine = "       | "
  116.     strLine = string(strLine, simplify(c[1], 8))
  117.     for i = 2:length(c)
  118.         strLine = string(strLine, "  ", simplify(c[i], 8))
  119.     end
  120.     println( strLine )
  121.     strLine = string(simplify(a, 8), " |")
  122.     strLine = string(strLine, "         ")
  123.     strLine = string(strLine, simplify(s[2], 8))
  124.     for i = 3:length(s)
  125.         strLine = string(strLine, "  ", simplify(s[i], 8))
  126.     end
  127.     println( strLine )
  128.     strLine = "       |"
  129.     for i = 1:length(q)
  130.         strLine = string(strLine, "--------")
  131.     end
  132.     println( strLine )
  133.     strLine = "         "
  134.     strLine = string(strLine, simplify(q[1], 8))
  135.     for i = 2:length(q)
  136.         strLine = string(strLine, "  ", simplify(q[i], 8))
  137.     end
  138.     println( strLine )
  139. end
  140. # 실행 시작 지점
  141. if length(ARGS) < 3
  142.     printUsage()
  143.     exit(1)
  144. end
  145. ######################################################
  146. # 피제식은 c_0 x^n +  c_1 x^(n -1) + ... + c_n
  147. # 제식은 x -  a
  148. a = float64(parse_float(ARGS[1]) )
  149. c = [0.0 for i=1:length(ARGS) - 1 ]
  150. s = [0.0 for i=1:length(ARGS) - 1 ]
  151. b = [0.0 for i=1:length(ARGS) - 1 ]
  152. for i = 1:length(c)
  153.     c[i] = float64(parse_float(ARGS[i + 1]))
  154. end
  155. ######################################################
  156. # 조립제법의 주요 부분
  157. s[1] = 0.0
  158. b[1] = c[1]
  159. for i in 2:length(c)
  160.     s[i] = b[i-1]*a
  161.     b[i] = c[i] + s[i]
  162. end
  163. ######################################################
  164. # 몫의 계수와 나머지를 출력한다.
  165. print("몫의 계수는 ")
  166. for i = 1:length(b)-2
  167.     print(simplify(b[i], 0), ", " )
  168. end
  169. print(simplify(b[length(b) - 1], 0), " ")
  170. print("이고, 나머지는 ", simplify(b[length(b)], 0), " 이다.")
  171. println("")
  172. ######################################################
  173. # 조립제법 표를 출력한다.
  174. printSyntheticTable(a, c, s, b)
  175. println("")
  176. ######################################################
  177. # (피제식) = (제식) x (몫) + (나머지)
  178. printDivisionResult(a, c, b)



실행> julia testSyntheticDivision.jl 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