智能科学数学实验任务:
使用牛顿迭代法求解一元多项式非线性方程。表达式中的多项式系数和常数皆不超过小数点后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;
}
}