測試函數是-x*sin(x),求其在0~4.5上的最小值。
首先繪圖觀察一下:
fplot(@(x) -x*sin(x),[0,4.5]); hold on; fplot(@(x) -sin(x)-x*cos(x),[0,4.5]); hold off; legend('f(x)',"f'(x)"); xlabel('x');
[x,fval] = fmincon(@(x) -x*sin(x),2)
x =
2.028757520194786
fval =
-1.819705741159516
可以看到x在2附近f(x)取到最小值。
三點二次插值
下面構建三點二次插值函數:
function [p1,fval]=int2p3(f,xinterval) p0=xinterval(1); p2=xinterval(2); p1=(p0+p2)/2; while true x=[p0,p1,p2]; y=[f(p0),f(p1),f(p2)]; c=polyfit(x,y,2); p1_=-c(2)/2/c(1); if f(p1)<f(p1_) if p1<p1_ p2=p1_; else p0=p1_; end else if p1<p1_ p0=p1; p1=p1_; else p2=p1; p1=p1_; end end if p2-p0<0.001 fval=f(p1); break end end end
測試:
>> [x,fval]=int2p3(@(x) -x*sin(x),[0,4.5])
x =
2.028757824672632
fval =
-1.819705741159653
點x的迭代過程如下圖:
最後收斂到2.029。
牛頓法
function [p1,fval]=newton(f,xinterval) p0=xinterval(1); p2=xinterval(2); p1=(p0+p2)/2; d=0.001; while true p1_=(f(p1+d)-f(p1))/d;%一階導數 p1_2=(f(p1)-f(p1-d))/d; p1__=(p1_-p1_2)/d;%二階導數 p1next=p1-p1_/p1__; if abs(p1next-p1)<d fval=f(p1); break else p1=p1next; end end end
>> [x,fval]=newton(@(x) -x*sin(x),[0,4.5])
x =
2.028286879504392
fval =
-1.819705441320462