要求:
编程实现:1.成功失败法找到存在局部极小值的区间[a,b]
2.在该区间内用0.618法找到局部极小值点,精确度为0.01
测试函数为:函数f(x)=x^4+x^3-x^2+1;
成功失败法找到区间[a,b]:
1.取x,步长l>0,令k=0,若f(x+l)<=f(x),转3.否则,令l=-l,转2;
首先选取点x,和步长l,判断f(x+l)是否小于等于f(x),若是,则证明现在朝着函数值下降的方向移动,若不是,证明现在朝着函数值上升的方向移动,这样不能找到局部极小值,所以改变移动方向,令l=-l;
2.若f(x+l)<=f(x),转3,否则,转4.
判断f(x+l)是否小于等于f(x),若是,则证明现在朝着函数值下降的方向移动,转3继续沿此方向移动,否则,证明已经找到一个区间,在该区间内存在局部极小值,转4,找到该区间。
3.更新x,l和k的值,令x=x+l,l=l*2,k=k+1,转2.
若现在朝着函数值下降的方向移动,则继续向此方向移动,更新x的值,令x=x+1,步长变为原来的2倍,l=l*2,转2继续判断。
4.若k=0,则令a=x+l,b=x-l。若k>0,则令a = x-l/2,b = x+l;
若k=0,则说明x已经在含极小值点的区间内了,即在第一步确定过x之后,不管朝着l方向走还是-l方向走,得到的函数值都比x点处的函数值大,此时便找到存在局部极小值的区间[x+l,x-l].若k>0,说明找到该区间时,至少朝着同一个方向走了两次,及l至少更新了一次,所以此时找到的区间为[x-l/2,x+l](或者{[x+l,x-l/2])
找到存在一个局部极小值的区间之后,在该区间内用0.618黄金分割法求出该区间内的局部极小值
0.618法找到局部极小值:
1.取n=a+0.618*(b-a),m=a+(b-n)。令r=f(m),g=f(n)。
第一步从区间[a,b]内找出符合0.618比例的两个点m,n,求出其函数值。
2.若r>g,转3,否则,转4.
判断m和n两点处的函数值大小。
3.令a=m,m=n,r=g,n=b-(m-a),g=f(n) 转5
如果m点的函数值大于n点的函数值,则在区间[a,m]不可能存在极小值点,故丢掉[a,m]部分,令原来的m点为新的a点,原来的n点为新的m点,根据0.618的比例找出新的n点,同时函数值r和g的值也相应的更新。
4.令b=n,n=m,g=r,m=a+(b-n),r=f(m),转5
如果m点的函数值小于n点的函数值,则在区间[n,b]内不可能存在极小值点,故丢掉[n,b]部分,令原来的n点为新的b点,原来的m点为新的n点,根据0.618的比例找出新的m点,同时相应的更新r和g的函数值。
5.若|b-a|<0.01,则找到局部极小值点(a+b)/2。否则,转2,进行继续循环直到满足所需的精度值,找到局部极小值点。
程序实现:
#include <stdio.h> #include <stdlib.h> #include <math.h> double f(double x){ double y; y = pow(x,4)+pow(x,3)-pow(x,2)+1; return y; } int main () { double x=0,l=0.5; double a,b,c; double m,n,r,g; int k = 0; if(f(x+l)<=f(x)){ x=x+l; l=l*2; k=k+1; } else l=-l; while(1){ if(f(x+l)<=f(x)){ x=x+l; l=l*2; k=k+1; } else{ break; } } if(k == 0){ a = x+l; b = x-l; } else{ a = x-l/2; b = x+l; } if(a>b){ c=a; a=b; b=c; }//成功失败法完成,找到区间[a,b],[a,b]区间内存在局部极小值 //0.618法 n = a+0.618*(b-a); m = a+(b-n); r=f(m); g=f(n); do{ if(r>g){ a=m; m=n; r=g; n=b-(m-a); g=f(n); } else{ b=n; n=m; g=r; m=a+(b-n); r=f(m); } }while(abs(b-a)>=0.01); printf("局部极小值为:%f\n",(a+b)/2); system("pause"); return 0; }