相変わらずゲーム作り・・・とはちょっとズレた、小さい関数や処理の高速化をちまちま調べてたり。
中学や高校の数学で、三角関数を習いはするものの、
「こんなの将来どこで使うんだ?」
なんて考えると、好きでもない勉強に身が入るわけも無いですね。
で、実際30過ぎまで三角関数なんて使う場面に合わなかった訳です。
仕事で組む業務用のシステムでも三角関数なんて使わないし。
でも2Dのゲームでは当たり前のように使うんですよね。
ゲーム作り始めて、「あんとき真面目にやっときゃ良かったー」ってよく思います。
学校の先生は「この関数はゲーム作りにも使われるんですよ」と、ちょっと例を出して教えてあげれば、クラスの2~3人は興味を示して身の入れ方が変わるんじゃないかなと思ったりするんですけどね。
あと3Dで当たり前に使う行列とかね。
それはさておき。
三角関数はゲーム(主に2D)で多用される割に重い処理です。
コレを軽くできると、ゲーム全体が軽くできる訳です。
で、ネットで三角関数の高速化方法を調べると色々出てきます。
予め計算結果をテーブル化しておく方法、「マクローリン展開」を途中まで処理してやめてしまう方法、「テイラー展開」を使用する方法などなど。
いずれも、標準関数でちゃんと計算した結果より精度が落ちる方法だけど、2Dゲーム限定で考えると十分許容できる精度なものです。
で、調べている中で、こんなコメントを見たりします。
8ビット機時代ならともかく、現在はFPUがある為、三角関数程度なら下手に近似計算するよりも高速だと思います。
数値計算の高速化 (cos, sin, exp) | OKWave
うん。じゃぁ、実際に試してみよう。
試してみたのは次の3通り
・VC++2008標準のsin/cos
・SeleneのFastSin/FastCos(テーブル使用)
・ネットで見つけたテイラー展開sin/cos
上記3つを、自作のタスクシステムに載せて調べてみました。
テスト環境は
・Core2Duo E6600
・AthlonXP 3500+
・PentiumM 1.1G
の3台。
本来ならソースも提示するべきなんだろうけど、ちょっと他人に見せられるようなコードじゃないんですみません。見栄え的な意味で。
単位はms。SinとCosを1回ずつ行う関数をタスク分(3,000)*10,000ループさせた時間。
無処理っていうのは、関数のなかを空っぽにした場合の時間。()内は、3,000*10,000の時間から無処理時間を弾いたもので、ざっくりとSin/Cosのみの処理時間になるはず。
– | 無処理 | 標準 | テーブル | テイラー |
---|---|---|---|---|
Core2Duo | 559 | 3,195(2,636) | 1,475(916) | 2,373(1,814) |
AthlonXP | 1,266 | 3,750(2,484) | 2,578(1,318) | 3,921(2,655) |
PentiumM | 1,602 | 7,911(6,309) | 3,645(2,043) | 6,909(5,307) |
標準のSin/Cosとテーブル使用版で約1.9~3倍。テイラー展開はだいたい標準と同じだから、精度落ちるし使う意味なさそう。
この結果を見る限り、3,000*10,000もの処理で2~3倍程度の違いしか出ないってことは、やっぱり通常は標準Sin/Cosで組んでおいて、パフォーマンスに不安が有るようだったら精度とトレードオフでテーブル使うってやり方でいいようですね。
SeleneのFastSin/FastCosは一周を4096個のテーブルで表現しているので、普通の2Dゲームだったら精度的にも問題にならないと思うし。
最初からSeleneで2Dゲームを組むつもりなら、角度を一周0~4096の整数型で統一すれば、通常の演算も早くなるし。
ホントはAtan2もやりたかったんだけど、テイラー展開版Atan2が見当たらなかったので断念。テーブル版はYaneSDK3rdから拝借できるんだけどねぇ。
テイラー展開とかマクローリン展開とか、言葉だけで内容全く知らんのですよ。