三角メソッド

どうせ土曜日は書かないだろうから、先に書いちゃう。
math.hの三角関数のメソッドの速度が遅いことは有名だが、この解決策として「配列に360度分のcos、sinの結果を格納しておく」という方法が有効かどうかを調べてみた。

以下、技術的な内容になるので、興味のある人だけ続きを読んでくだされ。

float m_SinArray[361], m_CosArray[361];
に、0〜360度のcosとsinの結果を入れておく。これをどう取り出すか、なんだが、角度を整数(0〜360)で扱ってるうちは、たしかにこっちのほうが早い。しかし、元の角度がラジアン角(0〜6.28)の場合、3.14で割って180をかけるという処理が必要になる。この計算が、ことのほか重い。angle/3.14*180 を angle*57.324という風に省略したところ、元のメソッドの70%まで処理時間を短縮できた。以下、そのソース。


float CLLUtil::GetCos( float rad ){
int angle = (int)(rad * 57.324f);
if( angle >= 360 ) angle = angle % 360;
if( angle < 0 ) angle = 360 + angle % 360;
return CLLUtil::m_CosArray[ angle ];
}

より早くするため、メソッドのオーバーヘッドとインスタンス生成をごっそりなくしてしまう方法を考えてみた。何度も何度も呼ぶ処理の中でネックになりやすいオーバーヘッドをなくすため、計算処理をUtilクラスのスタティックメソッドではなく、プリプロセッサで定義したマクロに詰め込んでみる。


#define GET_COS( _rad , _result )\
{\
_result = _rad * 57.324f;\
if( _result >= 360 ) _result = (int)_result % 360;\
if( _result < 0 ) _result = 360 + (int)_result % 360;\
_result = g_CosArray[ (int)_result ];\
}
この結果、処理時間をcosメソッドの35%にまで短縮できた。もっとも、この方法はインスタンス生成とメソッド呼び出しオーバーヘッドにかかる時間が大幅なネックとなっている場合にのみ効果的な方法である。またマクロ定義なので変数の型に制限がなく、バグの発生源にもなりえる。結局「実行速度>メンテナンス性」の場合にだけしか使えない。それに単発で呼び出したいときは、math.hの三角関数を呼び出してもそんなに変わらない。

結論

おとなしくmath.h使ったほうがいいのかなぁ。

さらに

改造してみた。3項演算子を駆使したところ、何がなにやらわからんが最速w 可読性の大事さを思い知るね。


#define GET_COS4( _rad , _temp )\
( (_temp = _rad * 57.324f) >= 360 ) ? \
CLLUtil::m_CosArray[ ((int)_temp % 360) ] : \
( _temp < 0 ) ? \
CLLUtil::m_CosArray[ (360 + (int)_temp % 360) ] : \
CLLUtil::m_CosArray[ (int)_temp ]