見出し画像

高校数学をプログラミングで解く(数学III編)「6-3 関数の値の変化」

割引あり

マガジンリスト > 数学Ⅲ編 6.微分法の応用 > 6-3 関数の値の変化


はじめに

今回は、数学IIIで学ぶ「関数の値の変化」について、任意の関数$${f(x)}$$の極値を求めて、その関数のグラフに極値を取る点をプロットするプログラムを作成していきます。

関数の値の変化

まず、関数の値の変化について解説しておきます。
なお、関数の値の変化については、記事『高校数学をプログラミングで解く(数学II編)「5-3 関数の値の変化」』ですでに解説していますので、そちらもご覧ください。

関数の極値

$${f(x)}$$は連続な関数とする。

極値
$${x=a}$$を含む十分小さい開区間において
「$${x \neq a}$$ならば$${f(x) < f(a)}$$」が成り立つとき $${f(a)}$$は極大値
「$${x \neq a}$$ならば$${f(x) > f(a)}$$」が成り立つとき $${f(a)}$$は極小値

極値をとるための必要条件
$${f(x)}$$が$${x=a}$$で微分可能であるとする。
$${f(x)}$$が$${x=a}$$で極値をとるならば $${f'(a)=0}$$
注意 $${f'(a)=0}$$であっても$${f(a)}$$は極値とは限らない。例:$${f(x)=x^3}$$

極大、極小の判定
$${x=a}$$の前後で
$${f'(x)}$$の符号が正から負に変わるならば $${f(a)}$$は極大値
$${f'(x)}$$の符号が負から正に変わるならば $${f(a)}$$は極小値
注意 $${x=a}$$で微分可能である必要はない。例:$${f(x)=|x|}$$ $${x=a}$$で極小

関数の極大・極小を計算する

記事『高校数学をプログラミングで解く(数学II編)「5-3 関数の値の変化」』では、3次関数に対して極大・極小を求めました。3次関数の場合、その導関数は2次関数となるので、極値を求める方程式$${f'(x)=0}$$は2次方程式となり、解と係数の関係を用いて極値の位置を求めることができました。
今回、極値を解析的に求めることが難しい場合でも対応できるような方法で、関数の極大・極小を計算することを考えます。

問題
次の関数の極値を求め、そのグラフを描き、極値をプロットせよ。

$$
y = -\frac{3x}{x^2+3}
$$

アルゴリズム設計

問題の導関数は、

$$
y' = f'(x) = \frac{3(x^2-3)}{(x^2+3)^2}
$$

となります。今回はこの導関数を利用して、以下の手順で極値を求めていきます。

① $${x}$$をグラフの描画範囲内で小さい方から動かして、$${f'(x)=0}$$を満たしていれば、そのときの$${x}$$の値が極値を取る値となります。

② その$${x}$$の値の前後の位置での導関数の値$${f'(x-e)}$$と$${f'(x+e)}$$との符号を調べることで、極値が極大値なのか、極小値なのかを決定することができます。ここで、$${e}$$は十分小さな正の数を表しています。

プログラム

それでは、任意の関数に対する極値を求め、その関数のグラフに極値を取る点をプロットするプログラムを作成します。
今回は、記事『高校数学をプログラミングで解く(数学II編)「5-3 関数の値の変化」』で作成したスケッチ「calcandplotExtrema」を再利用して作成していきます。以下の zip ファイルをダウンロードして展開または解凍してください。

そして、スケッチの名前(フォルダ名)を「calcandplotExtrema2」と変更し、またスケッチ「calcandplotExtrema2」内の「calcandplotExtrema.pde」ファイルの名前を「calcandplotExtrema2.pde」に変更します。そして、pdeファイル「calcandplotExtrema2.pde」をダブルクリックしてスケッチ「calcandplotExtrema2」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「calcandplotExtrema2」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。


float x_range = 10.0; // x軸の表示範囲 -x_rangeからx_rangeまで
float y_range = 5.0; // y軸の表示範囲 -y_rangeからy_rangeまで 

void setup(){
  size(500,500);
  noLoop();

  setAxes(x_range, y_range); // 座標軸の準備
  
  noFill();
  
  // 関数のグラフを描く
  stroke(0,0,0);  
  float x_min = -x_range;
  float x_max = x_range;
  draw_function(x_min, x_max);

  // 極値を計算してプロットする
  calc_and_plot_extrema(x_min, x_max);

}

// 関数
float f(
  float x 
){
  return -3.0*x/(x*x+3.0);
}

// 導関数
float f_prime(
  float x
){
  return 3.0*(x*x-3.0)/pow(x*x+3.0,2.0);
}

// 関数のグラフを描く関数
void draw_function(
  float x_min, // グラフの定義域の下限
  float x_max  // グラフの定義域の上限
){
  int plot_num = 2000; // グラフを描くための頂点の個数  
  
  // グラフを描画
  float x, y; // 関数の座標
  float X, Y; // キャンバス上の座標 
  beginShape();
  for(int i=1; i<plot_num; i++){
    x = x_min + (x_max - x_min) / plot_num * i; // 曲線上の点のx座標
    y = f(x); // 曲線上の点のyの値
    // キャンバス上の座標位置に換算
    X = width / 2.0 / x_range * x;
    Y = height / 2.0 / y_range * y;
    vertex(X, Y);
  }
  endShape();

}

// 極値を計算してプロットする関数
void calc_and_plot_extrema(
  float x_min, // グラフの定義域の下限
  float x_max  // グラフの定義域の上限
){
  // 極値前後の小さな区間[x-e,x+e]
  float e = 0.01;

  // 極値を求めてプロットする
  float epsilon = 0.0001;
  float dx = 0.001;
  int n = (int)((x_max-x_min)/dx);
  float x, y;
  float before_f, after_f;
  for(int i=1; i<n; i++){
    x = x_min+i*dx;
    if( abs(f_prime(x)) < epsilon ){
      y = f(x);
      before_f = f_prime(x-e);
      after_f = f_prime(x+e);
      if( before_f > 0.0 && after_f < 0.0 ){
        // 極大値であれば赤色でプロット
        stroke(255,0,0);
        println("極大値:", x, y);
      } else if(before_f < 0.0 && after_f > 0.0 ){
        // 極小値であれば青色でプロット
        stroke(0,0,255);
        println("極小値:", x, y);
      } else {
        // 極値でなければ緑色でプロット
        stroke(0,255,0);
        println("極値ではない:", x, y);
      }
      plot_extrema_point(x);      
    }
  }  
}

// 極値をプロットする関数
void plot_extrema_point(
  float x // 極値のx座標
){
  float y = f(x);
  float X, Y; // キャンバス上の座標
  // キャンバス上の座標位置に換算
  X = width / 2.0 / x_range * x;
  Y = height / 2.0 / y_range * y;
  strokeWeight(5);
  point(X, Y);
  strokeWeight(1);
}

ソースコード1 任意の関数に対する極値を求め、その関数のグラフに極値を取る点をプロットするプログラム

ソースコード1を、スケッチ「calcandplotExtrema2」の「calcandplotExtrema2」タブのテキストエディタ部分に書いて実行すると、図1のように、実行ウィンドウのキャンバス上に、問題の関数(黒色)とその関数の極大値(赤色)、極小値(青色)が描かれます。

図1 問題の関数の極大値、極小値

また、図2のように、開発環境ウィンドウのコンソールに、

極大値: -1.7319994 0.86602545
極小値: 1.7320004 -0.8660254

と、極大値、極小値の位置とその値が出力されます。

図2 スケッチ「calcandplotExtrema2」の実行結果

まとめ

今回は、数学IIIで学ぶ「関数の値の変化」について、任意の関数$${f(x)}$$の極値を求めて、その関数のグラフに極値を取る点をプロットするプログラムを作成しました。
このようなプログラムは記事『高校数学をプログラミングで解く(数学II編)「5-3 関数の値の変化」』で3次関数に対して作成していましたので、
それを再利用することで比較的簡単に作成できたのではないかと思います。極値の位置の求め方は変数$${x}$$をグラフの描画範囲で少しずつ変化させながら、条件式

$$
f'(x) = 0
$$

に代入していき、条件式が成り立てばその$${x}$$の値で極値の可能性があることがわかりますので、あとはこの$${x}$$の値の前後での導関数の値の符号が異符号であれば極値であるとして求めました。
ただ、今回作成したプログラム(ソースコード1)では1点注意が必要です。上記の導関数$${f'(x)}$$が$${0}$$と等しいという条件を厳密に成り立たせることは難しいので、プログラミングを行うときは少し条件を緩めて$${ | f'(x) | < \varepsilon}$$(ここで、$${\varepsilon}$$は十分小さい正の数)とします。実は、$${\varepsilon}$$の選び方はかなり重要になってきます。$${\varepsilon}$$の値をあまりに小さくしすぎると、条件が厳しくなりすぎて極値の位置でも極値が取れなくなってしまいますし、逆にあまり大きくしすぎると、条件が緩すぎて、本来極値でないものも極値として選択してしまう可能性があります。そのため、$${\varepsilon}$$の選び方には多少試行錯誤が必要になるかもしれません。もし余裕があれば、今回のプログラムで変数 epsilon や e 、dx などを変化させてみてどんな結果になるか試してみて下さい。きっと勉強になると思います。


読んだ感想などをお寄せください

本記事を読んだ感想や質問などを以下のお問い合せフォームからお寄せください。感想、質問をいただいた方には本記事の演習問題の解答をプレゼントします。(お問合せフォームの本文に、本記事のタイトルを入れてください。)


参考文献

改訂版 教科書傍用 スタンダード・オリジナル 数学III(数研出版、ISBN9784410209567)


演習問題

次の関数の極値を求め、そのグラフを描き、極値をプロットするプログラムを作成してください。

$$
y = \frac{\log x}{x^2+1}
$$


演習問題の解答例

ここから先は

790字 / 1画像 / 1ファイル

期間限定!PayPayで支払うと抽選でお得

この記事が気に入ったらチップで応援してみませんか?