Newton的方法程序(在C中)循环无限运行

时间:2016-11-26 21:19:48

标签: c algorithm loops newtons-method

C中的这段代码(附在帖子中)使用Newton - Raphson method来查找特定区间内多项式的根。

对于像x^3 + x^2 + x + 1这样的多项式,此代码非常适用,但运算符对于像x^3 - 6*x^2 + 11*x - 6这样的多项式来说是无限的。也就是说,此代码适用于输入间隔中具有一个或零根的多项式,但如果存在多个根,则它将无限期地运行。

如果有人找到解决方案,请告诉我。我在代码中写了评论来引导读者,但是如果有人发现难以理解,可以在评论中提问,我会解释它。

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>

int check(float num)                          //just a function to check for  the correct input
{
    char c;
    scanf("%c",&c);

    if(isalpha((int)c))
        printf("you entered an alphabet\n");

    else
        printf("you entered a character, please retry\n");

    return 0;
}

float func(float *p,int order,double x)                     //calculates the value of the function required in the formmula in main
{
    double fc=0.0;
    int i;

    for(i=0;i<=order;i++)
    {
        fc=fc+(double)(*p)*pow(x,(double)i);
        p++;
    }

    return fc;
}

float derv(float *q,int order,double x)               //calculates the derivative of the function required in the formmula in main
{     
    double dv=0.0,i;

    for(i=1;i<=order;i++)
    {
        dv=dv+(double)(*q)*(pow(x,(double)(i-1)))*(double)i;
        q++;
    }

    return dv;
}


int main()
{
    float coeff[1000];
    int order,count=0,i,j=0;
    char ch;
    float a,b;
    double val[5];

    printf("roots of polynomial using newton and bisection method\n");
    printf("enter the order of the equation\n");

    while(scanf("%d",&order)!=1)
    {
        printf("invalid input.please retry\n");
        while(getchar()!='\n'){}          
    }     

    printf("enter the cofficients\n");

    for(i=0;i<=order;i++)
    {
        printf("for x^%d  :",order-i);
        printf("\n");

        while(scanf("%f",&coeff[i])!=1)
        {
            check(coeff[i]);
        }   
    }

    while(getchar()!='\n'){}                                 //this clears the buffer accumulated upto pressing enter

    printf("the polynomial you entered is :\n");

    for(i=0;i<=order;i++)
    {
        printf(" %fx^%d ",coeff[i],order-i);
    }

    printf("\n");

    //while(getchar()!='\n'){};

    /* fflush(stdout);
    fflush(stdin);*/

    printf("plese enter the interval domain [a,b]\n");
    printf("enter a and b:\n");
    scanf("%f %f",&a,&b);

    while(getchar()!='\n'){}

    printf("the entered interval is [%f,%f]",a,b);

    fflush(stdout);
    fflush(stdin);

    //this array is used to choose a different value of x to apply newton's formula recurcively in an interval to scan it roperly for 3 roots

    val[0]=(double)b;       
    val[1]=(double)a;
    val[2]=(double)((a+b)/2);

    double t,x=val[0],x1=0.0,roots[10];

    while(1)
    {

        t=x1;
        x1=(x-(func(&coeff[0],order,x)/derv(&coeff[0],order,x)));           //this is the newton's formula

        x=x1;

        if((fabs(t - x1))<=0.0001 && count!=0)
        {
            roots[j]=x;
            j++;
            x=val[j];   // every time a root is encountered this stores the root in roots array and runs the loop again with different value of x to find other roots
            t=0.0;
            x1=0.0;
            count=(-1);

            if(j==3)
                break;
        }

        count++;
    }

    printf("the roots are = \n");

    int p=0;

    for(j=0;j<3;j++)
    {
        if(j==0 && roots[j]>=a && roots[j]<=b)
        {
            printf("  %f  ",roots[j]);
            p++;
        }

        if(fabs(roots[j]-roots[j-1])>0.5 && j!=0 && roots[j]>=a && roots[j]<=b)
        {
            printf(" %f  ",roots[j]);
            p++;
        }
    }

    if(p==0)
        printf("Sorry,no roots are there in this interval \n");

    return 0;
}

2 个答案:

答案 0 :(得分:8)

您没有正确计算函数或导数,因为您以相反的顺序存储系数,但您并未考虑到这一点。

当您打印出公式时,您 帐户,打印order-i

printf(" %fx^%d ",coeff[i],order-i);

所以你需要在func中做同样的事情:

fc=fc+(double)(*p)*pow(x,(double)(order-i));

derv

dv=dv+(double)(*q)*(pow(x,(double)((order-i)-1)))*(double)(order-i);

它为x^3 + x^2 + x + 1这样的多项式工作的原因是因为在这个例子中所有的系数是相同的,所以如果你向前或向后读数组,它就不会有所作为。< / p>

此外,正如Johnathon Leffler在评论中所提到的,您可能需要考虑该方法无法收敛的其他原因。您可以为循环设置最大迭代次数,如果超过最大值则突破。

调试类似这样的东西的好方法(当然除了使用调试器之外)是添加一些额外的printf语句来显示正在计算的值。您可以通过在Google搜索中输入等式来检查输出,它将提供该功能的交互式图表。

答案 1 :(得分:0)

Yehh,我终于在C中编写程序来计算用户在用户输入的区间内输入的多项式的根,它给出了输出 - 根所进行的根的多重性。使用的算法是首先我们将间隔划分为度数+ 1个等间隔的数量,然后在每个间隔中应用Newton-Raphson方法来计算最大根数。当用户给出无效输入时,还包括几个检查。对于某些多项式,它可能会产生不希望的输出

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>

int check(float num)                          //just a function to check for  the correct input
{
    char c;
    scanf("%c",&c);

    if(isalpha((int)c))
        printf("\tYou entered an alphabet. Kindly, retry with valid entry\n");
    else
        printf("\tYou entered a character. Kindly, retry with valid entry\n");

    return 0;
}

char signum(float x)
{
    if (x>=0) return '+';
    else return '-';
}



double func(double *p,int degree,double x)                     //calculates the value of the function required in the formmula in main
{
  double fc=0.0;
  int i;

  for(i=0;i<=degree;i++)
  {
    fc=fc+(*p)*pow(x,degree-i);
    p++;
  }

  return fc;
}


int fact(int n)
{
  if (n>0) return n*fact(n-1);
  else return 1;
}



double D(int k,int a,double x)               //calculates the derivative of the function required in the formmula in main
{
  if(x!=0 && a>=k)  return fact(a)*pow(x,a-k)/fact(a-k);
  else return 0;  
}


double derv(double *q,int degree,double x,int order)               //calculates the derivative of the function required in the formmula in main
{
  double dv=0.0;
  int i;
  for(i=0;i<=degree;i++)
  {
    dv=dv+(*q)*D(order,degree-i,x);
    q++;
  }
  return dv;
}



int main()
{
    double coeff[1000],t,x1=0.0,roots[100];
    int degree=-1,count=0,i,j=0,k,l=0,flag=1;
    char ch;
    float a,b;
    coeff[0]=0;
    printf("\t**This Programme helps you find roots of a polynomial using a manipulated version of Newton-Raphson Method in a real interval [a,b]**\n");


    while (degree<0)
    {
        printf("\tEnter a NON-NEGATIVE INTEGRAL value for the DEGREE of the polynomial: ");
        while(scanf("%d",&degree)!=1)
        {
            printf("\tInvalid Entry. Kindly, retry with valid entry: ");
            while(getchar()!='\n'){}
        }
}

int w[degree];
printf("\tEnter the coefficients...\n");

while(coeff[0]==0 && degree!=0)
{
    printf("\t-->for x^%d (Remember that this coefficient cannot be zero since degree is %d): ", degree,degree);
    while(scanf("%lf",&coeff[0])!=1)
    {
        check(coeff[0]);
    }
}

if (degree==0)
{
    printf("\t-->for x^%d: ",0);
    while(scanf("%lf",&coeff[0])!=1)
    {
        check(coeff[0]);
    }
}

for(i=1;i<=degree;i++)
{
    printf("\t-->for x^%d: ",degree-i);
    while(scanf("%lf",&coeff[i])!=1)
    {
        check(coeff[i]);
    }
}

  while(getchar()!='\n'){}                                 //this clears the buffer accumulated upto pressing enter
    printf("\tThe input polynomial is:\n");
  printf("\t");
  for(i=0;i<=degree;i++)
  {
    printf("%c %.2fx^%d ",signum(coeff[i]),fabs(coeff[i]),degree-i);
  }

  printf("\n");
  //while(getchar()!='\n'){};

  /* fflush(stdout);
  fflush(stdin);*/
  printf("\tFor the interval domain [a,b]; enter 'a' followed by 'b': ");
  scanf("%f %f",&a,&b);


  while(getchar()!='\n'){}
    printf("\tSo, you entered [%f,%f].\n",a,b);
  //while(getchar()!='\n'){}
  fflush(stdout);
  fflush(stdin);


  double d=(b-a)/(degree+1), val[degree+2],x=a;
  for (k = 0; k<=degree+1; k++)
  {
    val[k]= a+d*k;
  //    printf("%lf\t", val[k]);
  }

  while(l<(degree+2))
  {

    if(derv(&coeff[0],degree,x,1)<=0.00001)
    {
        if(func(&coeff[0],degree,x)<=0.00001)
        {
            w[j]=2;
            roots[j]=x;
        //printf("Axk before %f\n", x);
            j++;
        //  printf("jC is %d\n", j);
            l++;
            x=val[l];   // every time a root is encountered this stores the root in roots array and runs the loop again with different value of x to find other roots
         //printf("Axk after %f\n", x);
            t=0.0;
            x1=0.0;
            count=(-1);
        }
        else
        {
            t=0.0;
            x1=0.0;
            count=(-1);
            l++;
          //printf("Bxk before%f\n", x);
            x=val[l];
          //  printf("Bxk after%f\n", x);
        }
    }
       else
       {
          t=x1;
          x1=(x-(func(&coeff[0],degree,x)/derv(&coeff[0],degree,x,1)));           //this is the newton's formula
       // printf("jB is %d\n", j);
          //printf("Cxk before%f\n", x);
          x=x1;
          //printf("f %f\td %f\tCxk after%f\tc %i\n",func(&coeff[0],degree,x), derv(&coeff[0],degree,x,1), x,count);
          if(count>500)
          {

            if(j>degree)
                break;
              printf("\tPolynomial started to diverge. So, no roots can be found\n");
            l++;
            //printf("Dxk before %f\n", x);
            x=val[l];
            //printf("Dxk after %f\n", x);
            t=0.0;
            x1=0.0;
            count=(-1);

          }     
          if((fabs(t - x1))<=0.00001 && count!=0)
          {
            w[j]=1;
            if(j>degree)
                break;  

            roots[j]=x;

            j++;
            l++;
        //  printf("jC is %d\n", j);
            x=val[l];   // every time a root is encountered this stores the root in roots array and runs the loop again with different value of x to find other roots
         //printf("Exk after%f\n", x);
            t=0.0;
            x1=0.0;
            count=(-1);
            flag=0;
            if(derv(&coeff[0],degree,x,1)<=0.00001) w[j]=2;
            else w[j]=1;
           }
           count++;
       } 
   }

   if(flag==0)
   {
    printf("\tThe roots are = \t");
     // int p=0;
    for(j=0;j<degree;j++)
    {

        if(j==0 && roots[0]>=a && roots[0]<=b)
        {
            printf(" %d %f\n", w[0], roots[0]);
       //p++;
        }

        if(fabs(roots[j]-roots[j-1])>0.001 && j!=0 && roots[j]>=a && roots[j]<=b)
        {
            printf(" %d %f\n", w[j], roots[j]);
       //p++;
        }


    }
   } 
   else
    printf("\tNo roots found in the interval you entered.\n");

   return 0;

}
相关问题