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

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

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

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



  1. /*
  2.  *  Filename: testSyntheticDivisionCPP.cpp
  3.  *
  4.  *  Purpose:  Find the quotient and remainder when some polynomial is
  5.  *            divided by a monic polynomial of the first degree.
  6.  *
  7.  *  Compile:  cl -GX testSyntheticDivisionCPP.cpp
  8.  *        Or  cl /EHsc testSyntheticDivisionCPP.cpp
  9.  *
  10.  *  Execute:  testSyntheticDivisionCPP -2 1 3 3 1
  11.  */
  12. #include <iostream>
  13. #include <string>
  14. #include <cmath>
  15. #include <memory>
  16. using namespace std;
  17. void print(char str[]) {
  18.     cout << str;
  19. }
  20. void println() {
  21.     cout << endl;
  22. }
  23. void println(char str[]) {
  24.     cout << str << endl;
  25. }
  26. // 사용법 표시
  27. void printUsage() {
  28.      cout << "사용법: testSyntheticDivisionCPP [수] [피제식의 계수들]" << endl;
  29.      cout << "조립제법(synthetic method)에 의한 다항식 나눗셈 결과를 보여준다." << endl;
  30. }
  31. // 부동소수점수의 표현이 .0 으로 끝나는 경우 이를 잘라낸다.
  32. char *simplify(double v) {
  33.     int n;
  34.     static char t[] = "                               ";
  35.     char tmp[] = "                               ";
  36.     sprintf(t, "%g", v);
  37.     n = strlen(t);
  38.     if ((n > 2) && (t[n - 2] == '.') && (t[n - 1] == '0'))
  39.         t[n-2] = '\0';
  40.     return (char *) t;
  41. }
  42. // 부동소수점수의 표현이 .0 으로 끝나는 경우 이를 잘라낸다.
  43. // 전체 문자열 표시 너비는 매개변수 width 로 전달받아 처리한다.
  44. char *simplify(double v, int width) {
  45.     int n, len;
  46.     static char t[] = "                               ";
  47.     char tmp[] = "                               ";
  48.     sprintf(t, "%g", v);
  49.     n = strlen(t);
  50.     if ((n > 2) && (t[n - 2] == '.') && (t[n - 1] == '0'))
  51.         t[n-2] = '\0';
  52.     len = strlen(t);
  53.     strcpy(tmp, t);
  54.     if (len < width) {
  55.         strncpy(t, "               ", width - len);
  56.         t[width - len] = '\0';
  57.         strcat(t, tmp);
  58.     }
  59.     return (char *) t;
  60. }
  61. // 다항식을 내림차순의 문자열로로 반환하는 함수
  62. // 반환된 문자열은 동적 메모리에 존재하므로.
  63. // 사용 후 반드시 해제(free)하여야 한다.
  64. char *toPolyString(double c[], int size) {
  65.     int SIZE = size;
  66.     int i;
  67.     static char t[300];
  68.     char tmp[80];
  69.     char *pc = simplify(c[0], -1);
  70.     char *pci;
  71.     if (SIZE > 2) {
  72.         if (strlen(pc) == 1 && pc[0] == '1')
  73.             sprintf(t,  "x^%d", SIZE - 1);
  74.         else if (strlen(pc) == 2 && pc[0] == '-' && pc[1] == '1')
  75.             sprintf(t,  "-x^%d", SIZE - 1);
  76.         else
  77.             sprintf(t,  "%s x^%d", simplify(c[0], -1), SIZE - 1);
  78.     }
  79.     else if (SIZE == 2) {
  80.         if (strlen(pc) == 1 && pc[0] == '1')
  81.             strcpy(t,  "x");
  82.         else if (strlen(pc) == 2 && pc[0] == '-' && pc[1] == '1')
  83.             strcpy(t,  "-x");
  84.         else
  85.             sprintf(t,  "%s x", simplify(c[0], -1));
  86.     }
  87.     else if (SIZE == 1) {
  88.         sprintf(t,  "%s", simplify(c[0], -1));
  89.     }
  90.     for (i = 1; i < SIZE; i++) {
  91.         pci = simplify(c[i], -1);
  92.         if (SIZE - 1 - i > 1) {
  93.             if (c[i] > 0.0) {
  94.                 if (strlen(pci) == 1 && pci[0] == '1') {
  95.                     sprintf(tmp,  " + x^%d", SIZE - 1 - i);
  96.                     strcat(t, tmp);
  97.                 }
  98.                 else {
  99.                     sprintf(tmp,  " + %s x^%d", simplify(c[i], -1), SIZE - 1 - i);
  100.                     strcat(t, tmp);
  101.                 }
  102.             }
  103.             else if (c[i] < 0.0) {
  104.                 if (strlen(pci) == 2 && pci[0] == '-' && pci[1] == '1') {
  105.                     sprintf(tmp,  " - x^%d", SIZE - 1 - i);
  106.                     strcat(t, tmp);
  107.                 }
  108.                 else {
  109.                     sprintf(tmp,  " - %s x^%d", simplify(fabs(c[i]), -1), SIZE - 1 - i);
  110.                     strcat(t, tmp);
  111.                 }
  112.             }
  113.         }
  114.         else if (SIZE - 1 - i == 1) {
  115.             if (c[i] > 0.0) {
  116.                 if (strlen(pci) == 1 && pci[0] == '1') {
  117.                     strcat(t, " + x");
  118.                 }
  119.                 else {
  120.                     sprintf(tmp,  " + %s x", simplify(c[i], -1));
  121.                     strcat(t, tmp);
  122.                 }
  123.             }
  124.             else if (c[i] < 0.0) {
  125.                 if (strlen(pci) == 2 && pci[0] == '-' && pci[1] == '1') {
  126.                     strcat(t, " - x");
  127.                 }
  128.                 else {
  129.                     sprintf(tmp,  " - %s x", simplify(fabs(c[i]), -1));
  130.                     strcat(t, tmp);
  131.                 }
  132.             }
  133.         }
  134.         else if (SIZE - 1 - i == 0) {
  135.             if (c[i] > 0.0) {
  136.                 sprintf(tmp,  " + %s", simplify(c[i], -1));
  137.                 strcat(t, tmp);
  138.             }
  139.             else if (c[i] < 0.0) {
  140.                 sprintf(tmp,  " - %s", simplify(fabs(c[i]), -1));
  141.                 strcat(t, tmp);
  142.             }
  143.         }
  144.     }
  145.     return (char *) t;
  146. }
  147. // 다항식 나눗셈 결과를
  148. //     (피제식) = (제식)(몫) + (나마지)
  149. // 형태로 출력
  150. void printDivisionResult(double a, double c[], double b[], int size) {
  151.     int SIZE = size;
  152.     int i;
  153.     double *pTmpPoly;
  154.     double r;
  155.     double monic[] = { 1.0, 0.0 };
  156.     print("  ");
  157.     print(toPolyString(c, SIZE));
  158.     println("");
  159.     print("    = ( ");
  160.     monic[1] = -a;
  161.     print(toPolyString(  monic, 2 ));
  162.     print(" )");
  163.     pTmpPoly = (double *)  calloc(SIZE - 1, sizeof(double));
  164.     for (i = 0; i < SIZE - 1; i++) {
  165.         pTmpPoly[i] = b[i];
  166.     }
  167.     print("( ");
  168.     print(toPolyString(pTmpPoly, SIZE - 1));
  169.     print(" )");
  170.     free(pTmpPoly);
  171.     r = b[SIZE - 1];
  172.     if (r > 0.0) {
  173.         print(" + ");
  174.         print(simplify(r, -1));
  175.     }
  176.     else if (r < 0.0) {
  177.         print(" - ");
  178.         print(simplify(fabs(r), -1));
  179.     }
  180.     println();
  181. }
  182. // 조립제법 계산표 출력 함수
  183. void printSyntheticTable(double a, double c[], double s[], double q[], int size) {
  184.     int SIZE = size;
  185.     int i;
  186.     print("       | ");
  187.     print(simplify(c[0], 6));
  188.     for (i = 1; i < SIZE; i++) {
  189.         print("  ");
  190.         print(simplify(c[i], 6));
  191.     }
  192.     println();
  193.     print(simplify(a, 6));
  194.     print(" | ");
  195.     print("        ");
  196.     print(simplify(s[1], 6));
  197.     for (i = 2; i < SIZE; i++) {
  198.         print("  ");
  199.         print(simplify(s[i], 6));
  200.     }
  201.     println();
  202.     print("       |-");
  203.     for (i = 0; i < SIZE; i++) {
  204.         print("--------");
  205.     }
  206.     println();
  207.     print("         ");
  208.     print(simplify(q[0], 6));
  209.     for (i = 1; i < SIZE; i++) {
  210.         print("  ");
  211.         print(simplify(q[i], 6));
  212.     }
  213.     println();
  214. }
  215. // C++ 언어의 실행 시작 지점
  216. int main(int argc, char *argv[]) {
  217.     int i;
  218.     int SIZE = argc - 2;
  219.     double a, c[15], s[15], b[15];
  220.     if (argc < 4) {
  221.         printUsage();
  222.         exit(1);
  223.     }
  224.     //////////////////////////////////////////////////////
  225.     // 피제식은 c_0 x^n +  c_1 x^(n -1) + ... + c_n
  226.     // 제식은 x -  a
  227.     a = atof(argv[1]);
  228.     for (i = 0; i < SIZE; i++) {
  229.      c[i] = atof(argv[i + 2]);
  230.     }
  231.     //////////////////////////////////////////////////////
  232.     // 조립제법의 주요 부분
  233.     s[0] = 0.0;
  234.     b[0] = c[0];
  235.     for (i = 1; i < SIZE; i++) {
  236.         s[i] = b[i-1]*a;
  237.         b[i] = c[i] + s[i];
  238.     }
  239.     print("몫의 계수는 ");
  240.     for (i = 0; i < SIZE - 2; i++) {
  241.         print(simplify(b[i], -1));
  242.         print(", ");
  243.     }
  244.     print(simplify(b[SIZE - 2], -1));
  245.     print(" 이고, 나머지는 ");
  246.     print(simplify(b[SIZE - 1], -1));
  247.     println(" 이다.");
  248.     println();
  249.     //////////////////////////////////////////////////////
  250.     // 조립제법 표를 출력한다.
  251.     printSyntheticTable(a, c, s, b, SIZE);
  252.     println();
  253.     //////////////////////////////////////////////////////
  254.     // (피제식) = (제식) x (몫) + (나머지)
  255.     printDivisionResult(a, c, b, SIZE);
  256.     return 0;
  257. }




컴파일> cl -EHsc testSyntheticDivisionCPP.cpp

실행> testSyntheticDivisionCPP 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



Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
Posted by Scripter
,