【工程優化】一維搜尋方法
阿新 • • 發佈:2019-02-08
一維搜尋方法的分類如下:
這篇文章主要講解黃金分割法、二分法、牛頓法這三種一維搜尋方法。黃金分割法只用到原函式,二分法用到函式的一階導,牛頓法用到函式的二階導。由於本文主要對研一上學期的課程中的部分演算法進行程式實現,理論部分大多參考上課的課件。黃金分割法
基本概念:演算法思想:
演算法流程圖及優缺點如下:
二分法
基本思想:牛頓法
基本思想:演算法流程圖:
具體實現:
下面我們通過程式具體實現,在程式中,我們設定原函式都是f(x)=sinx/x,搜尋區間都是[0,1],牛頓法中假設初始值設為1,具體程式如下所示:#include<stdio.h> #include<math.h> /********************函式的定義、一階導、二階導的模組 BEGIN*************************/ /*****************************\ 輸入:x為自變數 輸出:x自變數對應的函式值 \*****************************/ double Function(double x) { return (x-0.5)*(x-0.5);//這裡填寫函式式f(x),根據自己的函式修改 } /*****************************\ 輸入:x為自變數 輸出:x自變數對應的一階導數值 \*****************************/ double Derivative(double x)//求函式的一階導數 { double eps=0.0000001;//精度控制 double dx=0.5;//設定初始的間隔,太大需要迭代多次,太小缺乏精度 double dy=Function(x+dx)-Function(x);//函式值的增量 double dd1=dy/dx;//導數 double dd2=0;//dx變化時的導數 dx=dx/2;//不斷地減少x的增量 dy=Function(x)-Function(x+dx); dd2=dy/dx;//計算新的導數值 while(abs(dd1-dd2)>eps)//當相鄰兩次的導數值小於精度時終止迭代,得到導數 { dd1=dd2; dx=dx/2.0; dy=Function(x+dx)-Function(x); dd2=dy/dx; } return dd2; } //求函式的2階導數,與求一階導數的原理一樣,只需要把求函式值的函式Function換成求一階導數的函式Derivative /*****************************\ 輸入:x為自變數 輸出:x自變數對應的二階導數值 \*****************************/ double Derivative2(double x) { double eps=0.00000001; double dx=0.5; double dy=Derivative(x+dx)-Derivative(x); double dd1=dy/dx; double dd2=0; dx=dx/2; dy=Derivative(x)-Derivative(x+dx); dd2=dy/dx; while(abs(dd1-dd2)>eps) { dd1=dd2; dx=dx/2.0; dy=Derivative(x+dx)-Derivative(x); dd2=dy/dx; } return dd2; } /********************函式的定義、一階導、二階導的模組 END*************************/ /******************************************\ 輸入:a,b為區間的上下限,n為最大的迭代次數 輸出:列印函式最小值及對應的自變數x \******************************************/ void GoldenSection(double a,double b,int n)//黃金分割法 { double l=a+0.382*(b-a); double h=a+0.618*(b-a); double region=b-a; double fl; double fh; int num=1;//迭代次數 while(region>0.0000000001&&num<n) { fl=Function(l); fh=Function(h); if(fl>fh) { a=l; l=h; h=a+0.618*(b-a); } else { b=h; h=l; l=a+0.382*(b-a); } num++; region=abs(b-a); } if(num==n) printf("找不到最小值"); else { printf("黃金分割法:x=%f時,最小值f(x)=%f",(a+b)/2,Function((a+b)/2)); } } /******************************************\ 輸入:a,b為區間的上下限 輸出:列印函式最小值及對應的自變數x \******************************************/ void Dichotomy(double a,double b)//二分法 { double eps=0.0000001; double x=(a+b)/2; double region=b-a; double fxDerivative= Derivative(x); while(region>0.0000001&&abs(fxDerivative)>eps) { fxDerivative= Derivative(x); if(fxDerivative>eps) b=x; if(fxDerivative<-eps) a=x; x=(a+b)/2; region=abs(b-a); } printf("\n\n二分法:x=%f時,f(x)=%f\n",x,Function(x)); } /******************************************\ 輸入:a,b為區間的上下限,x1是初始值 輸出:列印函式最小值及對應的自變數x \******************************************/ void Newton(double a,double b,double x1) { double eps=0.0000001; double x=x1; double d1=Derivative(x1);//一階導 double d2;//二階導 while(abs(d1)>eps) { d2=Derivative2(x); if(d2<0) printf("二階導小於0,無法求解"); else { x=x-d1/d2;//x迭代公式 d1=Derivative(x); } } printf("\n牛頓法:x=%f時,f(x)=%f\n\n",x,Function(x)); } void main() { GoldenSection(0,1,100000);//黃金分割法 Dichotomy(0,1);//二分法 Newton(0,1,1);//牛頓法 }
執行結果如下圖:
作者:nineheadedbird