计算方法-一元非线性方程求根的算法

一元非线性方程求根的算法,我们使用的是二分迭代

二分

首先给定一个有根区间,由于是有根区间,所以端点两边的值代入原函数所得的符号会相反.然后求出中点的值,然后判断符号,取这个中点和一边区间作为新的有根区间,这样不断缩短区间的大小,最后在某一个点的左右区间小于给定的误差,那么我们就认为,这个值是该函数的值

在这里插入图片描述
在这里插入图片描述

迭代

迭代法我们使用的是牛顿迭代
在这里插入图片描述
头文件定义

#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(ゝω・´★)

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一元非线性方程求根算法有很多种,下面介绍几种常见的算法: 1.二分法:将函数图像分成若干段,找到函数值正负变化的区间,然后用二分法不断缩小区间范围,直到满足精度要求为止。 2.牛顿迭代法:利用函数的导数信息,通过不断迭代逼近函数的零点。具体步骤是:选择一个初始点,计算函数在该点的导数和函数值,然后通过函数值和导数的比值得到函数的近似线性化,进而得到下一个迭代点,不断迭代直到满足精度要求为止。 3.割线法:类似于牛顿迭代法,但是用两个点之间的割线近似函数的线性化,而不是使用导数信息。具体步骤是:选择两个初始点,计算函数在这两个点的函数值,然后通过两点之间的割线近似函数的线性化,得到下一个迭代点,不断迭代直到满足精度要求为止。 4.弦截法:类似于割线法,但是每次迭代都将当前迭代点与前一个迭代点之间的弦线与x轴交点作为下一个迭代点。具体步骤是:选择两个初始点,计算函数在这两个点的函数值,然后通过两点之间的弦线与x轴交点近似函数的零点,得到下一个迭代点,不断迭代直到满足精度要求为止。 5.试位法:利用函数值的符号变化来逼近函数的零点。具体步骤是:选择两个初始点,计算函数在这两个点的函数值,找到函数值正负变化的区间,然后用插值的方法得到函数值为0的近似点,不断插值,直到满足精度要求为止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值