方程求根的几种数值方法--求解x^3 - x -1 = 0
求非线性方程的根主要有基本的二分法、迭代法。迭代法中设计到对于基本迭代算法的改进:Aitken加速法,牛顿迭代法。
首先初始工作,函数的构造
//简单迭代函数构造
double CFunction(double x)
{
x = x + 1;
double y = pow(x, 0.3333333); //计算机中没有1/3和0这样的数,用近似数代替
return y;
}
//Aitken迭代函数构造
double CFunction_1(double x)
{
double y = x * x;
y = y * x - 1;
return y;
}
//二分法函数构造
double tFunction(double x)
{
double y = x * x;
y = y * x - x - 1;
return y;
}
//判断区间有无根,只适用于区间较小时,和特定函数
double JuRoot(double tFunction(double x), double a, double b)
{
return tFunction(a) * tFunction(b);
}
double ReturnJust(double tFunction(double x), double upper, double below)
{
double result = 0;
if((result = JuRoot(tFunction, upper, below)) > 1E-6)
return 0;
else
return 1;
}
二分法的基本思想:一分为二,舍去不满足条件的部门,这个条件便是零点定理。
算法实现:E1:f(x_1) * f( x_2) <0,是,转到E2;否则无解
E2:middle = (x_1+x_2)/2,分别判断左右两支是否满足E1,满足跳转E3
E3:x_? = middle,赋值满足的一方,跳转E1
代码实现如下:
//二分法设计
double FindRoot(double tFunction(double x), double &upper, double &below)
{
double result = 0;
if((result = ReturnJust(tFunction, upper, below)) == 0)
{
cout << "嘿,没有搞错吧,居然没有根" << endl;
return 0;
}
double middle = (upper + below) / 2;
if(abs(upper - below) > 1E-6)
{
if((result = JuRoot(tFunction, upper, middle)) < 1E-6)
{
below = middle;
count ++;
return FindRoot(tFunction, upper, below);
}
else
{
upper = middle;
count ++;
return FindRoot(tFunction, upper, below);
}
}
return upper;
}
简单迭代算法的思想:将f(x)=0,改写成x=g(x)的形式。然后在区间[a,b]上任取一点x_0,求得x_1 = g(x_0),一直迭代下去,x_k+1 = g(x_k).由极限的思想可知,当x_k+1收敛到x*时,则g(x)收敛到g(x*)。当然在选取x_0的时候可以 用二分法算出大致的根,进行迭代更好。
对于简单迭代,构造函数时要使得函数的一阶导数递减,否则容易导致发散,而找不到所要的根。
//简单迭代
double FindRoot_2(double CFunction(double x), double upper, double below, double &x)
{
double result = 0;
if((result = ReturnJust(tFunction, upper, below)) == 0)
{
cout << "嘿,没有搞错吧,居然没有根" << endl;
return 0;
}
double i = CFunction(x);
if(abs(i - x) > 1E-6)
{
x = i;
count ++;
return FindRoot_2(CFunction, upper, below, x);
}
else
return x;
cout << "真不巧,这里找不到你想要精度的根" << endl;
return 0;
}
Aitken加速法是简单迭代算法的加速,迭代公式:
(1)x_k+1 = g(x_k);
(2)x_k+2 = g(x_k+1)
(3)x = x_k+2 - (x_k+2 - x_k+1)^2/(x_k+2 -2*x_k+1 + x_k)
//AITKEN迭代
double FindRoot_3(double CFunction_1(double x), double upper, double below, double &x)
{
double result = 0;
if((result = ReturnJust(tFunction, upper, below)) == 0)
{
cout << "嘿,没有搞错吧,居然没有根" << endl;
return 0;
}
double x_1, x_2, x_3, i, j;
x_1 = CFunction_1(x);
x_2 = CFunction_1(x_1);
i = (x_2 - x_1) * (x_2 - x_1);
j = (x_2 - 2 * x_1 + x);
x_3 = x_2 - (i / j);
if(abs(x_3 - x_2) > 1E-6)
{
x = x_3;
//cout << x_1 << endl;
count ++;
return FindRoot_3(CFunction_1, upper, below, x);
}
else
return x;
cout << "真不巧,这里找不到你想要精度的根" << endl;
return 0;
}
牛顿迭代思想:g(x) = x - f(x)/f'(x),利用的是函数在某点的切线与x轴的交点近似代替函数与x轴的交点.
其中变形有:弦割法,牛顿下山法,抛物线法
#include
#include
double s(double t)
{
return t-(t*t*t-t-1)/(3*t*t-1);
}
using namespace std;
int main()
{
int i;
double x,x0,x1,x2,e;
cout<<"请输入迭代初始值x0"<<",和控制精度e"<>x0>>e;
i=0;
x1=x0;
while(fabs(s(x1)-x1)>e)
{
i++;
x2=s(x1);
x1=x2;
}
x=(x1+x2)/2;
cout<<"近似根x="<
#include
#include
double s(double t)
{
return t*t*t-t-1;
}
using namespace std;
int main()
{
int i;
double x,x0,x1,x2,e;
cout<<"请输入迭代初始值x0,x1"<<",和控制精度e"<>x0>>x1>>e;
i=0;
while(fabs(x1-x0)>e)
{
i++;
x2=x1-s(x1)*(x1-x0)/(s(x1)-s(x0));
x0=x1;
x1=x2;
}
x=(x1+x2)/2;
cout<<"近似根x="<