对于非线性方程的求解,有时候很难找到解的解析函数,所以只能才用数值求解。常见的一些非线性方程为
算法的基本原理:如果非线性方程f(x)=0,的左端函数f(x)在区间[a,b]上连续,并满足f(a)f(b)<0,则方程至少有一个实根。
基本思想:逐步缩小这个有根的区间,当这个区间减少到一定程序时,就取这个中点作为根的近似值。
如果在区间[a,b]内有多个实根,则单独利用对分法只能得到其一个实根。所以,将对分法与逐步扫描法结合使用,以便尽量搜索给定区间的实根,这种方法概括如下:
(1)从区间左端点x=a开始,以h为步长,逐步往后进行搜索。
(2)对于在搜索过程中遇到的每一个子区间[xk,xk+1], 其中,xk+1=xk+h。进行如下处理:
1.若f(xk)=0,则xk为一个实根,从xk+0.5h开始往后搜索
2.容易f(xk+1)=0,则xk+1为一个实根,从xk+1+0.5h开始搜索
3.若f(xk)f(xk+1)>0,则子区间无实根或h选的过大,放弃本子区间,从xk+1开始搜索
4.容易f(xk)f(xk+1)<0,则当前区间有实根,继续利用对分法,直到求到一个实根为止。,然后从
xk+1开始往后搜索。
代码如下:
/*二分法搜索方程的实根
*函数int dhrt(double a,double b,double h,double eps,double *x,int m,double (*f)(double))
*double a:求根区间的左端点
*double b:求根区间的右端点
*double h:搜索求根时所采用的步长
*double eps:控制的精度要求
*double* x:返回在区间[a,b]搜索到的实根。实根个数由函数值返回
*int m:在区间[a,b]内实根个数的预估值
*double (*f)(double):f(x)的迭代函数
*/
#include <iostream>
#include<cmath>
#include<iomanip>
using namespace std;
int dhrt(double a, double b, double h, double eps, double *x, int m, double(*f)(double))
{
int n = 0;
int js = 0;
double z = a; //搜素区间的中间点
double z1; //定义的搜素区间的末端
double z0; //定义的搜素区间的起始端
double y1; //用于存放z1点的函数结果
double y0; //用于存放z0点的函数结果
double y = (*f)(z); //用于存放函数z点处的函数结果
//计算过程
while ((z <= b + h / 2) && (n != m))
{
if (fabs(y)<eps) //如果值满足“精度要求eps“下的0状态
{
n = n + 1; //进行下一次查找
x[n - 1] = z; //保存节点值
z = z + h / 2.0; //变换起始区间加0.5h继续搜素
y = (*f)(z); //计算中点处的值
}
else //当中点处的值不满足精度要求的根时
{
z1 = z + h; //z1是搜素的子尾区间点
y1 = (*f)(z1); //计算子尾点区间的值
if (fabs(y1)<eps) //如果子尾区间点的值正好满足精度要求
{
n = n + 1; //则同上,保存根
x[n - 1] = z;
z = z1 + h / 2.0; //子区间起始点加0.5h
y = (*f)(z);
}
else if (y*y1>0.0) //首尾根节点的函数值为正,则表示无根,所以往后开始搜素
{
y = y1;
z = z1;
}
else //如果有根,则二分查找
{
js = 0;
while (js == 0) //立一个flag
{
if (fabs(z1 - z)<eps) //如果(z1-z)满足精度要求
{
n = n + 1;
x[n - 1] = (z1 + z) / 2.0;
z = z1 + h / 2.0; //搜素起始区间加h
y = (*f)(z);
js = 1; //flag为1
}
else //如果不满足判断要求,继续二分
{
z0 = (z1 + z) / 2.0; //计算中点处的值
y0 = (*f)(z0);
if (fabs(y0)<eps) //满足精度要求就保存,同上
{
x[n] = z0;
n = n + 1;
js = 1;
z = z0 + h / 2;
y = (*f)(z);
}
else if (y*y0<0.0) //相异有根
{
z1 = z0;
y1 = y0;
}
else //否则相同无根
{
z = z0;
y = y0;
}
}
}
}
}
}
return n;
}
double func(double x)
{
return x*x - 3 * x + 2 - exp(x);
}
int main()
{
cout << "Hello world!" << endl;
double a[5];
int n;
n = dhrt(0, 1, 0.05, 0.0000001, a, 2, func);
cout << n << endl;
cout << setprecision(8) << a[0] << " " << endl;
return 0;
}
注意一点:函数指针那个子程序是对应着不同的函数,需要自己定制!!