三次函数求近似解(牛顿迭代法/二分法)

三次函数求近似解

牛顿迭代法、二分法

本人大一学生,学习C语言刚刚三个月,分享一下自己学习的题目和方法,欢迎大佬们批评指正!
首先解释一下牛顿迭代法和二分法的原理:
(参考同济大学高等数学第七版上册 第三章第八节 方程的近似解)
首先根据切线的定义式,并通过近似逼近:
( f ( x ) f(x) f(x)- f ( x 0 f(x_0 f(x0))/( x − x 0 x-x_0 xx0)= f 1 ( x ) f^1(x) f1(x)
f ( x 0 f(x_0 f(x0)=0
移项得
x = x 0 − f ( x 0 ) / f 1 ( x 0 ) x=x_0-f(x_0)/f^1(x_0) x=x0f(x0)/f1(x0)
每一次的迭代都会逼近于真实解
(不明白的话可以去翻翻高数课本,各高校的教材应该都会有)
先上文件和函数库

#include<iostream>
#include<cmath>//调用pow函数 
#define EPSILON 1e-6//确定精度 
using namespace std;

再放原函数和导数的方程

//原函数 
double f(int a,int b,int c,int d,double x){
	return a*pow(x,3)+b*pow(x,2)+c*x+d;
}
//导数 
double fDerivable(int a,int b,int c,double x){
	return 3*a*pow(x,2)+2*b*x+c;
}

再来看牛顿迭代法(循环实现)

//EPSILON为事先规定的精度

double newton(int a,int b,int c,int d,double x){
	while(fabs(f(a,b,c,d,x)/(fDerivable(a,b,c,x)))>EPSILON){
		x=x-f(a,b,c,d,x)/fDerivable(a,b,c,x);
	}
	return x;
}

再送上牛顿迭代法(递归实现)

double newton2(int a,int b,int c, int d,double x){
	if(fabs(f(a,b,c,d,x)/(fDerivable(a,b,c,x)))<=EPSILON){
		return x;
	}else{
		x=x-f(a,b,c,d,x)/fDerivable(a,b,c,x);
		return newton2(a,b,c,d,x);
	}
}

再来介绍一下二分法(又称为夹逼法)

顾名思义,通过函数的连续性,利用零点定理(介值定理)找到近似解。

先来循环实现

double bi(int a,int b,int c,int d,double x1,double x2){
	//a,b,c,d为系数 x1 ,x2 为区间左右端点
	double s1=x1,s2=x2;
	while(fabs(s1-s2)>1e-6&&f(a,b,c,d,s1)!=0){
		if(f(a,b,c,d,(s1+s2)/2)*f(a,b,c,d,x1)<0){
			s2=(s1+s2)/2;//右端点左移 
		}else{
			s1=(s1+s2)/2;//左端点右移 
		}
	}
	return s1;
}

再来递归实现

double bi2(int a,int b,int c,int d,double x1,double x2)
{
	double s1=x1,s2=x2;
	double m=(s1+s2)/2;//middle
	if(f(a,b,c,d,m)==0||fabs(s1-m)<EPSILON){
		//如果正好为解 或 达到指定精度精度 
		return m;
	} else if((f(a,b,c,d,m)*f(a,b,c,d,x1))<0){
		//判断左端点与middle的函数值是否为异号 
		return bi(a,b,c,d,x1,m);
	}else{ 
		return bi(a,b,c,d,m,x2);
	}
}

最后放上全部代码

#include<iostream>
#include<cmath>//调用pow函数 
#define EPSILON 1e-6//确定精度 
using namespace std;
//原函数 
double f(int a,int b,int c,int d,double x){
	return a*pow(x,3)+b*pow(x,2)+c*x+d;
}
//导数 
double fDerivable(int a,int b,int c,double x){
	return 3*a*pow(x,2)+2*b*x+c;
}
//牛顿迭代法 
double newton(int a,int b,int c,int d,double x){
	while(fabs(f(a,b,c,d,x)/(fDerivable(a,b,c,x)))>EPSILON){
		x=x-f(a,b,c,d,x)/fDerivable(a,b,c,x);
	}
	return x;
}
double newton2(int a,int b,int c, int d,double x){
	if(fabs(f(a,b,c,d,x)/(fDerivable(a,b,c,x)))<=EPSILON){
		return x;
	}else{
		x=x-f(a,b,c,d,x)/fDerivable(a,b,c,x);
		return newton2(a,b,c,d,x);
	}
}
//二分法(循环) 
double bi(int a,int b,int c,int d,double x1,double x2){
	//a,b,c,d为系数 x1 ,x2 为区间左右端点
	double s1=x1,s2=x2;
	while(fabs(s1-s2)>1e-6&&f(a,b,c,d,s1)!=0){
		if(f(a,b,c,d,(s1+s2)/2)*f(a,b,c,d,x1)<0){
			s2=(s1+s2)/2;//右端点左移 
		}else{
			s1=(s1+s2)/2;//左端点右移 
		}
	}
	return s1;
}
//用二分法解(递归) 
double bi2(int a,int b,int c,int d,double x1,double x2)
{
	double s1=x1,s2=x2;
	double m=(s1+s2)/2;//middle
	if(f(a,b,c,d,m)==0||fabs(s1-m)<EPSILON){
		//如果正好为解 或 达到指定精度精度 
		return m;
	} else if((f(a,b,c,d,m)*f(a,b,c,d,x1))<0){
		//判断左端点与middle的函数值是否为异号 
		return bi(a,b,c,d,x1,m);
	}else{ 
		return bi(a,b,c,d,m,x2);
	}
}
int main()
{
	int a=1,b=-3,c=6,d=-1;//样例函数数据  
	cout<<"The coefficients are a="<<a<<" b="<<b<<" c="<<c<<" d="<<d<<":"<<endl;
	double x1=0,x2=1;//(0,1)区间 
	//牛顿迭代法 
	cout<<"The approximate root is: "<<newton(a,b,c,d,x1)<<endl;
	cout<<"The approximate root is: "<<newton2(a,b,c,d,x1)<<endl;
	//二分法 
	cout<<"The approximate root is: "<<bi(a,b,c,d,x1,x2)<<endl;
	cout<<"The approximate root is: "<<bi2(a,b,c,d,x1,x2)<<endl;
	return 0;
}

总结

1.在实际操作中,牛顿迭代法需要求出 f ( x ) f(x) f(x)的二阶导,画出 f ( x ) f(x) f(x)的大致图像,使指定区间内有且仅有一个零点,判断端点中哪个值为初始的 x 0 x_0 x0
2.同样的,二分法在实操中,需要确定端点值,使指定区间内有且仅有一个零点。

本人是某邮物联网专业学生,这也是我第一次写博客,再加上是新手,用的不太熟练,欢迎大家批评指正,一起交流学习。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值