高校数学をプログラミングで解く(数学II編)「2-1 直線の方程式」
はじめに
今回は、数学IIで学ぶ「直線の方程式」について、いくつかの種類の直線の方程式に基づき、直線を描くプログラムを作成します。
直線の方程式
まず、直線の方程式について解説しておきます。
① 一般形 $${ax+by+c=0 \ (a \neq 0 \mathrm{または}b \neq 0)}$$あるいは$${y=mx+n, x=k}$$
② 点$${(x_1, y_1)}$$を通り、傾きが$${m}$$の直線 $${y-y_1=m(x-x_1)}$$
点$${(x_1, y_1)}$$を通り、$${x}$$軸に垂直な直線 $${x=x_1}$$
③ 異なる2点$${(x_1, y_1),(x_2, y_2)}$$を通る直線
$$
x_1 \neq x_2\mathrm{のとき} y-y_1=\frac{y_2-y_1}{x_2-x_1}(x-x_1), \ \ \ \ x_1=x_2\mathrm{のとき} x=x_1
$$
④ $${x}$$切片が$${a}$$、$${y}$$切片が$${b}$$である直線
$$
\frac{x}{a}+\frac{y}{b}=1 \ \ \ \ [ a \neq 0, b \neq 0 ]
$$
直線を描く
今回は、上記の直線の方程式を利用して直線を描くプログラムを作成していきます。
問題
次の直線を描け。
(1) $${y=2x+3}$$
(2) 点$${(-1,2)}$$を通り、傾きが$${3}$$
(3) 2点$${(-4,3),(6,-3)}$$を通る
(4) $${x}$$切片が$${-3}$$、$${y}$$切片が$${5}$$
アルゴリズム設計
今回は、直線の方程式の係数や直線が通る点の座標などを引数とする、直線を描くための関数を準備して、各問題の直線を描いていきます。
問題(1)は直線の方程式①を利用します。具体的には、一般形$${ax+by+c=0}$$を
$$
y = -\frac{a}{b}x-\frac{c}{b}
$$
の形にして利用します。
問題(2)は直線の方程式②を$${y=m(x-x_1)+y_1}$$の形にして利用します。
問題(3)は直線の方程式③を
$$
y=\frac{y_2-y_1}{x_2-x_1}(x-x_1)+y_1
$$
の形にして利用します。
問題(4)は直線の方程式④を
$$
y=-\frac{b}{a}x+b
$$
の形にして利用します。
また、記事『高校数学をプログラミングで解く(数学I編)「1-0-2 グラフを描くための準備(その2)」』で作成した座標軸を描くためのsetAxes関数を格納した「setAxes.pde」ファイルを再利用します。
プログラム 問題(1)
それでは、問題(1)の直線を描くプログラムを作成します。そのために、まず、記事『高校数学をプログラミングで解く(数学I編)「1-0-2 グラフを描くための準備(その2)」』で作成したスケッチ「drawFunction」をフォルダごとコピーして、スケッチの名前(フォルダ名)を「drawEquationOfLine1」と変更し、またスケッチ「drawEquationOfLine1」内の「drawFunction.pde」ファイルの名前を「drawEquationOfLine1.pde」に変更します。そして、pdeファイル「drawEquationOfLine1.pde」をダブルクリックしてスケッチ「drawEquationOfLine1」の開発環境ウィンドウを立ち上げます。
開発環境ウィンドウのタブ欄で「drawEquationOfLine1」タブを選択すると、そのテキストエリアのソースコードには以下のような記述になっています。
void setup(){
size(500,500);
noLoop();
float x_range = 10.0; // x軸の表示範囲 -x_rangeからx_rangeまで
float y_range = 10.0; // y軸の表示範囲 -y_rangeからy_rangeまで
setAxes(x_range, y_range); // 座標軸の準備
noFill();
stroke(0,0,0);
// グラフの定義域
float x_min = -x_range;
float x_max = x_range;
int plot_num = 200; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
beginShape();
for(int i=0; i<=plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 関数のx座標
y = quadraticfunction(x); // 関数の値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
float quadraticfunction(
float x
){
return x*x + 4.0*x + 3.0;
}
ソースコード0 「drawEquationOfLine1」タブに記載されているプログラム(修正前)
このソースコード0を問題(1)に合わせて修正していきます。修正結果を先に示します(ソースコード1)。
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);
// 直線y=2x+3を描画
float a = 2.0;
float b = -1.0;
float c = 3.0;
draw_equation_of_line1(a, b, c);
}
// 直線の方程式① ax+by+c=0を描く関数
void draw_equation_of_line1(
float a, // xの係数
float b, // yの係数
float c // 定数項
){
// グラフの定義域
float x_min = -x_range;
float x_max = x_range;
int plot_num = 200; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
beginShape();
for(int i=0; i<=plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
y = -a/b * x -c/b; // 直線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
ソースコード1 問題(1)の直線の方程式を描くプログラム
まず、ソースコード0のsetup関数内にある
float x_range = 10.0; // x軸の表示範囲 -x_rangeからx_rangeまで
float y_range = 10.0; // y軸の表示範囲 -y_rangeからy_rangeまで
を、setup関数の外に出します。これは、変数 x_range と y_range のスコープをsetup関数内だけでなく、スケッチ全体で利用できるようにするために行います。
次に、ソースコード0のsetup関数内に記述していた関数$${y=x^2+4x+3}$$のグラフを描いている箇所
// グラフの定義域
float x_min = -x_range;
float x_max = x_range;
int plot_num = 200; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
beginShape();
for(int i=0; i<=plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 関数のx座標
y = quadraticfunction(x); // 関数の値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
を取り出して関数化(関数名「draw_equation_of_line1」)しています。
// 直線の方程式① ax+by+c=0を描く関数
void draw_equation_of_line1(
float a, // xの係数
float b, // yの係数
float c // 定数項
){
// グラフの定義域
float x_min = -x_range;
float x_max = x_range;
int plot_num = 200; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
beginShape();
for(int i=0; i<=plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
y = -a/b * x -c/b; // 直線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
なお、「draw_equation_of_line1」関数の引数は、直線の方程式$${ax+by+c=0}$$の係数$${a,b,c}$$を取ります。
最後に、setup関数内でこのdraw_equation_of_line1関数を問題(1)に合わせた引数を与えて呼び出します。
// 直線y=2x+3を描画
float a = 2.0;
float b = -1.0;
float c = 3.0;
draw_equation_of_line1(a, b, c);
ソースコード0を修正したソースコード1を、スケッチ「drawEquationOfLine1」の「drawEquationOfLine1」タブのテキストエディタ部分に書いて実行すると、図1のように、実行ウィンドウのキャンバス上に問題(1)の直線が描かれます。
プログラム 問題(2)
次に、問題(2)の直線を描くプログラムを作成します。先ほど作成したスケッチ「drawEquationOfLine1」を再利用します。
スケッチ「drawEquationOfLine1」をフォルダごとコピーして、スケッチの名前(フォルダ名)を「drawEquationOfLine2」と変更し、またスケッチ「drawEquationOfLine2」内の「drawEquationOfLine1.pde」ファイルの名前を「drawEquationOfLine2.pde」に変更します。そして、pdeファイル「drawEquationOfLine2.pde」をダブルクリックしてスケッチ「drawEquationOfLine2」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「drawEquationOfLine2」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。
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);
// 点(-1,2)を通り、傾きが3の直線を描画
float x1 = -1.0;
float y1 = 2.0;
float m = 3.0;
draw_equation_of_line2(x1, y1, m);
}
// 直線の方程式② 点(x1,y1)を通り、傾きmの直線を描く関数
void draw_equation_of_line2(
float x1, // 直線が通る点のx座標
float y1, // 直線が通る点のy座標
float m // 直線の傾き
){
// グラフの定義域
float x_min = -x_range;
float x_max = x_range;
int plot_num = 200; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
beginShape();
for(int i=0; i<=plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
y = m * (x-x1) + y1; // 直線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
ソースコード2 問題(2)の直線の方程式を描くプログラム
ソースコード1からの違いは、直線の方程式①を描く関数「draw_equation_of_line1」を直線の方程式②を描く関数「draw_equation_of_line2」に書き換えているところです。なお、「draw_equation_of_line2」関数の引数は、直線が通る点の座標$${(x_1,y_1)}$$と直線の傾き$${m}$$を取ります。
そして、setup関数内でこのdraw_equation_of_line2関数を問題(2)に合わせた引数を与えて呼び出します。
ソースコード2を、スケッチ「drawEquationOfLine2」の「drawEquationOfLine2」タブのテキストエディタ部分に書いて実行すると、図2のように、実行ウィンドウのキャンバス上に問題(2)の直線が描かれます。
プログラム 問題(3)
今度は、問題(3)の直線を描くプログラムを作成します。こちらも先ほど作成したスケッチ「drawEquationOfLine1」を再利用します。
スケッチ「drawEquationOfLine1」をフォルダごとコピーして、スケッチの名前(フォルダ名)を「drawEquationOfLine3」と変更し、またスケッチ「drawEquationOfLine3」内の「drawEquationOfLine1.pde」ファイルの名前を「drawEquationOfLine3.pde」に変更します。そして、pdeファイル「drawEquationOfLine3.pde」をダブルクリックしてスケッチ「drawEquationOfLine3」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「drawEquationOfLine3」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。
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);
// 2点(-4,3),(6,-3)を通る直線を描画
float x1 = -4.0;
float y1 = 3.0;
float x2 = 6.0;
float y2 = -3.0;
draw_equation_of_line3(x1, y1, x2, y2);
}
// 直線の方程式③ 異なる2点(x1,y1),(x2,y2)を通る直線を描く関数
void draw_equation_of_line3(
float x1, // 直線が通る点1のx座標
float y1, // 直線が通る点1のy座標
float x2, // 直線が通る点2のx座標
float y2 // 直線が通る点2のy座標
){
// グラフの定義域
float x_min = -x_range;
float x_max = x_range;
int plot_num = 200; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
beginShape();
for(int i=0; i<=plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
y = (y2-y1)/(x2-x1) * (x-x1) + y1; // 直線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
ソースコード3 問題(3)の直線の方程式を描くプログラム
ソースコード1からの違いは、直線の方程式①を描く関数「draw_equation_of_line1」を直線の方程式③を描く関数「draw_equation_of_line3」に書き換えているところです。なお、「draw_equation_of_line3」関数の引数は、直線が通る2点の座標$${(x_1,y_1)}$$と$${(x_2,y_2)}$$を取ります。
そして、setup関数内でこのdraw_equation_of_line3関数を問題(3)に合わせた引数を与えて呼び出します。
ソースコード3を、スケッチ「drawEquationOfLine3」の「drawEquationOfLine3」タブのテキストエディタ部分に書いて実行すると、図3のように、実行ウィンドウのキャンバス上に問題(3)の直線が描かれます。
プログラム 問題(4)
最後に、問題(4)の直線を描くプログラムを作成します。先ほど作成したスケッチ「drawEquationOfLine1」を再利用します。
スケッチ「drawEquationOfLine1」をフォルダごとコピーして、スケッチの名前(フォルダ名)を「drawEquationOfLine4」と変更し、またスケッチ「drawEquationOfLine4」内の「drawEquationOfLine1.pde」ファイルの名前を「drawEquationOfLine4.pde」に変更します。そして、pdeファイル「drawEquationOfLine4.pde」をダブルクリックしてスケッチ「drawEquationOfLine4」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「drawEquationOfLine4」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。
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);
// x切片が-3、y切片が5である直線を描画
float a = -3.0;
float b = 5.0;
draw_equation_of_line4(a, b);
}
// 直線の方程式④ x切片がa、y切片がbである直線を描く関数
void draw_equation_of_line4(
float a, // x切片
float b // y切片
){
// グラフの定義域
float x_min = -x_range;
float x_max = x_range;
int plot_num = 200; // グラフを描くための頂点の個数
// グラフを描画
float x, y; // 関数の座標
float X, Y; // キャンバス上の座標
beginShape();
for(int i=0; i<=plot_num; i++){
x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
y = -b/a * x + b; // 直線上の点のyの値
// キャンバス上の座標位置に換算
X = width / 2.0 / x_range * x;
Y = height / 2.0 / y_range * y;
vertex(X, Y);
}
endShape();
}
ソースコード4 問題(4)の直線の方程式を描くプログラム
ソースコード1からの違いは、直線の方程式①を描く関数「draw_equation_of_line1」を直線の方程式④を描く関数「draw_equation_of_line4」に書き換えているところです。なお、「draw_equation_of_line4」関数の引数は、$${x}$$切片の$${a}$$と$${y}$$切片の$${b}$$を取ります。
そして、setup関数内でこのdraw_equation_of_line4関数を問題(4)に合わせた引数を与えて呼び出します。
ソースコード4を、スケッチ「drawEquationOfLine4」の「drawEquationOfLine4」タブのテキストエディタ部分に書いて実行すると、図4のように、実行ウィンドウのキャンバス上に問題(4)の直線が描かれます。
まとめ
今回は、数学IIで学ぶ「直線の方程式」について、4種類の直線の方程式に基づき、直線を描くプログラムを作成しました。
直線などのグラフを描くことについては、記事『高校数学をプログラミングで解く(数学I編)「1-0-2 グラフを描くための準備(その2)」』で解説しています。このとき作成したスケッチ「drawFunction」を再利用しました。そして、直線を描く部分は、setup関数の外に出してそれぞれの直線の方程式に基づいて関数化し、その関数をsetup関数内で呼び出すようにしました。
今回作成したプログラムはいづれも$${x}$$軸と垂直に交わるような直線を描くことができるようにはしていません。ただ、そのような直線も描くことができるように直線の方程式の関数を修正することは比較的簡単です。是非チャレンジしてみてください。
参考文献
改訂版 教科書傍用 スタンダード 数学II(数研出版、ISBN9784410209369)
この記事が気に入ったらサポートをしてみませんか?