一元非线性方程求根的算法,我们使用的是二分和迭代
二分
首先给定一个有根区间,由于是有根区间,所以端点两边的值代入原函数所得的符号会相反.然后求出中点的值,然后判断符号,取这个中点和一边区间作为新的有根区间,这样不断缩短区间的大小,最后在某一个点的左右区间小于给定的误差,那么我们就认为,这个值是该函数的值
迭代
迭代法我们使用的是牛顿迭代
头文件定义
#ifndef NONLINEAREQUATIONSOLVER_H
#define NONLINEAREQUATIONSOLVER_H
#include <string>
#include <iostream>
#include <cmath>
#include <iomanip>
#include<assert.h>
using namespace std;
class NonLinearEquationSolver
{
public:
NonLinearEquationSolver();
~NonLinearEquationSolver();
//二分法求根,参数依次为有根区间端点a、b、函数、绝对误差限
void Dichotomy(float a, float b, float(*f)(float), float e,int k);
//输出第k次二分区间的结果,参数为当前区间端点、二分次数
void ShowDichotomyProcess(float a, float b, int k,float x,float(*f)(float));
//获取浮点数的符号
//string getFloatSign(float x);
//迭代法求根,参数为迭代初值、迭代函数、绝对误差限、最大迭代次数
void Iteration(float x0, float(*f)(float), float e, int MAX,int k);
//迭牛顿代法求根,参数为迭代初值、迭代函数、绝对误差限、最大迭代次数
void NewTownIteration(float x0, float(*f)(float), float e, int MAX,int k);
//输出一次迭代的结果,参数为前一值、当前值、迭代次数
void ShowIterationProcess(float a, float b, int k);
//输出牛顿迭代
void ShowNewTownIteration(float x0,float x1,int k);
void ChordCutting(float x0,float x1, float(*f)(float), float e,int k, int MAX);
float GetDerivative(float(*f)(float), double x0);
protected:
};
#endif
具体方法的实现
#include "NonLinearEquationSolver.h"
NonLinearEquationSolver::NonLinearEquationSolver()
{
}
NonLinearEquationSolver::~NonLinearEquationSolver()
{
}
//输出迭代结果 包括区间范围 和误差
void NonLinearEquationSolver::ShowIterationProcess(float a, float b, int k)
{
cout << "k=" << setw(10) << k << " [";
cout << setw(10) << setiosflags(ios::fixed) << setprecision(4) << a << ",";
cout << setw(10) << setiosflags(ios::fixed) << setprecision(4) << b << "]";
cout << " x*=";
cout << setw(10) << setiosflags(ios::fixed) << setprecision(4) << (a+b)/2.0 << " 误差:"<<setw(10)<<(fabs(b-a)/2);
cout<<" e=";
cout << setw(10) << setiosflags(ios::fixed) << setprecision(4) << (b-a)/2.0 <<endl;
}
//二分
void NonLinearEquationSolver::Dichotomy(float a, float b, float(*f)(float), float e,int k)
{
//递归
float distance,x;
x = (a + b) / 2.0; //中点
ShowDichotomyProcess(a, b, k,x,f);
if (f(a) * f(x) < 0) //在左边 右端点左移
b = x;
else //在右边 左端点右移
a = x;
distance = fabs(b - a); //误差限
if (distance < e)
{
cout << "x* = " << x<<endl;
return;
}
Dichotomy(a, b, f, e,k+1);
}
//输出二分
void NonLinearEquationSolver::ShowDichotomyProcess(float a, float b, int k,float x,float(*f)(float))
{
cout << "k=" << setw(10) << k << " [";
cout << setw(10) << setiosflags(ios::fixed) << setprecision(5) << a << ",";
cout << setw(10) << setiosflags(ios::fixed) << setprecision(5) << b << "]";
cout<<" 中点:"<<setw(10)<<((b+a)/2);
cout<< " 精度:"<<setw(10)<<(fabs(b-a)/2);
if(f(x)>0)
cout<< " 符号:"<<setw(5)<<"+"<<endl;
else
cout<< " 符号:"<< setw(5)<<"-"<<endl;
}
//迭代法
void NonLinearEquationSolver::Iteration(float x0, float(*f)(float), float e, int MAX,int k)
{
if (k < MAX) //迭代次数
{
float x1 = f(x0);
if (fabs(x1 - x0) < e)
{
ShowNewTownIteration(x0,x1,k);
cout << "x*= " << x1 << endl;
return;
}
else
{
if (k > MAX)
{
cout << "超出最大迭代次数!" << endl;
return;
}
else
{
ShowNewTownIteration(x0,x1,k);
Iteration(x1, f, e, MAX, k+1);
}
}
}
}
//求导
float NonLinearEquationSolver::GetDerivative(float(*f)(float), double x0) //求f(x)在x0处的导数
{
float t = 0.00001;
return (f(x0 + t) - f(x0)) / t;
}
//牛顿迭代
void NonLinearEquationSolver::NewTownIteration(float x0, float(*f)(float), float e, int MAX, int k)
{
if (GetDerivative(f, x0) == 0)
{
cout << "导数为0,错误!" << endl;
return;
}
else
{
float x1 = x0 - (f(x0) / GetDerivative(f, x0));
ShowNewTownIteration(x0, x1, k+1);
if (fabs(x1 - x0) < e)
{
cout << "x*= " << x1 << endl;
return;
}
else
{
if (k > MAX)
{
cout << "超出最大迭代次数!" << endl;
return;
}
else
{
NewTownIteration(x1, f, e, MAX, k+1);
}
}
}
}
//显示 牛顿迭代
void NonLinearEquationSolver::ShowNewTownIteration(float x0, float x1, int k)
{
cout << "k = " << k<< setw(10)<<" x1 = ";
cout << setw(5) << setiosflags(ios::fixed) << setprecision(5) << x1 << ",";
cout << setw(10) <<" 误差:"<<setw(10)<<(fabs(x1-x0))<<endl;
}
//弦割法 用平均变化率取代了求导 避免了牛顿迭代对导数要求过高的缺点
void NonLinearEquationSolver::ChordCutting(float x0,float x1, float(*f)(float), float e,int k, int MAX)
{
float x = x1 - (f(x1)/(f(x1)-f(x0))*(x1-x0));
if(fabs(x-x1)<e)
{
ShowIterationProcess(x, x1, k+1);
cout<<"x* = "<<x<<endl;
return ;
}else
{
if(k>MAX)
{
cout<<"超过最大迭代!"<<endl;
exit(0);
}else
{
ShowIterationProcess(x, x1, k+1);
ChordCutting(x1,x,f,e,k+1,MAX);
}
}
}
主函数,只需要把fun1和fun2的返回改为要计算的函数即可,然后在main方法中,修改区间和误差的值,即可计算出最后结果
#include<iostream>
#include"NonLinearEquationSolver.h"
float fun1(float x) //二分法函数
{
/*
double result = x * x * x - sin(x) - 4 * x + 1;
if (result > 0)
return result;
else
return -result;
*/
//return 1-x-sin(x);
// return x*x*x-x-1;
return x * x * x - sin(x) - 4 * x + 1;
}
float fun2(float x) //迭代法函数
{
//double result = sin(x) + (4 * x) - 1;
double result = 5+2*x;
if (result > 0)
return pow(result, 1.0 / 3);
else
return (-pow(fabs(result), 1.0 / 3));
}
float fun3(float x) //牛顿迭代法函数
{
// return x - (x * x * x - sin(x) - 4 * x + 1) / (3 * x * x - cos(x) - 4);
//return (x*x*x)-(2*x)-5;
//return x - cos(x);
}
int main()
{
//非线性方程
int MAX = 30;
NonLinearEquationSolver solver;
float a = -3, b = -2, e = 0.005; //初始条件
float x0 = -2.5,x1=-0;
// cout<<"二分法:"<<endl;
solver.Dichotomy(a, b, fun1, e, 0); //二分法
// cout<<"迭代法:"<<endl;
// solver.Iteration(x0, fun3, e, MAX, 1); //迭代
// cout<<"牛顿迭代法:"<<endl;
// solver.NewTownIteration(x0, fun1, e, MAX, 0); //牛顿迭代
// solver.ChordCutting(x0,x1,fun3,e,0,40);
return 0;
}
这个是完整的项目解压包:
链接:https://pan.baidu.com/s/1gczu01rgQd9mscHCnMuPvw
提取码:jddy
OK(ゝω・´★)