見出し画像

高校数学をプログラミングで解く(数学III編)「1-4 複素数と図形(1)」

割引あり

マガジンリスト > 数学Ⅲ編 1.複素数平面 > 1-4 複素数と図形(1)


はじめに

今回は、数学IIIで学ぶ「複素数と図形」について、複素数の方程式が表す図形を描くプログラムを作成します。

複素数と図形(1)

まず、複素数に関する内分点、外分点、および方程式の表す図形について解説します。

内分点、外分点

$${\mathrm{A}(\alpha),  \mathrm{B}(\beta),  \mathrm{C}(\gamma)}$$とします。
① 線分$${\mathrm{AB}}$$を$${m:n}$$に内分または外分する点を表す複素数は
内分点

$$
\frac{n \alpha + m \beta}{m+n}
$$

外分点

$$
\frac{-n \alpha + m \beta}{m-n}
$$

特に中点

$$
\frac{\alpha+\beta}{2}
$$

② $${\triangle \mathrm{ABC}}$$の重心を表す複素数は

$$
\frac{\alpha + \beta + \gamma}{3}
$$

方程式の表す図形

① $${|z-\alpha|=r}$$ 点$${\alpha}$$を中心とする半径$${r}$$の円
② $${|z-\alpha|=|z-\beta|}$$ 2点$${\alpha, \beta}$$を結ぶ線分の垂直二等分線

方程式の表す図形を描く

では、次の方程式が表す図形を描くプログラムを作成します。

問題1
次の方程式を満たす点$${z}$$全体は、どのような図形か。複素数平面上にその軌跡を図示せよ。
(1) $${|z+2|=3}$$
(2) $${|z-3|=|z-i|}$$
(3) $${|z+1|=2|z-2|}$$

アルゴリズム設計

今回、この問題1の軌跡を描くにあたり、記事『高校数学をプログラミングで解く(数学II編)「2-5 軌跡と方程式」』で解説した方法を利用します。
つまり、複素数平面の描画範囲内の任意の点$${z  (=x+iy)}$$を取ってきて、その点が方程式を満たすかどうかを確かめ、方程式を満たしていればその点をキャンバス上の複素数平面にプロットし、方程式を満たしていなければプロットしないというルールで行います。そして、プロットされた点が描く軌跡がどのような図形(方程式)になっているかを見てみます。
実際のプログラムでは、任意の複素数$${z=x+iy}$$は(2つの) random 関数を利用して取得します。このように取得した点から方程式の左辺の値 lhs と方程式の右辺の値 rhs とをそれぞれ計算して比較していきますが、厳密に lhs と rhs とが等しくなるようなことはほとんど起こらないでしょう。つまり、プログラム内において

lhs == rhs

という条件を満たす点は現れないでしょう。
そこで、条件を少し緩めます。つまり、ある程度小さな値をもつマージン$${e}$$を用意して「 左辺と右辺とが等しい」という条件を「左辺と右辺との差が $${-e}$$と$${e}$$との間に入っている」という条件に緩めることにします。この条件を式で表すと、

abs(lhs-rhs) < e

と書くことができます。

プログラム

今回は、複素数を複素数平面上にプロットしていきますので、記事『高校数学をプログラミングで解く(数学III編)「1-3 ド・モアブルの定理」』で作成したスケッチ「plot_root_of_unity」を再利用します。以下の zip ファイルをダウンロードして展開または解凍してご利用ください。

展開または解凍したスケッチ「plot_root_of_unity」の名前(フォルダ名)を「drawTrajectory_complex」と変更し、またスケッチ「drawTrajectory_complex」内の「plot_root_of_unity.pde」ファイルの名前を「drawTrajectory_complex.pde」に変更します。そして、pdeファイル「drawTrajectory_complex.pde」をダブルクリックしてスケッチ「drawTrajectory_complex」の開発環境ウィンドウを立ち上げます。

準備ができたら、問題1の各方程式が表す図形を描くプログラムを作成していきます。

// 方程式の表す図形を描く
void setup(){
  size(500,500,P2D); // widthとheightは同じにしておく
  noLoop();
  float range = 10.0; // 実軸と虚軸の表示範囲 -rangeからrangeまで
  setAxes(range, range); // 座標軸の準備
  
  // 以下、複素数平面に複素数をプロットしていく
  noFill(); // グラフの中身を塗りつぶさない
  stroke(0,0,0); // グラフの線の色を黒色に設定

  // 複素数平面の原点から複素数までの線分を描かない
  boolean line_flag = false;
  
  // 点の生成回数
  int n = 1000000;
  // マージン
  float e = 0.001;
  
  // (1) |z-alpha|=rの軌跡
  PVector alpha1 = new PVector(-2.0,0.0);
  float r = 3.0;

  // (2) |z-alpha| = |z-beta|の軌跡
  PVector alpha2 = new PVector(3.0,0.0);
  PVector beta2 = new PVector(0.0,1.0);
  
  // (3) a|z-alpha| = b|z-beta|の軌跡
  PVector alpha3 = new PVector(-1.0,0.0);
  PVector beta3 = new PVector(2.0,0.0);
  float a = 1.0;
  float b = 2.0;
  
  float x, y; // 任意の点の座標
  PVector z; // 任意の点の複素数
  float lhs, rhs; // 左辺と右辺の値
  for(int i=0; i<n; i++){
    // 任意の複素数を生成
    x = random(-range, range);
    y = random(-range, range);
    z = new PVector(x,y);
    
    // (1)の式を満足する場合、プロット
    stroke(255,0,0);
    lhs = c_absolute_value( c_sub(z,alpha1) );
    rhs = r;
    if( abs(lhs-rhs) < e ){
      plot_complex_number(z, range, line_flag);
    }
    
    // (2)の式を満足する場合、プロット
    stroke(0,255,0);
    lhs = c_absolute_value( c_sub(z,alpha2) );
    rhs = c_absolute_value( c_sub(z,beta2) );
    if( abs(lhs-rhs) < e ){
      plot_complex_number(z, range, line_flag);
    }   
    
    // (3)の式を満足する場合、プロット
    stroke(0,0,255);
    lhs = a * c_absolute_value( c_sub(z,alpha3) );
    rhs = b * c_absolute_value( c_sub(z,beta3) );
    if( abs(lhs-rhs) < e ){
      plot_complex_number(z, range, line_flag);
    }   
    
  }
}

ソースコード1 方程式が表す図形を描くプログラム

なお、ソースコード1では、複素数の生成回数$${n}$$を$${1000000}$$に設定してループを回していますが、問題1の方程式ごとにループを回さず、ループは1回だけ回すようにしています。これにより処理時間を少し短縮することができます。

スケッチ「drawTrajectory_complex」の「drawTrajectory_complex」タブを選択してそのテキストエディタ部分をソースコード1で書き換えて実行すると、図1のように、実行ウィンドウのキャンバスの複素数平面上に、(1)の方程式の軌跡が赤色、(2)の方程式の軌跡が緑色、(3)の方程式の軌跡が青色でそれぞれ描かれます。

図1 方程式が表す図形の描画

図1を見ると、(1)の方程式は円(赤色)、(2)の方程式は直線(緑色)となっており、これはこの記事の最初に解説した方程式の表す図形の①と②にそれぞれ対応していることがわかります。(3)については円になりました(青色)。これは(3)の方程式を式変形していくと、

$$
|z-3|=2
$$

つまり、方程式の表す図形の①の形となり、方程式からも円を表すことがわかります。

座標変換した点が表す図形を描く

次に、複素数$${z}$$がある図形上を動くときに、$${z}$$を座標変換した点$${w}$$が描く図形(軌跡)について考えます。

問題2
点$${z}$$が、原点$${\mathrm{O}}$$を中心とする半径$${1}$$の円上を動くとき、次の条件を満たす点$${w}$$はどのような図形を描くか。
(1) $${w=z+i}$$
(2) $${w =\frac{iz +4}{2}}$$
(3) 点$${3i}$$と点$${z}$$を結ぶ線分の中点$${w}$$

アルゴリズム設計

今回は、問題2の図形を描くために以下のように考えていきます。

単位円上の点$${z}$$
問題では『点$${z}$$が、原点$${\mathrm{O}}$$を中心とする半径$${1}$$の円上を動く』となっています。今回はこの単位円上の点$${z}$$として円周を$${n}$$等分するようにとっていきます。つまり、

$$
z = \cos \left( \frac{2 \pi}{n} k \right) + i \sin \left( \frac{2 \pi}{n} k \right) \ \ ( k= 0,1,2,\cdots, n-1)
$$

として、$${k}$$を$${0}$$から順番にとっていくことで『点$${z}$$が単位円周上を動く』を表すことにします。

座標変換の式
問題2の式は、それぞれ変形すると、
(1) $${w=z+i}$$
(2) $${w = \frac{i}{2} z + 2}$$
(3) $${w = \frac{1}{2} z + \frac{3i}{2}}$$
となります。これらの式は、複素数$${\alpha,  \beta}$$として、

$$
w = \alpha z + \beta
$$

と共通の形にまとめることができます。今回のプログラムではこの性質を利用しています。

プログラム

先程、問題1で作成したスケッチ「drawTrajectory_complex」を再利用します。
スケッチ「drawTrajectory_complex」をフォルダごとコピーして、スケッチの名前(フォルダ名)を「drawTrajectory_complex2」と変更し、またスケッチ「drawTrajectory_complex2」内の「drawTrajectory_complex.pde」ファイルの名前を「drawTrajectory_complex2.pde」に変更します。そして、pdeファイル「drawTrajectory_complex2.pde」をダブルクリックしてスケッチ「drawTrajectory_complex2」の開発環境ウィンドウを立ち上げます。

問題2の各式が表す図形(軌跡)を描くプログラムを作成していきます。

// 単位円上の点zを変数変換した値wの軌跡を描く
void setup(){
  size(500,500,P2D); // widthとheightは同じにしておく
  noLoop();
  float range = 3.0; // 実軸と虚軸の表示範囲 -rangeからrangeまで
  setAxes(range, range); // 座標軸の準備
  
  // 以下、複素数平面に複素数をプロットしていく
  noFill(); // グラフの中身を塗りつぶさない
  stroke(0,0,0); // グラフの線の色を黒色に設定

  // 複素数平面の原点から複素数までの線分を描かない
  boolean line_flag = false;
  
  // 単位円の分割数
  int n = 100;

  // (1) w = alpha1 z + beta1
  PVector alpha1 = new PVector(1.0,0.0);
  PVector beta1 = new PVector(0.0,1.0);

  // (2) w = alpha2 z + beta2
  PVector alpha2 = new PVector(0.0,0.5);
  PVector beta2 = new PVector(2.0,0.0);
  
  // (3) w = alpha3 z + beta3
  PVector alpha3 = new PVector(0.5,0.0);
  PVector beta3 = new PVector(0.0,1.5);
  
  float x, y; // 単位円上の点の座標
  PVector z; // 単位円上の点の複素数
  PVector w; // 変数変換後
  for(int k=0; k<n; k++){
    // 単位円上の複素数を生成
    x = cos(2.0*PI/n * k);
    y = sin(2.0*PI/n * k);
    z = new PVector(x,y);

    // 単位円
    stroke(0,0,0);
    plot_complex_number(z, range, line_flag);
    
    // (1)の点をプロット
    stroke(255,0,0);
    w = c_sum(c_prod(z,alpha1), beta1);
    plot_complex_number(w, range, line_flag);
    
    // (2)の点をプロット
    stroke(0,255,0);
    w = c_sum(c_prod(z,alpha2), beta2);
    plot_complex_number(w, range, line_flag);
        
    // (3)の点をプロット
    stroke(0,0,255);
    w = c_sum(c_prod(z,alpha3), beta3);
    plot_complex_number(w, range, line_flag);
    
  }
}

ソースコード2 座標変換した点が表す図形(軌跡)を描くプログラム

なお、ソースコード2でも、円周の分割数$${n}$$を$${100}$$に設定してループを回しますが、問題2の変換式ごとにループを回さず、ループは1回だけ回すようにしています。

スケッチ「drawTrajectory_complex2」の「drawTrajectory_complex2」タブを選択してそのテキストエディタ部分をソースコード2で書き換えて実行すると、図2のように、実行ウィンドウのキャンバスの複素数平面上に、(1)の軌跡が赤色、(2)の軌跡が緑色、(3)の軌跡が青色でそれぞれ描かれます。

図2 座標変換した点が表す図形(軌跡)の描画

単位円上の点$${z}$$は$${|z|=1}$$の方程式を満たすので、問題2の各式を$${z= \alpha' w + \beta'}$$の形にして、$${|z|=1}$$に代入し整理すると、
(1) $${|w-i|=1}$$
(2) $${|w-2|=\frac{1}{2}}$$
(3) $${|w-\frac{3i}{2}| = \frac{1}{2} }$$
と$${w}$$の方程式として書くことができます。これらの方程式と図2に描いた図形を比較すると、正しく図形を描けていることがわかります。

まとめ

今回は、数学IIIで学ぶ「複素数と図形」について、複素数の方程式が表す図形を描くプログラムを2つ作成しました。

今回作成したプログラムは、条件を満たす点をプロットしていくことで図形(軌跡)を描いていきましたが、もちろん、このようなやり方ではなく、それぞれの問題の式を変形して直線の方程式や円の方程式の形に直してから、line 関数や circle 関数を用いて描くこともできます。こちらの方法で図形を描くプログラムも作成して、今回作成したプログラムの結果と一致しているか確認してみてください。

参考文献

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


演習問題

複素数平面上の点$${\mathrm{A}(\alpha),  \mathrm{B}(\beta),  \mathrm{C}(\gamma)}$$を

$$
\alpha = -3-i, \ \ \beta = 4+i, \ \ \gamma = 5i
$$

とします。$${\triangle \mathrm{ABC}}$$を複素数平面上に描いたうえで、以下の点をプロットするプログラムを作成してください。

(1) 線分$${\mathrm{AB}}$$を$${2:1}$$に内分する点(赤色)
(2) 線分$${\mathrm{BC}}$$を$${2:1}$$に外分する点(緑色)
(3) 線分$${\mathrm{CA}}$$の中点(青色)
(4) $${\triangle \mathrm{ABC}}$$の重心(黄色)


演習問題の解答例

ここから先は

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

この記事が気に入ったらサポートをしてみませんか?