三次函数求近似解
牛顿迭代法、二分法
本人大一学生,学习C语言刚刚三个月,分享一下自己学习的题目和方法,欢迎大佬们批评指正!
首先解释一下牛顿迭代法和二分法的原理:
(参考同济大学高等数学第七版上册 第三章第八节 方程的近似解)
首先根据切线的定义式,并通过近似逼近:
(
f
(
x
)
f(x)
f(x)-
f
(
x
0
f(x_0
f(x0))/(
x
−
x
0
x-x_0
x−x0)=
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=x0−f(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.同样的,二分法在实操中,需要确定端点值,使指定区间内有且仅有一个零点。
本人是某邮物联网专业学生,这也是我第一次写博客,再加上是新手,用的不太熟练,欢迎大家批评指正,一起交流学习。