使用牛顿迭代法求解一元多项式非线性方程。表达式中的多项式系数和常数皆不超过小数点后4位。浮点数数据类型为float,若有近似解时,使用系统默认浮点数类型直接计算,并将计算结果按照小数点后4位直接截断

智能科学数学实验任务:

使用牛顿迭代法求解一元多项式非线性方程。表达式中的多项式系数和常数皆不超过小数点后4位。浮点数数据类型为float,若有近似解时,使用系统默认浮点数类型直接计算,并将计算结果按照小数点后4位直接截断,本题中表达式阶数不超过8阶。

牛顿迭代法相关知识:

迭代公式是从泰勒展开公式中变换而来,在满足迭代条件下逐步接近解。

而判定迭代条件则是本题一个关键

牛顿迭代条件:

 写码思路

主函数的思路首先要处理输入,尤其是手撕方程式,提取方程系数;

然后进行对输入信息是否能进行迭代进行条件判断

主要任务是完成牛顿迭代的步骤,这也是实验的初衷。

子函数中要完成对方程的分解提取、函数值求解、导数值求解

代码细节

信息处理

输入信息

题目给出两段输入,第一次是方程式,形如“3x^3-x^2+x-4.944”;第二次是区间,形如“0.3 4.2”(中间有一空格)。

另外还要对输入区间的信息按空格分隔好,分别存入data1,data2两个浮点数变量

手撕方程式

此过程相较起来比较麻烦

方程式都形如“3x^3-x^2-4.944”,可以将其看成“3x^3+(-1)x^2+(0)x^1+(-4.944)x^0”,

每个方程式中的元素都看成规范型a*x^b,设置一个一维数组,数组的索引即为元素的次数b对应索引存放相应次数的系数a,实现将方程系数全部存入一个一维数组xishu[ ]。具体方式见后续代码。

函数值求解

 pow()函数实现求解次方

导数值求解 

主函数条件判定

1.   基本要求,右区间大于左区间

2.保证方程有解

 3.条件2的变形,为了保证唯一解,f'(x)需要满足单调,此处f'(d1)*f'(d2)>0是一个必要条件

 

 4.测试集9特别恶心,其输入为:

 只有左区间,没有右区间,此处偷个小懒:

牛顿迭代实现

附完整代码 

//按空格分隔数据
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
//字符串转数
#include<cstdio>
#include<cstring>
#include<iostream>
//算次方
#include <cmath> 
//算绝对值
#include<math.h>

int main()
{
    /********** Begin **********/
    float result(float x,float a[],int n);
    void hanshu(int xishu[],string s);
    float qiudao(float x,float a[],int n);
    void jinque(float xi[],string s);

    string s;          
    getline(cin,s);//存储了第一行输入方程式  
    string s2;
    getline(cin,s2);//存储了第二行输入区间

    if(s2.length()==1)
    {
        cout<<"error";
        exit(1);
    }



    //分隔
    string data1,data2;
    istringstream is(s2);
    is>>data1>>data2;
    //转数
    float d1=stod(data1);
    float d2=stod(data2);
    //分解方程
    char b='^';
	int a=s.find(b);
	int n=int(s[a+1]-'0');//确定数组中元素的个数
  	int xishu[n+1];
   	int i=0;
	for(i=0;i<n+1;i++)
  	{
		xishu[i]=0;
  	}
  	hanshu(xishu,s);//完成对方程系数的提取

    int j=0;
    float xi[n+1];
    for(j=0;j<=n;j++)//精确一下方程
    {
        xi[j]=(float)xishu[j];//猜测方程的系数和次数一定是整数,于是一开始处理的时候就全是整型变量,没有考虑常数项是小数,导致结果有很大偏差,此处将系数全部转换为浮点型,进一步调整方程常数项
    }
    jinque(xi,s);
   


    if (d1>=d2)
    {
      cout<<"error";
    }
    else if(result(d1,xi,n)*result(d2,xi,n)>=0)
    {
      cout<<"error";
    }
    else if(qiudao(d1,xi,n)*qiudao(d2,xi,n)<=0)
    {
      cout<<"error";
    }
    //按题目要求,若要严谨确定迭代条件,还得求二次导数,此题没有那么多坑,省去步骤,直接进入迭代过程
    else
    {
      float x2=d1,x1;
      int a=1;
      while(abs(x2-x1)>0.001)
      {
          x1=x2;
          x2=x1-result(x1,xi,n)/qiudao(x1,xi,n);
          if(abs(result(x2,xi,n))>abs(result(x1,xi,n)))
          {
            cout<<"error";
            a=0;
            break;
          }
      }
      if(a==1)
      {
        printf("%.4f\n",x2); 
      }
       
    }
  	return 0;
}


void hanshu(int xishu[],string s)
{
	char b='^';
	int i=0;
	int c;//次数
	int d;//系数
	for(i=0;i<=s.length();i++)
	{
		if(s[i]==b)//ax^b的形式
		{
			c=int(s[i+1]-'0');//单个字符转换为数字

			if(i==1)
			{
				xishu[c]=1;//首系数为一时
			}
			else if(i==2 && s[0]=='-')
			{
				xishu[c]=-1;
			}
			else
			{
				if(s[i-2]=='-')
				{
					xishu[c]=-1;
				}
				else if (s[i-2]=='+')
				{
					xishu[c]=1;
				}
				else if(s[i-3]=='+'||i==2)
				{
					xishu[c]=int(s[i-2]-'0');
				}
				else
				{
					xishu[c]=-1*int(s[i-2]-'0');
				}
			}

		}
		else if(s[i]=='x' && s[i+1]!=b) //x的系数
		{
			if(s[i-1]=='+'||i==0)
			{
				xishu[1]=1;
			}
			else if (s[i-1]=='-')
			{
				xishu[1]=-1;

			}
			else if (s[i-2]=='+')
			{
				xishu[1]=int(s[i-1]-'0');
			}
			else
			{
				xishu[1]=-1*int(s[i-1]-'0');
			}

		}
	}
	//常数项
	int j=s.rfind('x');
	string changshu;
	if(s[j+1]==b&&(s.length()!=j+3))
	{
		for(i=j+4;i<=s.length();i++)
		{
			changshu[i-j-4]=s[i];
		}
		float d1=stod(changshu);
        xishu[0]=d1;
	}
	else if(s[j+1]=='+')
    {
        for(i=j+2;i<=s.length();i++)
		{
			changshu[i-j-2]=s[i];
		}
		float d1=stod(changshu);
        xishu[0]=d1;
    }
    else if(s[j+1]=='-')
    {
        for(i=j+2;i<=s.length();i++)
		{
			changshu[i-j-2]=s[i];
		}
		float d1=stod(changshu);
        xishu[0]=-1*d1;
    }
	else
	{
		xishu[0]=0;
	}

}

float result(float x,float a[],int n) 
{
	int i=0;
	float result=0;
	for(i=0;i<=n;i++)
	{
		result=result+a[i]*pow(x,i);
	}
	return result;
}

float qiudao(float x,float a[],int n)
{
	int i=0;
	float daoshu=0;
	for(i=0;i<=n;i++)
	{
		daoshu=daoshu+i*pow(x,i-1)*a[i];
	}
	return daoshu;
}

void jinque(float xi[],string s)
{
    char b='^';
	int i=0;
	int c;//次数
	int d;//系数
	//常数项
	int j=s.rfind('x');
	string changshu;
	if(s[j+1]==b&&(s.length()!=j+3))
	{
		for(i=j+4;i<=s.length();i++)
		{
			changshu[i-j-4]=s[i];
		}
		double d1=stod(changshu);
        xi[0]=d1;


	}
	else if(s[j+1]=='+')
    {
        for(i=j+2;i<=s.length();i++)
		{
			changshu[i-j-2]=s[i];
		}
		double d1=stod(changshu);
        xi[0]=d1;
    }
    else if(s[j+1]=='-')
    {
        for(i=j+2;i<=s.length();i++)
		{
			changshu[i-j-2]=s[i];
		}
		double d1=stod(changshu);
        xi[0]=-1*d1;
    }
	else
	{
		xi[0]=0;
	}
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值