そして,自分で考えて実装したのが,下記コードの GetPerpendicularOf() 関数です.
この関数の実装に関して,
(1)誤った答えを出してしまうような入力が有り得るでしょうか?
(2)(何らかの意味で)より良い実装方法(アルゴリズム?)を御存じの方がおられましたら,ご教示願いたいです.
#include <iostream>
#include <limits>
#include <random>
//3次元ベクトル
struct Vec3
{
Vec3( double x=0, double y=0, double z=0 ){ V[0]=x; V[1]=y; V[2]=z; }
double &operator[]( int i ){ return V[i]; }
double operator[]( int i ) const { return V[i]; }
double V[3]; //要素
};
//3次元ベクトルVに直行する3次元ベクトルを返す.
//(無限に有り得るうちのどれか一つ.もちろん,ゼロベクトルではない.)
//※ただし,Vがゼロベクトルの時は,戻り値は何らかの単位ベクトルを返すこととする.
Vec3 GetPerpendicularOf( const Vec3 &V )
{
//Vの3要素の絶対値を比較して{最大,真ん中,最小}の要素のindex {iMax,iMddle,iMin}を求む
const double Abs[3] = { fabs(V[0]), fabs(V[1]), fabs(V[2]) };
int iMax = 0;
if( Abs[iMax] < Abs[1] ){ iMax=1; }
if( Abs[iMax] < Abs[2] ){ iMax=2; }
int iMiddle = (iMax+1)%3;
int iMin = (iMax+2)%3;
if( Abs[iMiddle] < Abs[iMin] ){ std::swap( iMiddle, iMin ); }
//Vに直行するベクトルRを作る
Vec3 R; //(0,0,0)
if( Abs[iMiddle] <= std::numeric_limits<double>::epsilon() )
{//Vの要素のうち,2つ以上が0と見なせるとき
R[iMin] = 1;
}
else
{//少なくともV[iMiddle]が0ではない値であるとき
R[iMiddle] = V[iMin];
R[iMin] = -V[iMiddle];
}
return R;
}
//
inline std::ostream &operator <<( std::ostream &OS, const Vec3 &V )
{ return ( OS << "[ " << V[0] << ", " << V[1] << ", " << V[2] << " ]" ); }
//
int main()
{
//テストコード
std::random_device seed_gen;
std::mt19937 engine( seed_gen() );
std::uniform_real_distribution<> dist( -10000, 10000 );
for ( int i=0; i<32; ++i )
{
Vec3 V( dist(engine), dist(engine), dist(engine) );
Vec3 R = GetPerpendicularOf( V );
double IP = V[0]*R[0] + V[1]*R[1] + V[2]*R[2]; //innner-product
std::cout << "V = " << V << std::endl;
std::cout << "R = " << R << std::endl;
std::cout << "IP = " << IP << std::endl;
std::cout << std::endl;
}
//
Vec3 R = GetPerpendicularOf( Vec3() );
std::cout << "ResultOf(0,0,0) = " << R << std::endl;
//
std::cin.ignore();
return 0;
}
・何らかの課題ではありません.
以上,宜しくお願い申し上げます.