見出し画像

高校数学をプログラミングで解く(数学B編)「2-3 空間ベクトルの内積」

マガジンリスト > 数学B編 2.空間のベクトル > 2-3 空間ベクトルの内積


はじめに

今回は、数学Bで学ぶ「空間ベクトルの内積」について、空間ベクトルの内積を利用する問題を、空間ベクトルの成分を用いて内積を計算する方法とプログラミング言語 Processing で用意された内積を計算する関数を用いる方法の2つの方法でプログラムを作成して解いてみます。

空間ベクトルの内積

まず、空間ベクトルの内積についてその性質も含めてまとめておきます。なお、以下で$${k}$$は実数とし、$${\vec{a} = (a_1, a_2, a_3), \ \vec{b} = (b_1, b_2, b_3), \ \vec{a} \neq \vec{0}, \ \vec{b} \neq \vec{0}}$$とします。また、$${\vec{a}}$$と$${\vec{b}}$$のなす角を$${ \theta \ ( 0^{\circ} \leq \theta \leq 180^{\circ} ) }$$とします。

空間ベクトルの内積と成分

① 定義

$$
\vec{a} \cdot \vec{b} = | \vec{a} || \vec{b} | \cos \theta
$$

② 成分表示

$$
\vec{a} \cdot \vec{b} = a_1 b_1 + a_2 b_2 + a_3 b_3
$$

③  なす角

$$
\cos \theta = \frac{ \vec{a} \cdot \vec{b} }{ | \vec{a} || \vec{b} | } = \frac{ a_1b_1+a_2b_2+a_3b_3}{ \sqrt{ a_1^2+a_2^2+a_3^2 } \sqrt{ b_1^2+b_2^2+b_3^2 }}
$$

④ 垂直条件

$$
\vec{a} \perp \vec{b} \Leftrightarrow \vec{a} \cdot \vec{b} = 0 \Leftrightarrow a_1b_1 + a_2b_2 + a_3b_3 = 0
$$

空間ベクトルの内積の性質

① $${ \vec{a} \cdot \vec{b} = \vec{b} \cdot \vec{a} }$$
② $${ \vec{a} \cdot \vec{a} = | \vec{a} |^2 }$$
③ $${ (k \vec{a}) \cdot \vec{b} = \vec{a} \cdot (k \vec{b}) = k ( \vec{a} \cdot \vec{b} ) }$$
④ $${ ( \vec{a} + \vec{b} ) \cdot \vec{c} = \vec{a} \cdot \vec{c} + \vec{b} \cdot \vec{c} }$$
⑤ $${ \vec{a} \cdot ( \vec{b} + \vec{c} ) = \vec{a} \cdot \vec{b} + \vec{a} \cdot \vec{c} }$$

空間ベクトルの内積に関する問題

今回は、下記の問題を解くプログラムを作成していきます。

問題
次の2つの空間ベクトル$${ \vec{a}, \vec{b} }$$の内積と、そのなす角$${\theta}$$を求めよ。
(1) $${ \vec{a} = ( 1, 1, 0 ), \ \vec{b} = ( 1, 2, -2 ) }$$
(2) $${ \vec{a} = ( 3, 5, 2 ), \ \vec{b} = ( -3, 1, 2 ) }$$
(3) $${ \vec{a} = ( 1, -1, 1 ), \ \vec{b} = ( 1, \sqrt{6}, -1 ) }$$

ベクトルの成分を用いて内積を計算するプログラム

まず、ベクトルの大きさや内積をベクトルの成分を用いて計算して、それらの値をもとに2つのベクトルのなす角を求めるプログラムを作成します。

PVector クラスによるベクトル成分の取得

ベクトルの大きさや内積をベクトルの成分を用いて計算するために、まず、PVector クラスを用いて生成したベクトルから$${x, y, z}$$の各成分を取得する方法について解説します。

PVector a = new PVector(a1,a2,a3); // ベクトルの生成
a.x; // ベクトルaのx成分
a.y; // ベクトルaのy成分
a.z; // ベクトルaのz成分

上記のように、PVector クラスとして生成したベクトル a に対して、
a.x : ベクトルaの$${x}$$成分 float型
a.y : ベクトルaの$${y}$$成分 float型
a.z : ベクトルaの$${z}$$成分 float型
とするだけで、ベクトルの成分の値を取得できます。

2つのベクトルの大きさ、内積、なす角を計算するプログラム

ベクトルの成分を取得できるようになりましたので、問題(1)を例にしてベクトルの大きさや内積についてベクトルの成分を用いて計算し、最後になす角を算出するプログラムを作成します。
記事『高校数学をプログラミングで解く(数学B編)「2-0-3 右手系で図形を描く」』で作成したスケッチ「draw3DCoordinates_temp」を再利用します。以下の zip ファイルをダウンロードして展開または解凍してください。

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

// 2つの空間ベクトルの内積とそのなす角を計算する

float range; // 座標系での表示範囲-range≦x,y.z≦range
float res; // 座標系のサイズをキャンバスのサイズに変換するパラメータ
float angle = 0.0;

PVector a, b; // 与えられた空間ベクトル

void setup(){
  size(400, 400, P3D);
  noFill();
  ortho();
  range = 10.0; 
  res = width / 2.0 / range;

  // 2つの空間ベクトル
  a = new PVector(1.0, 1.0, 0.0);
  b = new PVector(1.0, 2.0, -2.0);

  // 2つのベクトルの大きさ
  float magnitude_a = sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
  float magnitude_b = sqrt(b.x * b.x + b.y * b.y + b.z * b.z);
  
  // 2つのベクトルの内積を計算する
  float innerproduct = a.x * b.x + a.y * b.y + a.z * b.z;
  
  // なす角を求める
  float cos_theta = innerproduct / magnitude_a / magnitude_b;
  float theta = 180.0 / PI * acos( cos_theta );
  
  println( "ベクトルaの大きさ:", magnitude_a);
  println( "ベクトルbの大きさ:", magnitude_b);
  println( "ベクトルの内積:", innerproduct);
  println( "ベクトルのなす角:", theta);
  
}

void draw(){
  background(204); // 背景をグレーにする
  // 視点を設定する
  camera(200.0, -200.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0);
  // マウスボタンが押されたときの処理
  if(mousePressed){ 
    if( mouseButton == LEFT ){ // 左ボタンがおされたときはz軸時計周りに回転
      angle = angle + 1.0;
    } else if( mouseButton == RIGHT ){ // 右ボタンがおされたときはz軸反時計周りに回転
      angle = angle -1.0;
    } else {
    }
  }
  // z軸周りに回転
  rotateZ(radians(angle));

  // 座標軸の設定
  fill(255,0,0);
  stroke(255,0,0);
  arrow3D(0.0,0.0,0.0,range * res,0.0,0.0); // x軸(赤色)
  fill(0,255,0);
  stroke(0,255,0);
  arrow3D(0.0,0.0,0.0,0.0,range * res,0.0); // y軸(緑色)
  fill(0,0,255);
  stroke(0,0,255);
  arrow3D(0.0,0.0,0.0,0.0,0.0,range * res); // z軸(青色)

  noFill();
  stroke(0,0,0);
  // 以下に、図形を描いていく
  
  // 空間ベクトルa,bを描く
  fill(0,0,0);
  stroke(0,0,0);
  arrow3D(0.0,0.0,0.0, a.x*res,a.y*res,a.z*res);
  fill(0,0,0);
  stroke(0,0,0);
  arrow3D(0.0,0.0,0.0, b.x*res,b.y*res,b.z*res);
}

ソースコード1 2つの空間ベクトルの大きさ、内積、なす角を求めるプログラム

このスケッチ「calcInnerProduct3D」を実行すると、図1のように、コンソールに各ベクトルの大きさ、2つのベクトルの内積、2つのベクトルのなす角が順に、

ベクトルaの大きさ: 1.4142135
ベクトルbの大きさ: 3.0
ベクトルの内積: 3.0
ベクトルのなす角: 44.999996

と表示されます。

図1 スケッチ「calcInnerProduct3D」の実行結果

この結果は、
$${\vec{a}}$$の大きさ:$${\sqrt{2} = 1.41421356 \cdots}$$
$${\vec{b}}$$の大きさ:$${3}$$
$${\vec{a} \cdot \vec{b}}$$:$${3}$$
なす角:$${45^{\circ}}$$
と丸め誤差の範囲で一致していることがわかります。
また、図2のように、実行ウィンドウのキャンバスにそれぞれのベクトルが矢印で描かれます。

図2 問題(1)の2つの空間ベクトル

なお、実行ウィンドウのキャンバス内をクリックすると$${z}$$軸回りに図形が回転するので、いろいろな角度から空間ベクトルを眺めてみてください。

また、ソースコード1で2つのベクトルのなす角$${\theta}$$を求めている部分

  float cos_theta = innerproduct / magnitude_a / magnitude_b;
  float theta = 180.0 / PI * acos( cos_theta );

については、記事『高校数学をプログラミングで解く(数学B編)「1-2 ベクトルの内積」』で解説していますので、そちらも確認してください。

その他の問題

残りの問題(2)(3)についてもソースコード1の

  // 2つの空間ベクトル
  a = new PVector(1.0, 1.0, 0.0);
  b = new PVector(1.0, 2.0, -2.0);

の部分を書き換えて、実行するだけで解を求めることができます。以下に、出力結果を示しておきます。

問題(2)
ベクトルaの大きさ: 6.164414
ベクトルbの大きさ: 3.7416575
ベクトルの内積: 0.0
ベクトルのなす角: 90.0

図3 問題(2)の2つの空間ベクトル

問題(3)
ベクトルaの大きさ: 1.7320508
ベクトルbの大きさ: 2.828427
ベクトルの内積: -2.4494898
ベクトルのなす角: 120.0

図4 問題(3)の2つの空間ベクトル


PVector クラスの内積を計算する関数を用いるプログラム

前節『ベクトルの成分を用いて内積を計算するプログラム』では、PVector クラスの変数 a に対して、a.x、a.y、a.z とすることで空間ベクトルの$${x}$$成分、$${y}$$成分、$${z}$$成分を取り出すことができることを利用して、2つのベクトルの大きさや内積、そしてなす角を計算しましたが、PVectorクラスには、ベクトルの大きさや2つのベクトルの内積、2つのベクトルのなす角を求めるための関数が用意されています。これらについては、記事『高校数学をプログラミングで解く(数学B編)「1-2 ベクトルの内積」』で平面ベクトルに対して解説しています。空間ベクトルについても同じ関数を用いて求めることができます。ここでは、それらの関数を改めて紹介したあと、それらの関数を用いて、ソースコード1を書き換えます。

ベクトルの大きさを求める関数「mag」

PVectorクラスの変数 a で表したベクトルに対してその大きさを求めるときは、mag 関数を用います。

PVector a = new PVector(a1, a2, a3);
a.mag();

mag 関数は引数を取りませんが、返り値はベクトル a の大きさ(float型)となります。

2つのベクトルの内積を求める関数「dot」

PVector クラスの変数 a, b で表した2つのベクトルに対してそれらの内積を求めるときは、dot 関数を用います。

PVector a = new PVector(a1, a2, a3);
PVector b = new PVector(b1, b2, b3);
b.dot(a);

dot 関数の引数は内積を算出したいベクトル(PVector クラス)を取り、返り値は2つのベクトルの内積(float型)となります。

2つのベクトルのなす角を求める関数「angleBetween」

PVector クラスの変数 a, b で表した2つのベクトルに対してそれらのなす角を求めるときは、angleBetween 関数を用います。

PVector a = new PVector(a1, a2, a3);
PVector b = new PVector(b1, b2, b3);
PVector.angleBetween(a, b);

angleBetween 関数の引数は2つのベクトル(PVectorクラス)を取り、返り値は2つのベクトルのなす角(ラジアン、float型)となります。なお、mag 関数や dot 関数と違い「PVector.angleBetween」という形で利用することに注意してください。

2つのベクトルの大きさ、内積、なす角を計算するプログラムの書き換え

それでは、上記の PVector クラスの関数を利用して、2つのベクトルの大きさ、内積、なす角を計算するプログラム(ソースコード1)を書き換えます。

// 2つの空間ベクトルの内積とそのなす角を計算する

float range; // 座標系での表示範囲-range≦x,y.z≦range
float res; // 座標系のサイズをキャンバスのサイズに変換するパラメータ
float angle = 0.0;

PVector a, b; // 与えられた空間ベクトル

void setup(){
  size(400, 400, P3D);
  noFill();
  ortho();
  range = 10.0; 
  res = width / 2.0 / range;

  // 2つの空間ベクトル
  a = new PVector(1.0, 1.0, 0.0);
  b = new PVector(1.0, 2.0, -2.0);

  // 2つのベクトルの大きさ
  float magnitude_a = a.mag();
  float magnitude_b = b.mag();
  
  // 2つのベクトルの内積を計算する
  float innerproduct = b.dot(a);
  
  // なす角を求める
  float theta = 180.0 / PI * PVector.angleBetween(a,b);
  
  println( "ベクトルaの大きさ:", magnitude_a);
  println( "ベクトルbの大きさ:", magnitude_b);
  println( "ベクトルの内積:", innerproduct);
  println( "ベクトルのなす角:", theta);
  
}

void draw(){
  background(204); // 背景をグレーにする
  // 視点を設定する
  camera(200.0, -200.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0);
  // マウスボタンが押されたときの処理
  if(mousePressed){ 
    if( mouseButton == LEFT ){ // 左ボタンがおされたときはz軸時計周りに回転
      angle = angle + 1.0;
    } else if( mouseButton == RIGHT ){ // 右ボタンがおされたときはz軸反時計周りに回転
      angle = angle -1.0;
    } else {
    }
  }
  // z軸周りに回転
  rotateZ(radians(angle));

  // 座標軸の設定
  fill(255,0,0);
  stroke(255,0,0);
  arrow3D(0.0,0.0,0.0,range * res,0.0,0.0); // x軸(赤色)
  fill(0,255,0);
  stroke(0,255,0);
  arrow3D(0.0,0.0,0.0,0.0,range * res,0.0); // y軸(緑色)
  fill(0,0,255);
  stroke(0,0,255);
  arrow3D(0.0,0.0,0.0,0.0,0.0,range * res); // z軸(青色)

  noFill();
  stroke(0,0,0);
  // 以下に、図形を描いていく
  
  // 空間ベクトルa,bを描く
  fill(0,0,0);
  stroke(0,0,0);
  arrow3D(0.0,0.0,0.0, a.x*res,a.y*res,a.z*res);
  fill(0,0,0);
  stroke(0,0,0);
  arrow3D(0.0,0.0,0.0, b.x*res,b.y*res,b.z*res);
}

ソースコード2 ソースコード1の一部を PVector クラスの関数で置き換え

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

図5 スケッチ「calcInnerProduct3D2」の実行結果

結果として、コンソールに各ベクトルの大きさ、2つのベクトルの内積、2つのベクトルのなす角が順に、

ベクトルaの大きさ: 1.4142135
ベクトルbの大きさ: 3.0
ベクトルの内積: 3.0
ベクトルのなす角: 45.0

と表示されます。これは、ソースコード1のときと丸め誤差の範囲内で一致しているということがわかります。
また、図6のように、実行ウィンドウのキャンバスにそれぞれのベクトル(黒色)が矢印で描かれます。これは、図2と同じものです。

図6 問題(1)の2つの空間ベクトル(図2と同じ)


まとめ

今回は、数学Bで学ぶ「空間ベクトルの内積」について、空間ベクトルの内積を利用する問題を、空間ベクトルの成分を用いて内積を計算する方法とプログラミング言語 Processing で用意された内積を計算する関数を用いる方法の2つの方法でプログラムを作成して解いてみました。
空間ベクトルは平面ベクトルを扱うクラスとして解説したものと同じ、PVector クラスを利用することができ、$${z}$$成分が増えるだけで扱い方もほとんど変わりません。
ただ、平面ベクトルでは扱わない、空間ベクトルのみで扱う演算もあり、このような演算も PVector クラスの関数として準備されています。これらの演算は高校数学の範囲を越えるものもありますので紹介はしませんが、興味のある方はProcessingのマニュアル(英語のサイト)をのぞいてみてください。

参考文献

改訂版 教科書傍用 スタンダード 数学B(数研出版、ISBN9784410209468)

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