高校数学をプログラミングで解く(数学III編)「6-1 接線と法線」
マガジンリスト > 数学Ⅲ編 6.微分法の応用 > 6-1 接線と法線
はじめに
今回は、数学IIIで学ぶ「接線と法線」について、方程式$${F(x,y)=0}$$で定めれらる関数や媒介変数で表された関数で表される曲線に対する接線や法線を求めて、それらを図示することを考えていきます。
接線と法線
まず、接線、法線の方程式について解説しておきます。
なお、接線と法線については、記事『高校数学をプログラミングで解く(数学II編)「5-2 接線」』でも解説していますので、そちらもご覧ください。
接線、法線の方程式
曲線$${y=f(x)}$$上の点$${(a, f(a))}$$における接線、法線(接点で接線に垂直)
① 接線の方程式
$$
y-f(a) = f'(a)(x-a)
$$
② 法線の方程式
$${f'(a) \neq 0 }$$のとき
$$
y-f(a) = -\frac{1}{f'(a)} (x-a)
$$
$${f'(a) = 0}$$のとき
$$
x = a
$$
関数のいろいろな表し方と導関数
記事『高校数学をプログラミングで解く(数学II編)「5-2 接線」』では、2次関数や3次関数のように、$${y=f(x)}$$という形をした曲線の式に対して接線や法線の方程式を求めました。今回、$${y=f(x)}$$のような形になっていないような曲線、つまり、方程式$${F(x,y)=0}$$で定められる関数や媒介変数で表された関数などを扱います。そのような関数で表される曲線に対して接線や法線の方程式を求めるにあたり、知っておいた方がよい、導関数の導出の仕方をまとめておきます。
方程式 F(x,y)=0 で定められる関数の導関数
両辺を$${x}$$について微分し、$${dy/dx}$$を求める。
$$
\frac{d}{dx} f(y) = \frac{d}{dy}f(y) \cdot \frac{dy}{dx}
$$
を利用する。
例:円の方程式$${F(x,y) = x^2+y^2-a^2 = 0}$$の場合
両辺を$${x}$$で微分すると、
$$
2x +\frac{d}{dx} y^2 = 0
$$
$$
2x + 2y \frac{dy}{dx} = 0
$$
となるので、$${dy/dx}$$は
$$
\frac{dy}{dx} = -\frac{x}{y}
$$
となります。
媒介変数で表された関数の導関数
$${x=f(t), y=g(t)}$$のとき
$$
\frac{dy}{dx} = \frac{ \frac{dy}{dt} }{ \frac{dx}{dt} } = \frac{ g'(t) } { f'(t) }
$$
方程式 F(x,y)=0 で定められる関数の接線と法線
それではまず、方程式$${F(x,y)=0}$$で定められる曲線上の点での接線と法線を描くことを考えてみます。
問題1
次の曲線上の点$${\mathrm{A}}$$における接線と法線の方程式を求め、$${xy}$$平面上に図示せよ。
$$
3 x^2 + y^2 = 12 \ \ \ \ \ \ \mathrm{A} (1,-3)
$$
アルゴリズム設計
今回の問題は、関数$${F(x,y)=0}$$上の点$${\mathrm{A}}$$での微分係数を求めることができれば、上記で定義した接線の方程式や法線の方程式をそのまま利用して描いていくことができますので、その微分係数を求めてみます。
$${F(x,y) = 3x^2+y^2-12 = 0}$$として、両辺を$${x}$$で微分すると、
$$
6x + \frac{d}{dx} y^2 = 0
$$
が得られます。次に、
$$
\frac{d}{dx} y^2 = 2y \frac{dy}{dx}
$$
を利用すると、
$$
6x + 2y \frac{dy}{dx} = 0
$$
すなわち、
$$
f'(x) = \frac{dy}{dx} = -\frac{3x}{y}
$$
が得られます。
プログラム
それでは、方程式$${F(x,y)=0}$$で定められる曲線上の点での接線と法線を描くプログラムを作成していきます。
今回は、記事『高校数学をプログラミングで解く(数学II編)「5-2 接線」』で作成したスケッチ「drawTangentialLine」を再利用して作成していきます。以下の zip ファイルをダウンロードして展開または解凍してください。
そして、スケッチの名前(フォルダ名)を「drawTangentialLine_F」と変更し、またスケッチ「drawTangentialLine_F」内の「drawTangentialLine.pde」ファイルの名前を「drawTangentialLine_F.pde」に変更します。そして、pdeファイル「drawTangentialLine_F.pde」をダブルクリックしてスケッチ「drawTangentialLine_F」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「drawTangentialLine_F」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。
float x_range = 10.0; // x軸の表示範囲 -x_rangeからx_rangeまで
float y_range = 10.0; // y軸の表示範囲 -y_rangeからy_rangeまで
void setup(){
size(500,500);
noLoop();
setAxes(x_range, y_range); // 座標軸の準備
noFill();
float x_min = -x_range;
float x_max = x_range;
// 楕円を描く
stroke(0,0,0);
float e_width = 2.0*2.0; // 楕円の幅
float e_height = 2.0*2.0*sqrt(3.0); // 楕円の高さ
draw_ellipse(e_width, e_height);
// 接点をプロットする
float ax = 1.0; // 接点のx座標
float ay = -3.0; // 接点のy座標
stroke(0,255,0);
plot_contact_point(ax,ay);
// 接線を描く
stroke(255,0,0);
draw_tangential_line(ax,ay,x_min,x_max);
// 法線を描く
stroke(0,0,255);
draw_normal_line(ax,ay,x_min,x_max);
}
// 曲線の導関数
float f_prime(
float x,
float y
){
return -3.0*x/y;
}
// 楕円を描く関数
void draw_ellipse(
float e_width, // 楕円の幅
float e_height // 楕円の高さ
){
float W, H; // キャンバス上の座標
W = width / 2.0 / x_range * e_width;
H = height / 2.0 / y_range * e_height;
ellipse(0.0,0.0,W,H);
}
// 接点をプロットする関数
void plot_contact_point(
float ax, // 接点のx座標
float ay // 接点のy座標
){
float X, Y; // キャンバス上の座標
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * ax;
Y = height / 2.0 / y_range * ay;
strokeWeight(5);
point(X, Y);
strokeWeight(1);
}
// 接線を描く関数
void draw_tangential_line(
float ax, // 接点のx座標
float ay, // 接点のy座標
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_prime(ax,ay) * (x-ax) + ay; // 接線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
// 法線を描く関数
void draw_normal_line(
float ax, // 接点のx座標
float ay, // 接点のy座標
float x_min, // グラフの定義域の下限
float x_max // グラフの定義域の上限
){
int plot_num = 2000; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
if( f_prime(ax,ay) == 0.0 ){
X = width / 2.0 / x_range * ax;
line(X, -height/2.0, X, height/2.0);
} else {
beginShape();
for(int i=1; i<plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 接線上の点のx座標
y = - 1.0 / f_prime(ax,ay) * (x-ax) + ay; // 接線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
}
ソースコード1 方程式$${F(x,y)=0}$$で定められる曲線上の点での接線と法線を描くプログラム
ソースコード1で、関数$${F(x,y)=0}$$の導関数を f_prime 関数として準備しています。記事『高校数学をプログラミングで解く(数学II編)「5-2 接線」』で作成したスケッチ「drawTangentialLine」でも、導関数を f_prime 関数で準備しましたが、そのときと違い、f_prime 関数の引数は$${x}$$座標と$${y}$$座標の2つを指定するようにしています。これは、導関数が
$$
f'(x) = \frac{dy}{dx} = -\frac{3x}{y}
$$
と右辺に$${x}$$と$${y}$$の両方を値を与える形になっているからです。
また、これに伴い、接点をプロットする関数 plot_contact_point 、接線を描く関数 draw_tangential_line 、および法線を描く関数 draw_normal_line も、それらの引数に接点の$${x}$$座標だけでなく、接点の$${y}$$座標も与えるようにしています。
あと、関数$${F(x,y)=0}$$は今回の問題で楕円の関数になっていますので、楕円の曲線を描く関数として draw_ellipse 関数を準備しました。
これらの関数を setup 関数内で呼び出すことで図形を描きます。
ソースコード1を、スケッチ「drawTangentialLine_F」の「drawTangentialLine_F」タブのテキストエディタ部分に書いて実行すると、図1のように、実行ウィンドウのキャンバス上に、楕円が黒色の線、接点$${\mathrm{A}}$$が緑色の点、点$${\mathrm{A}}$$での接線が赤色の線、そして点$${\mathrm{A}}$$での法線が青色の線でそれぞれ描かれます。
媒介変数で表された関数の接線と法線
次に、媒介変数で表された曲線上の点での接線と法線を描くことを考えてみます。
問題2
次の媒介変数$${t}$$で表された曲線について、与えられた$${t}$$の値に対応する曲線上の点における接線と法線の方程式を求め、$${xy}$$平面上に図示せよ。
$$
\begin{cases}
x = 2-t \\
y = 3+t+t^2
\end{cases}
\ \ \ \ (t=2)
$$
アルゴリズム設計
今回の問題も、$${t=2}$$のときの微分係数を求めることができれば、上記で定義した接線の方程式や法線の方程式をそのまま利用して描いていくことができます。
媒介変数$${t}$$で表された$${x, y}$$を、$${t}$$で微分すると、
$$
\frac{dx}{dt} = -1, \ \ \ \ \frac{dy}{dt} = 1+2t
$$
となりますので、導関数として
$$
\frac{dy}{dx} = \frac{1+2t}{-1} = -1-2t
$$
が得られます。
プログラム
それでは、媒介変数で表された曲線上の点での接線と法線を描くプログラムを作成していきます。
今回も、記事『高校数学をプログラミングで解く(数学II編)「5-2 接線」』で作成したスケッチ「drawTangentialLine」を再利用して作成していきます。以下の zip ファイルをダウンロードして展開または解凍してください。
そして、スケッチの名前(フォルダ名)を「drawTangentialLine_t」と変更し、またスケッチ「drawTangentialLine_t」内の「drawTangentialLine.pde」ファイルの名前を「drawTangentialLine_t.pde」に変更します。そして、pdeファイル「drawTangentialLine_t.pde」をダブルクリックしてスケッチ「drawTangentialLine_t」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「drawTangentialLine_t」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。
float x_range = 10.0; // x軸の表示範囲 -x_rangeからx_rangeまで
float y_range = 10.0; // y軸の表示範囲 -y_rangeからy_rangeまで
void setup(){
size(500,500);
noLoop();
setAxes(x_range, y_range); // 座標軸の準備
noFill();
// 曲線を描く
stroke(0,0,0);
float t_min = 1.0-x_range;
float t_max = 1.0+x_range;
draw_curve_function(t_min, t_max);
// 接点をプロットする
float at = 2.0; // 接点での媒介変数の値
stroke(0,255,0);
plot_contact_point(at);
// 接線を描く
stroke(255,0,0);
float x_min = -x_range;
float x_max = x_range;
draw_tangential_line(at, x_min, x_max);
// 法線を描く
stroke(0,0,255);
draw_normal_line(at, x_min, x_max);
}
// 曲線上の点のx座標を媒介変数tで表す関数
float f(
float t
){
return 1.0-t;
}
// 曲線上の点のy座標を媒介変数tで表す関数
float g(
float t
){
return 3.0+t+t*t;
}
// 曲線の導関数
float f_prime(
float t
){
return -1.0-2.0*t;
}
// 曲線を描く関数
void draw_curve_function(
float t_min, // 媒介変数tが動く範囲の下限
float t_max // 媒介変数tが動く範囲の上限
){
int plot_num = 2000; // グラフを描くための頂点の個数
// グラフを描画
float t; // 媒介変数
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
beginShape();
for(int i=1; i<plot_num; i++){
t = t_min + (t_max - t_min) / plot_num * i; // 媒介変数の値
x = f(t); // 曲線上の点のx座標
y = g(t); // 曲線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
// 接点をプロットする関数
void plot_contact_point(
float at // 接点でのtの値
){
float x = f(at);
float y = g(at);
float X, Y; // キャンバス上の座標
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
strokeWeight(5);
point(X, Y);
strokeWeight(1);
}
// 接線を描く関数
void draw_tangential_line(
float at, // 接点でのtの値
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_prime(at) * (x-f(at)) + g(at); // 接線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
// 法線を描く関数
void draw_normal_line(
float at, // 接点でのtの値
float x_min, // グラフの定義域の下限
float x_max // グラフの定義域の上限
){
int plot_num = 2000; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
if( f_prime(at) == 0.0 ){
X = width / 2.0 / x_range * f(at);
line(X, -height/2.0, X, height/2.0);
} else {
beginShape();
for(int i=1; i<plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 接線上の点のx座標
y = - 1.0 / f_prime(at) * (x-f(at)) + g(at); // 接線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
}
ソースコード2 媒介変数で表された曲線上の点での接線と法線を描くプログラム
ソースコード2では、曲線上の点の$${x}$$座標を媒介変数$${t}$$で表す関数を f 、曲線上の点の$${y}$$座標を媒介変数$${t}$$で表す関数を g 、そして、導関数を表す関数 f_prime も、媒介変数 t の関数として準備しました。
また、曲線を描く関数 draw_curve_function は、引数に媒介変数$${t}$$が動く範囲の下限 t_min と上限 t_max を与えるようにし、接点をプロットする関数 plot_contact_point 、接線を描く関数 draw_tangential_line 、および法線を描く関数 void draw_normal_line については、接点での$${t}$$の値を表す変数 at を与えるようにしています。
これらの関数を setup 関数内で呼び出すことで図形を描きます。
ソースコード2を、スケッチ「drawTangentialLine_t」の「drawTangentialLine_t」タブのテキストエディタ部分に書いて実行すると、図2のように、実行ウィンドウのキャンバス上に、曲線が黒色の線、接点が緑色の点、接線が赤色の線、そして法線が青色の線でそれぞれ描かれます。
まとめ
今回は、数学IIIで学ぶ「接線と法線」について、方程式$${F(x,y)=0}$$で定めれらる関数や媒介変数で表された関数で表される曲線に対する接線や法線を求めて、それらを図示することを考えました。
接線や法線の方程式を求めてそれらを図示する方法は、記事『高校数学をプログラミングで解く(数学II編)「5-2 接線」』で解説したものと同じ方法でできます。ただ、導関数を求める方法が少し変わっていました。これは、上記の関数のいろいろな表し方と導関数の節で解説しています。
今回作成したプログラムは記事『高校数学をプログラミングで解く(数学II編)「5-2 接線」』で作成した「drawTangentialLine」を少しずつ変更したものでした。比較的簡単に感じたのではないでしょうか。そう感じたのであれば、確実に高校数学とプログラミングの力がついてきている証拠だと思います。引き続き、プログラミング経験を増やしていってください。
読んだ感想などをお寄せください
本記事を読んだ感想や質問などを以下のお問い合せフォームからお寄せください。感想、質問をいただいた方には本記事の演習問題の解答をプレゼントします。(お問合せフォームの本文に、本記事のタイトルを入れてください。)
参考文献
改訂版 教科書傍用 スタンダード・オリジナル 数学III(数研出版、ISBN9784410209567)
演習問題
次の曲線上の点$${\mathrm{A}}$$における接線と法線の方程式を求め、$${xy}$$平面上に図示するプログラムを作成してください。
$$
xy = 2 \ \ \ \ \ \ \mathrm{A} (1,2)
$$
演習問題の解答例
ここから先は
この記事が気に入ったらチップで応援してみませんか?