计算多项式非线性方程f(x)=0的求根问题 .cpp

来自「计算多项式非线性方程f(x)=0的求根问题,本人数值分析课程设计做的一个程序,供」· C++ 代码 · 共 489 行

CPP
489
字号
/***************************实验题目:计算非线性方程f(x)=0的求根问题***********************


一:设计内容和期望
     本程序把函数f(x)在X(k) 完成二次泰勒展开,并得到一个新的迭代公式计算X(k+1),以此来计算非线性方程
     f(x)=0的根,从而改进牛顿法的计算公式,使计算精度从平方收敛达到3阶收敛(估计,尚待证明)


二:遇到的问题
    1:对于任意f(x)的输入;
	2:f(x)导数的实现;
	3:误差精度的控制;


三:根据以上问题,提出下列解决方案
    1:采用数据结构的相关知识解决输入问题,(由于受到算法限制先完成对f(x)为多项式函数的形式,其他
	    例如包含sin,cos,exp的形式有待解决);
    2:编写通用多项式求导和求值问题,以便完成新的迭代公式;
	3:控制x(k+1)与x(k)的误差(精度可手动输入控制),保证迭代数列收敛,以便达到精度为3阶收敛;
	

四:实验效果预期
    1:可手动输入多项式形式的非线性方程;
	2:可手动输入精度,迭代初值;
	3:通过与牛顿法进行对比分析,从而从实验中证明精度有所提高;
	  (例如同样的多项式非线性方程,在同样的精度下,新方法比牛顿法迭代次数少即可证明精度提高)*/






#include "stdio.h"
#include "iostream.h"
#include "stdlib.h"
#include "math.h"
#include "iomanip.h"
/**********************************
*  	常量定义
*********************************/


#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0


/**********************************
*  	类型定义
*********************************/

typedef int Status;  /* 函数返回类型   */

/*  链表结点的数据元素的数据类型定义 */

typedef struct{
  float coef;
  int expn;
} Term,LkLtElemtype;

/*  链表结点的数据类型定义 */

typedef struct LNode{
  LkLtElemtype data;         /* 说明结点的数据元素类型为上面定义的结构体类型 */
  struct LNode *next;
} LNode,*Link, *Position;


/* 链表的数据类型定义 */

typedef struct{
  Link head,tail;   /*  head指向链表的头结点,tail指向最后一个结点 */
  int len;         /* 链表的长度*/
}LinkList;

/* 定义一个多项式类型为链表类型  */

typedef LinkList Polynomial;


/********************************** 
*   对链表的操作实现
*********************************/


/* 分配由*p指向的值为e的结点,并返回OK, 若分配失败返回ERROR  */

Status MakeNode(Link *p,LkLtElemtype e){

  *p=(Link) malloc(sizeof(LNode));
  if(!(*p)) return ERROR;
  (*p)->data=e;
  (*p)->next=NULL;
  return OK;
}


/* 释放*p所指向的结点  */

void FreeNode(Link *p){
  if(!(*p)){
    free(*p);
    *p=NULL;
  }
}


/*  构造一个空的线性链表,成功返回OK,失败返回ERROR  */

Status InitList(LinkList * l){
  if(!l) return ERROR;
  l->head=(Link)malloc(sizeof(LNode));
  if(!(l->head)) return ERROR;
  l->head->next=NULL;
  l->tail=NULL;
  l->len=0;
  return OK;
}


/* 销毁线性表链表*/

Status DestroyList(LinkList * l){
  Link q=NULL;
  Link p=NULL;
  if(!l) return ERROR;
  p=l->head->next;
  while(!p){
    q=p->next;
    free(p);
    p=q;
  }
  free(l->head);
  return OK;
}

/* 已知h指向线性链表的头结点,将s所指向结点插入在第一个结点之前 */

Status InsFirst(Link head,Link s){
  if ((!head ) || (!s)) return ERROR;
  s->next=head->next;
  head->next=s;
  return OK;
}

/*  已知*p指向线性链表中的一个结点,用e更新*p所指结点中数据元素的值  */

Status SetCurElem(Link *p,LkLtElemtype e){
  if (!(*p)) return ERROR;
  (*p)->data=e;
  return OK;
}


/*  已知p指向线性链表中的一个结点,返回p所指结点中数据元素的值  */

LkLtElemtype GetCurElem(Link p){
  return p->data;
}


/* 返回线性链表中头结点的位置 */

Position GetHead(LinkList l){
   return l.head;
}

/*************************************************************
*   对多项式链表所特有的操作实现(见教材P42-43)
*************************************************************/

/*  依a的指数值小于、等于、大于b的指数值,分别返回-1,0,1 */


int cmp(Term a,Term b){
  if(a.expn<b.expn) return -1;
  if(a.expn==b.expn) return 0;
  if(a.expn>b.expn) return 1;
  return OK;
}


/* 若有序链表中存在与e满足判定函数compare()取值为0的元素,则*q批示第一个值为e的结点的位置,并返回TRUE;
*  否则*q批示第一个与e满足判定函数compare()取值>0的元素的前驱的位置,并返回FALSE
*/
Status LocateElem2(LinkList l,LkLtElemtype e,Position *q,int (*compare)(LkLtElemtype,LkLtElemtype)){
  Link p;
  Link pp;
  p=l.head;
  do{pp=p,p=p->next;}
   while(p&&(*compare)(p->data,e)<0);

  if  (!p||(*compare)(p->data,e)>0)
 {*q=pp;return FALSE;}
else  {*q=p;return TRUE;}
}

/* 输入m项的系数和指数,建立表示一元多项式的按指数有序的链表 */

void CreatePolyn(Polynomial *p,int m)
{
  Term *t;
  int i;
  Link q;
  Link s;
  Link h;
  float f;
  InitList(p);
 /* printf("Ployn length:%d\n",(*p).len);*/
  h=GetHead(*p);
 /* printf("head:%o",h);*/
  t=(Term *)malloc(sizeof(Term));
  t->coef=0.0f;
  t->expn=-1;
  SetCurElem(&h,*t);
/* printf("head:expn:%d\n",(h->data).expn);*/
  printf("请输入一元多项式f(x):(格式:系数 指数,顺序可任意)\n");
  for(i=1;i<=m;++i)
  {
    //printf("please input the %d coef:",i);
    scanf("%f",&f);
    t->coef=f;
    //printf("please input the %d expn:",i);
    scanf("%d",&(t->expn));
    if(!LocateElem2(*p,*t,&q,(*cmp))){
      if(MakeNode(&s,*t)) InsFirst(q,s);
    }
  }
}



/* 显示一个用链表表示的多项式 */


void PrintPolyn(Polynomial p){
  Link q;
  int i=1;
  float coef;
  int expn;
  q=p.head->next;
  while(q)
  {
      coef=(q->data).coef;
      expn=(q->data).expn;//cout<<coef<<"x^"<<expn<<endl;
      if(i%10==0) printf("\n");
      else
	  {
		  if(expn!=0)
		{
          if(coef>0)
		  {
            if(i==1)  printf("%3.2fx^%d",coef,expn);
            else      printf("+%3.2fx^%d",coef,expn);
          }
          else printf("%3.2fx^%d",coef,expn);
       }
       else
	   {
         if(coef>0)
		 {
            if(i==1)  printf("%3.2f",coef);
            else      printf("+%3.2f",coef);
          }
          else printf("%3.2f",coef);
		 }
	}
      
      q=q->next;
      i++;
  }
  printf("\n");
 
}


/*多项式求导函数*/

void qiudao(Polynomial *p,Polynomial pa,int m)
{
    Link q1;
	q1=pa.head->next;
	Term *t;
  //int i;
  Link q;
  Link s;
  Link h;
  
  InitList(p);
   h=GetHead(*p);
 /* printf("head:%o",h);*/
  t=(Term *)malloc(sizeof(Term));
  t->coef=0.0f;
  t->expn=-1;
  SetCurElem(&h,*t);
  while (q1)
  {
    t->coef=q1->data.coef*q1->data.expn;
    t->expn=q1->data.expn-1;
	if(t->coef!=0)
	{
       if(!LocateElem2(*p,*t,&q,(*cmp)))
	   {
         if(MakeNode(&s,*t)) InsFirst(q,s);
	   }
	}
	
	
	q1=q1->next;
  }
}

/*多项式求值*/

double qiuzhi(Polynomial p,double x)
{
	Link q;double sum=0.0;
    q=p.head->next;
	while(q)
	{
		sum=sum+q->data.coef*pow(x,q->data.expn);
		q=q->next;
	}
	return sum;
}

/*初值条件的判断*/

int czpanduan(double *x,Polynomial pa,Polynomial pb,Polynomial pc)
{
	double f,f1,f2,sq;
        f=qiuzhi(pa,*x);f1=qiuzhi(pb,*x);f2=qiuzhi(pc,*x);
        sq=f1*f1-2*f2*f;	//cout<<"sq="<<sq<<"  "<<"f1="<<f1<<"  "<<"f2="<<f2<<endl;
	if(sq>=0&&f2!=0&&f1!=0) return OK;
	else return ERROR;
	
}

/*利用新的迭代公式计算收敛数列x(k+1)*/

double xindegongshi(double x,Polynomial pa,Polynomial pb,Polynomial pc)
{
     double f,f1,f2;
	 double t,t1;    //cout<<"x="<<x;
	f=qiuzhi(pa,x);
    //printf("f(%2f)=%f\n",x,f);
      f1=qiuzhi(pb,x);
    //printf("f`(%2f)=%f\n",x,f1);
     f2=qiuzhi(pc,x);
    //printf("f``(%2f)=%f\n",x,f2);
    t=x-(f1+sqrt(f1*f1-2*f2*f))/f2;
	t1=x-(f1-sqrt(f1*f1-2*f2*f))/f2;//新的迭代公式

	//cout<<"t="<<t;cout<<"t="<<t1;
    
	if(fabs(t-x)>fabs(t1-x)) return t1;
	else return t;//通过与上一次的值比较,选择绝对值差小的作为下一次的迭代值,从而保证数列收敛
}




int xinfangfa(double x,double exp,Polynomial pa,Polynomial pb,Polynomial pc)
{ 
	
	double x1;int i=0;
	x1=xindegongshi(x,pa,pb,pc);
     if(!czpanduan(&x1,pa,pb,pc)) return ERROR;
	        cout<<"x["<<i++<<"]="<<setprecision(8)<<x<<endl;
			cout<<"x["<<i++<<"]="<<setprecision(8)<<x1<<endl;
     while (fabs(x1-x)>=exp)
	 {
		 x=x1;x1=xindegongshi(x,pa,pb,pc);
		 cout<<"x["<<i++<<"]="<<setprecision(8)<<x1<<endl;
	 }
	 return OK;
}

/*newton迭代公式*/

double gongshi(double x,Polynomial pa,Polynomial pb,Polynomial pc)
{
     double f,f1;
	 double t;   
	f=qiuzhi(pa,x);
    f1=qiuzhi(pb,x);
    t=x-f/f1;
    return t;
}


void newton(double x,double exp,Polynomial pa,Polynomial pb,Polynomial pc)
{ 
	
	double x1;int i=0;
	x1=gongshi(x,pa,pb,pc);
	        cout<<"x["<<i++<<"]="<<setprecision(8)<<x<<endl;
			cout<<"x["<<i++<<"]="<<setprecision(8)<<x1<<endl;
     while (fabs(x1-x)>=exp)
	 {
		 x=x1;x1=gongshi(x,pa,pb,pc);
		 cout<<"x["<<i++<<"]="<<setprecision(8)<<x1<<endl;
	 }
}





/*************************************************************
*               主函数
*************************************************************/

void main()
{

  Polynomial pa,pb,pc;/* 定义多项式链表pa,pa,pc分别保留原函数,一阶导函数,二阶导函数 */

  int ma; /*pa的项数*/

  double x;/*x作为初值*/
  
  double exp;/*定义精度*/
  
  /*输入多项式函数项数*/

  printf("请输入多项式函数项数:");
  scanf("%d",&ma);

  /*按指数有序构造多项式链表pa,pb,pc*/

  CreatePolyn(&pa,ma);qiudao(&pb,pa,ma);qiudao(&pc,pb,ma);

  /*显示多项式pa*/

  printf("你输入的多项式函数f(x)=");
  PrintPolyn(pa);
  
  /*显示多项式一阶和二阶导函数*/

  printf("f`(x)=");
  PrintPolyn(pb);
  printf("f``(x)=");PrintPolyn(pc);cout<<endl;

  /*输入迭代初值*/
 
  printf("现在计算f(x)=0的根,请输入一个迭代初值:");
  cin>>x;

  /*判断迭代初值是否满足要求*/
  while(1)
  {
   if(czpanduan(&x,pa,pb,pc)) break;
   else 
   {
	  printf("初值不和要求,请重新输入一个迭代初值:");
      cin>>x;
   }
  }
			  
  /*输入精度*/

  printf("请输入精度(例如1e-3,表示0.001)");
  cin>>exp;cout<<endl;

  /*利用新的迭代公式计算*/

  cout<<"利用新的迭代公式计算的收敛数列如下:"<<endl;
  while(1)
  {
	  if(xinfangfa(x,exp,pa,pb,pc)) break;
      printf("中间变量不和要求,请重新输入一个迭代初值,重新进行计算:");
      cin>>x;
  }
  cout<<endl;
     
 /*利用牛顿法的迭代公式计算*/

  cout<<"利用牛顿法的迭代公式计算的收敛数列如下:"<<endl;
  newton(x,exp,pa,pb,pc);cout<<endl;

  /*计算完毕后销毁多项式函数,释放空间*/
  DestroyList(&pa);DestroyList(&pb);DestroyList(&pc);
  
  
  cout<<"通过数据请分析该算法的优缺点,以便加以改进,谢谢!!"<<endl;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?