ある3次元ベクトルVが与えられたとき,それに直交する3次元ベクトルを求めるための関数を作る.
関数の仕様:
- Vが零ベクトルでない場合,解も零ベクトルでないものとする
- 解は無限に存在しますが,そのうちのいずれか1つを結果とする
……という話に対して,解を求める方法として後述する2つ{(A)と(B)}の話を考えました.
…のですが,(A)と(B)の2つは考えの出発点がちょっと違っていただけで,結局,(B)は(A)の縮小版みたいな話でした.
実際,後述の2つのコードを見比べれば,(B)は(A)の処理を簡略化した形の内容になっています.
質問の内容は,「実用上(?),(B)で問題ないのだろうか?」ということです.
計算量の観点では(B)の方がちょっとだけ良いだろうと思いますが,
「(B)は,(A)が返し得る3種類の解のうちの1つ((A)のコード内の末尾の解)を返さない」という点が気になっています.
「(B)では足りてなくて,(A)でなくてはならない」とか,
「(B)の方が(A)よりも(何らかの意味で)良くない」といったことがあるものでしょうか?
(A)
Vの要素のうち最も絶対値が小さい要素を捨てて(=0にして),あとは残りの2次元の平面上で90度回転すれば解が得られる.
…という考えを愚直に実装したのが↓のコードです.
C++
1//Vに直交するベクトルを計算して,結果をPVに入れる. 2//(A)Version 3void Perpendicular_A( const double (&V)[3], double (&PV)[3] ) 4{ 5 const double ABS[]{ fabs(V[0]), fabs(V[1]), fabs(V[2]) }; 6 7 if( ABS[0] < ABS[1] ) 8 { 9 if( ABS[0] < ABS[2] ) 10 { 11 PV[0] = 0; 12 PV[1] = -V[2]; 13 PV[2] = V[1]; 14 return; 15 } 16 } 17 else if( ABS[1] < ABS[2] ) 18 { 19 PV[0] = V[2]; 20 PV[1] = 0; 21 PV[2] = -V[0]; 22 return; 23 } 24 25 //※この解は,後述の方法(B)の実装には現れない 26 PV[0] = -V[1]; 27 PV[1] = V[0]; 28 PV[2] = 0; 29}
(B)
何か適当なベクトルaを持ってきたとき,a が V と平行でなければ,a と V の外積が解である.
↓
適当に決めたベクトルaと,それに直交するベクトルbの2つを用意しておいて,
- a と V の外積
- b と V の外積
のうち,ノルムが大きい側を解とすれば,Vに平行な(あるいは非常に平行に近い)ベクトルを用いてしまうことへ対策できる.
この話を
a = { 1,0,0 }
b = { 0,1,0 }
として実装したのが↓のコードです.
C++
1//Vに直交するベクトルを計算して,結果をPVに入れる. 2//(B)Version 3void Perpendicular_B( const double (&V)[3], double (&PV)[3] ) 4{ 5 //CrossProd( {1,0,0}, V ) = { 0, -V[2], V[1] } 6 //CrossProd( {0,1,0}, V ) = { V[2], 0, -V[0] } 7 //ノルムが大きい側を採用するとしたら,V[0]とV[1]の絶対値を見て判定すればよい 8 9 const double ABS[]{ fabs(V[0]), fabs(V[1]) /*, fabs(V[2])*/ }; 10 11 //※解の種類が2種類だけだが,これで「十分」であろうか? 12 if( ABS[0] < ABS[1] ) 13 { 14 PV[0] = 0; 15 PV[1] = -V[2]; 16 PV[2] = V[1]; 17 } 18 else 19 { 20 PV[0] = V[2]; 21 PV[1] = 0; 22 PV[2] = -V[0]; 23 } 24}
※補足:
(B)は(A)の縮小版みたいな話でした
という言い方は少し違うかもしれない.
(B)の話において,a や b に単位ベクトルを選ぶことで,a(bも同様)と V との外積というのは,
「V の a 方向成分を除去したものを, a を回転軸として90度回したもの」という話になる.
で, その単位ベクトルとして,a = {1,0,0} としたことによって,(A)の話と全く同じことになっている.
…という感じか.
[追記]
いくつかの回答やコメントにおいて,「非0」という概念が述べられていますが,
この質問内に示した実装では,「値が0かどうか」を直接的に判定するのではなく,(要素のABSを比較することによって)「より0から遠いものを用いる」という方法を採っています.
「値が0かどうか」という判定を用いた場合,その判定で0でないとされた「0にとても近い値」だけで結果が構成されるかもしれず,
そのような結果は{精度が?,利用のし易さが?}良くないものになる可能性があるのではないだろうか? と考えています.(←この考え自体が間違い?)
回答4件
あなたの回答
tips
プレビュー