// MullerÀÇ ¹æ¹ý 

#include <complex.h>  // Borland-C¿¡¼­´Â º¹¼Ò¼ö Ŭ·¡½º°¡ Áö¿øµÊ.
#include <stdio.h>
#include <math.h>
#include <iostream.h>

#define ZERO 1.0E-20
#define pi 3.141592654
#define true 1
#define false 0

void main()
{
   complex Z_[4], G_[4], CH1_[3], CDEL1_[2], CDEL_, CB_, CD_, CE_, Q_, E_, F_;
   // º¹¼Ò¼ö º¯¼ö´Â º¯¼ö¸í µÚ¿¡ _ ¸¦ ºÙ¿© Ç¥½Ã

   double A[50], F[4], X[4], H[3];
   double DEL1[2];
   double DEL, B, D, E;
   int degree, i, j, KK, OK, isComplex;
   double tolerance = 1.e-4; // ¿ÀÂ÷ÀÇ ÇѰè
   int num = 40;           // °è»êÀÇ È½¼ö
   FILE *display;

   // Ãâ·ÂÀ§Ä¡ ÁöÁ¤
   cout << "Select Output :" << endl;
   cout << " 1 : screen (default)" << endl;
   cout << " 2 : file   (->muller.txt)" << endl;
   cin >> i;

   if(i == 2) display = fopen("muller.txt","w");
   else display = stdout;
   // 2¹øÀ» ¼±ÅÃÇÏ¸é ÆÄÀÏ·Î ÀúÀå, ³ª¸ÓÁö °æ¿ì´Â È­¸é Ãâ·Â

   fprintf(display, "Muller's Method.\n");

   OK = false;

   while (!OK) {
      cout << "Input the degree of the polynomial" << endl;
      cin >> degree;   // Â÷¼ö¸¦ ÀԷ¹޴´Ù.

      if (degree++ > 0) {
         OK = true;
	 cout << "\nInput the coefficients of the "   \
		 "polynomial in ascending order\n"    \
                 "of exponent at the prompt" << endl;

	 for (i=0; i<degree ; i++) {
	    cout << "Input A(" << i << ")\n";
	    cin >> A[i];  // °è¼ö¸¦ ÀԷ¹޴´Ù.
         }
      } else cout << "n must be a positive integer" << endl;
   }

   if (A[degree-1] ==0) {  // ÃÖ°íÂ÷Ç× °è¼ö°¡ 0ÀÏ °æ¿ì
      cout << "Leading coefficient is 0 - error in input" << endl;
      OK = false;
   }

   if (degree == 2) {  // 1Â÷½ÄÀÎ °æ¿ì
      printf("Polynomial is linear: root is %11.8f", -A[0]/A[1]);
      OK = false;
   }

   if (OK) {

      OK = true;

      //°è»êÇÒ ¼¼ Á¡À» ¹Þ¾ÆµéÀδÙ.
      cout << "Input the first of three starting values" << endl;
      scanf("%lf", &X[0]);
      cout << "Input the second of three starting values" << endl;
      scanf("%lf", &X[1]);
      cout << "Input the third starting value" << endl;
      scanf("%lf", &X[2]);
   }

   if (OK) {
      // ÁÖ¾îÁø ¼¼Á¡À» ÀÌ¿ëÇØ¼­ ¼¼ Á¡À» Áö³ª´Â ÇÔ¼öÀÇ °ªÀ» F[0]~F[2] ¿¡ ÀúÀå
      for (i=0; i<3; i++) {                       // Horner's Method ¸¦ »ç¿ë
	 F[i] = A[degree-1];
	 for (j=1; j<degree; j++)
	    F[i] = F[i] * X[i] + A[degree-j-1];
      }

      // isComplex = false ÀÌ¸é ½Ç¼ö °è»êÀ̰í, true ÀÌ¸é º¹¼Ò¼ö °è»êÀÌ´Ù.
      isComplex = false;

      H[0] = X[1] - X[0];  // H[0]Àº óÀ½ µÎÁ¡ »çÀÌÀÇ °Å¸®
      H[1] = X[2] - X[1];  // H[1]Àº ´ÙÀ½ µÎÁ¡ »çÀÌÀÇ °Å¸®
      DEL1[0] = (F[1] - F[0]) / H[0];  // óÀ½ µÎ Á¡ »çÀÌÀÇ ±â¿ï±â
      DEL1[1] = (F[2] - F[1]) / H[1];  // ³ªÁß µÎ Á¡ »çÀÌÀÇ ±â¿ï±â
      DEL = (DEL1[1] - DEL1[0]) / (H[1] + H[0]);
      // DELÀº ¼¼ Á¡¿¡¼­ ±¸ÇÑ 2Â÷Ç×ÀÇ °è¼ö(== a)

      i = 3;
      OK = true;

      while ((i++ <= num) && OK) {

	 if (isComplex == false) {  // ½Ç¼ö °è»êÀ϶§

            B = DEL1[1] + H[1] * DEL;  // B´Â ¼¼ Á¡¿¡¼­ ±¸ÇÑ 1Â÷Ç×ÀÇ °è¼ö(==b)
            D = B * B - 4.0 * F[2] * DEL;  // ÆÇº°½Ä (B==b, F[2]==c, DEL==a)

            if (D >= 0.0) {  // ÆÇº°½Ä - ½Ç±ÙÀÏ °æ¿ì

               // ±×·¡ÇÁ°¡ 1Â÷ Á÷¼±ÀÎ °æ¿ì, Áï ÃÖ°íÂ÷Ç×ÀÇ °è¼ö°¡ 0ÀÎ °æ¿ì
               if (fabs(DEL) <= ZERO) {

                  // ³ªÁß µÎ Á¡ »çÀÌÀÇ ±â¿ï±â°¡ 0ÀÏ °æ¿ì
                  if (fabs(DEL1[1]) <= ZERO) {
                     printf("Horizontal Line\n");
                     OK = false;
                  } else {  // ±â¿ï±â°¡ 0ÀÌ ¾Æ´Ò°æ¿ì
                     X[3] = (F[2]-DEL1[1]*X[2])/DEL1[1];
                     H[2] = X[3]-X[2];
                  }
               }
               else { // ±×·¡ÇÁ°¡ 1Â÷ Á÷¼±ÀÌ ¾Æ´Ñ °æ¿ì
                  D = sqrt(D);

                  E = B+D;
                  if (fabs(B-D) > fabs(E)) E = B-D;

                  H[2] = -2.0*F[2]/E;
                  X[3] = X[2]+H[2];
               }
               if (OK) {

		  F[3] = A[degree-1];  // Horner's method¸¦ »ç¿ëÇØ¼­ f(3)À» ±¸ÇÑ´Ù.
		  for (j=1; j<degree; j++)    F[3] = F[3]*X[3]+A[degree-j-1];

		  fprintf(display, "x(%d)    -> %16.14f\n", i, X[3]);
		  fprintf(display, "F(x(%d)) -> %16.14f\n\n", i, F[3]);
		
                  // Çã¿ë¿ÀÂ÷º¸´Ù ÀÛÀ» °æ¿ì °è»êÀ» ³¡³½´Ù.
		  if (fabs(H[2]) < tolerance) {
                     fprintf(display, "Results are real Number.\n");

		     fprintf(display, "\nMethod Succeeds");
                     fprintf(display, "\nApproximation -> %16.14e", X[3]);
		     fprintf(display, "\nTolerance -> %.10e", tolerance);
		     fprintf(display, "\nIterations -> %d\n", i);
                     OK = false;
                  }
                  else {
		     for (j=1; j<=2; j++) {
			H[j-1] = H[j];
			X[j-1] = X[j];
			F[j-1] = F[j];
                     }
                     X[2] = X[3];
                     F[2] = F[3];
                     DEL1[0] = DEL1[1];
                     DEL1[1] = (F[2]-F[1])/H[1];
                     DEL = (DEL1[1]-DEL1[0])/(H[1]+H[0]);
                  }
               }
            }
            else {  // ÆÇº°½Ä¿¡¼­ Çã±ÙÀÌ ³ª¿Ã °æ¿ì
	       isComplex = 1;
	       for (j=1; j<=3; j++) {

		  Z_[j-1] = complex(X[j-1], 0.0);
		  G_[j-1] = complex(F[j-1], 0.0);
               }
	       for (j=1; j<=2; j++) {
		  CDEL1_[j-1] = complex(DEL1[j-1], 0.0);
		  CH1_[j-1] = complex(H[j-1], 0.0);
               }
               CDEL_ = complex(DEL, 0.0);
            }
         }
         if ((isComplex == true) && OK) {  // Çã¼ö °è»êÀÏ °æ¿ì

            // ÃÖ°íÂ÷Ç×ÀÇ °è¼ö°¡ 0ÀÎ °æ¿ì(±×·¡ÇÁ°¡ 1Â÷ Á÷¼±)
            if ( abs(CDEL_) <= ZERO) {

               // ±â¿ï±â°¡ 0ÀÎ °æ¿ì
               if ( abs(CDEL1_[0]) <= ZERO) {
                  printf("horizontal line - complex\n");
                  OK = false;
               }
               else {  // ±â¿ï±â°¡ 0ÀÌ ¾Æ´Ñ °æ¿ì
                  printf("line - not horizontal\n");

                  E_ = CDEL1_[1] * Z_[2];
                  F_ = G_[2] - E_;
                  Z_[3] = F_ / CDEL1_[1];
                  CH1_[2] = Z_[3] - Z_[2];
               }
            }
            else {  // ÃÖ°íÂ÷Ç×ÀÌ 0ÀÌ ¾Æ´Ñ °æ¿ì(±×·¡ÇÁ°¡ 2Â÷ °î¼±)
               E_ = CH1_[1] * CDEL_;
               CB_ = CDEL1_[1] + E_;
               E_ = G_[2] * CDEL_;
               F_ = E_ * complex(4.0, 0.0);
               Q_ = CB_;
               E_ = CB_ * Q_;
               CD_ = E_ - F_;
               F_ = sqrt(CD_);

               CD_ = F_;
               CE_ = CB_ + CD_;
               F_ = CB_ - CD_;

               if (abs(F_) > abs(CE_))   CE_ = CB_ - CD_;

               E_ = G_[2] / CE_;
               CH1_[2] = E_ * complex(-2.0, 0.0);
               Z_[3] = Z_[2] + CH1_[2];
            }
            if (OK) {
	       G_[3] = complex(A[degree-1],0.0);
	       // Horner's method¸¦ »ç¿ëÇØ¼­ º¹¼Ò¼ö f(3)À» ±¸ÇÔ.

	       for (j=1; j<degree; j++) {
                  E_ = G_[3] * Z_[3];
		  G_[3] = complex(real(E_)+A[degree-j-1], imag(E_));
	       }
	
	       fprintf(display, "x(%d)    -> %16.14f %+16.14f i\n", i, real(Z_[3]), imag(Z_[3]));
	       fprintf(display, "F(x(%d)) -> %16.14f %+16.14f i\n\n",i, real(G_[3]), imag(G_[3]));

	       // Çã¿ë¿ÀÂ÷º¸´Ù ÀÛÀ» °æ¿ì °è»êÀ» ³¡³½´Ù.
	       if (abs(CH1_[2]) <= tolerance) {
                  fprintf(display, "Results are complex Number\n");

		  fprintf(display, "\nMethod Succeeds\n");
                  fprintf(display, "\nApproximation -> %16.14f %+16.14f i", real(Z_[3]), imag(Z_[3]));
		  fprintf(display, "\nTolerance -> %.10e", tolerance);
		  fprintf(display, "\nIterations -> %d\n", i);
                  OK = false;
               }
               else {
		  for (j=1; j<=2; j++) {
		     CH1_[j-1] = CH1_[j];
		     Z_[j-1] = Z_[j];
		     G_[j-1] = G_[j];
		  }

                  Z_[2] = Z_[3];
                  G_[2] = G_[3];
                  CDEL1_[0] = CDEL1_[1];
                  E_ = G_[2] - G_[1];
                  CDEL1_[1] = E_ / CH1_[1];
                  E_ = CDEL1_[1] - CDEL1_[0];
                  F_ = CH1_[1] + CH1_[0];
                  CDEL_ = E_ / F_;
               }
            }
         }
      }
      // °è»êȽ¼ö¸¸Å­ °è»êÇØµµ Çã¿ë¿ÀÂ÷º¸´Ù Ŭ °æ¿ì
      if (OK) fprintf(display, "Method failed\n");

      fclose(display);
   }
}