極値の話

今日は極値でふと考えたことを書こうと思います。

 

関数 f(x)区間 [ x_1 , x_2 ]のある値 x = x_0極値をとると考えます。

 

通常、極値をとるような xを求めるには f'(x) = 0となるような xを求めます。

 

そのような xが求められれば良いのですが、どうしても求まらない場合には方程式 f'(x) = 0の数値解を求めるのではないかと思います。(ワテクシはこの分野はあまり知らないので何とも言えないですが…)

 

方程式の数値解を求める手法は二分法やニュートン法などあります。

 

このときふと思ったのは、以下の方法でも極値をとる xの値が求まるのではないかと思いました。

 

[1]

 (x_1 , f(x_1) )を通る y = f(x)の接線

 y = f'(x_1) (x-x_1) + f(x_1)

 (x_2 , f(x_2) )を通る y = f(x)の接線

 y = f'(x_2) (x-x_2) + f(x_2)

の交点の x座標を x_3とする。

 x_3は計算できて

 x_3 = \frac{x_1 f'(x_1) - x_2 f'(x_2) + f(x_2) - f(x_1)}{f'(x_1)-f'(x_2)} 

となります。

 

[2]

 f(x_3) f(x_i) \lt 0となる i = 1 , 2と[1]と同様のことを行う。

 

繰り返していけば x_0に収束するのではないかと思いました。(収束するかどうかは検証する必要性有)

 

f:id:Akyuine:20171118220448p:plain

 

とりあえず今回はこの方法と二分法で比較してみることにしました。

 

以下が今回作成したプログラム(C言語)です。

関数は f(x) = e^{-x^2}区間 [-1 , 0.5 ] でやってみました。

 

プログラム

#include <stdio.h>

#include <stdio.h>

#include <math.h>

#define err 1e-5

double f(double x)

{

return exp(-x*x);

}


double diff(double (*func)(double),double x)

{

double h=1e-9;
return (func(x+h)-func(x))/h;

}


int count1=0;

int count2=0;

 

void bis(double (*func)(double),double a,double b)

{

double h=1e-9;

double c;


c=(a+b)/2;


if(b-a<err) {

if*1/h < 0){

printf("Local maximum: %.4f (if x = %.4f)\n",func*2/h < 0){

printf("Local maximum: %.4f (if x = %.4f)\n",func*3/(diff(func,a)-diff(func,b));


if(diff(func,a)*diff(func,c)<0){

tangent(func,a,c);

}else{

tangent(func,c,b);

}

}


int main(void)

{

double a,b;


scanf("%lf",&a);

scanf("%lf",&b);


printf("Bisection Method\n"); bis(f,a,b); printf("Tangent Method\n");

tangent(f,a,b);


return 0;

}

 

結果

 $ ./a.exe
-1
0.5
Bisection Method
Local minimum: 1.0000 (if x = -0.0000)
18 times
Tangent Method
Local maximum: 1.0000 (if x = -0.0000)
17 times

 Bisection Methodは二分法、Tangent Methodは今回の方法(テキトーに名前付けた)。

それぞれ繰り返した回数も表示させている。

 

そんなに回数に変化がないですね…

正直もっと早く収束してほしかったです…(^_^;)

 

とりあえずこの関数では収束しそうだなということはわかりました。

 

まぁこの方法、誰かやってそう、というかこの手法に名前とかついてそうなので一度調べてみようと思います。

*1:diff(func,c)-diff(func,c-h

*2:a+b)/2),(a+b)/2);

}else{

printf("Local minimum: %.4f (if x = %.4f)\n",func((a+b)/2),(a+b)/2);

}

printf("%d times\n",count1); return;

}
count1++;


if(diff(func,a)*diff(func,c)<0){

bis(func,a,c);

}else{

bis(func,c,b);

}

}


void tangent(double (*func)(double),double a,double b)

{

double h=1e-9;


if(b-a<err) {

if((diff(func,(a+b)/2)-diff(func,(a+b)/2-h

*3:a+b)/2),(a+b)/2);

}else{

printf("Local minimum: %.4f (if x = %.4f)\n",func((a+b)/2),(a+b)/2);

}

 

printf("%d times\n",count2);

 

return;

}


count2++;


double c;


c=(a*diff(func,a)-b*diff(func,b)+func(b)-func(a