已知某非线性方程(常为n方多项式),手动计算难以求解。因此,我们利用计算机擅长繁冗大量计算的特点,将其转换为程序,计算机执行即可。
首先,二分法的求解是我们常用的方法之一。
二分法的定义:
对于区间[a,b]上连续不断且f(a)·f(b)<0的函数y=f(x),通过不断地把函数f(x)的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法。(来自百度)
代码实现:
#include<iostream>
#include<cmath>
using namespace std;
double f(float x)
// f(x) 函数体 以2倍的x的三次方减去4倍的x的二次方加3倍的x减6 为例
//返回函数值
{
double y = 2*x*x*x - 4*x*x + 3*x - 6;
return y;
}
//主函数
int main()
{
float x1 = -10.0;
float x2 = 10.0;
float mid , f1 , fmid;
//定义 x1 与 x2 的中间值mid 与其对应的函数值 fmid
//定义 x1 对应的函数值 f1
if(f(x1)*f(x2)>0)
{
printf("不一定有根");
return 0;
}
//如果选取的两个点不相等的话 即为有大于等于0.000001的空隙
while(fabs(x1-x2)>=0.000001)
{
mid=(x1+x2)/2;
f1=f(x1);
fmid=f(mid);
if(fmid==0) break;
//中间值恰好为根
else if(f1*fmid<0) x2=mid;
//f1与fmid异号 则用mid代替x2
else x1=mid;
//否则即为x2的函数值与fmid异号 则用mid代替x1
}
printf("%6.6f",(x1+x2)/2);
return 0;
}
可以看到,二分法主要借助一中间变量以及其函数值来判断是否是根。
其次推广到三分法。
三分法是基于二分法的概念,将间隔平均分为三份。
代码实现:
#include<iostream>
#include<cmath>
using namespace std;
double f(float x)
{
double y = 2*x*x*x - 4*x*x + 3*x - 6;
return y;
}
int main()
{
float a,b,h,fa,f1,f2,fb,t1,t2;
a = -10,b = 10;
if(f(a)*f(b)>0)
{
printf("不一定有根");
return 0;
}
while(fabs(a-b)>=0.000001)
{
h = fabs(b-a)/3;
t1 = a+h;
t2 = a+2*h;
fa = f(a);
fb = f(b);
f1 = f(t1);
f2 = f(t2);
if(f1==0)
{
printf("%.6f",t1);
break;
}
else if(f2==0)
{
printf("%.6f",t2);
break;
}
else if(fa == 0)
{
printf("%.6f",a);
break;
}
//if(f1 == 0) printf("%.6f",t1);
//if(f2 == 0) printf("%.6f",t2);
else if(fb == 0)
{
printf("%.6f",b);
break;
}
if(fa*f1<0)
b=t1;
else if(fa*f2<0)
b=t2;
else if(fb*f2<0)
a=t2;
else if(fb*f1<0)
a=f1;
else
{
a=t1;
b=t2;
}
}
return 0;
}
三分法代码的bug是在找h的时候,应该用后面的减去前面的,取绝对值除以三才是三等分,和二分不一样,因为你得考虑符号问题:就是那个 ( -10 + 10) 的话就是 0,你的 h 就变成 0 了不管a与b怎么加减都是不变的,然后导致循环一直进行没有停止,也就没有输出。
再有就是,后面的情况考虑全面,加上 a b 现在一共有四个点,考虑t1 t2 (判断顺序换了应该也没问题,情况全面就可以乐)。
最后就是输出,要是三分法就不能直接输出(a+b)/3了,因为你不知道实在哪个三分点,所以直接在循环里面判断完接着输出就好乐。
希望能帮到大家。