より高速な正弦関数はありますか?


25

ジェネレーション3d perlinノイズに取り組んでいます。C#Mathライブラリは、ほとんどの関数が二重の精度を使用しているため、私が必要とするものに対してはやり過ぎのようです。いくつかの場所でMath.Sin()を使用してノイズを生成します。誰もがより高速な正弦関数を知っていますか?

回答:


32

放物線を使用して、正弦関数の値を近似できます。これには、TaylorSeriesまたはMaclaurinSeriesに基づく他の高速近似では通常そうではない、厳密に-pi / 2およびpi / 2に根を持つという利点があります。

public float Sin(float x)
{
    const float B = 4 / PI;
    const float C = -4 / (PI*PI);

    return -(B * x + C * x * ((x < 0) ? -x : x));
} 

以下は、実際のサイン関数との比較です。

alt text


3
これは確かに素晴らしい解決策です。これがdevmaster.netの優れた記事で、これが機能する理由と実装の詳細を説明しています。devmaster.net
forums

C#については知りませんが、ほとんどのC環境のabs()関数は、最適化されると、ブランチ(?:演算子)よりも高速になる可能性があります。

3
このコードがXbox 360またはWindows Phone 7で実行されると想定したため、Math.Abs​​()呼び出しを削除しました。Xbox360のJITコンパイラーは何もインライン化しません。Math.Abs​​()の呼び出しは、実際にはより高価です。
zfedoran


1
@zfedoranなぜ戻り値を無効にしますか?負の正弦波のようです。
ダニエルペンダーガスト

12

sin()関数への入力値の範囲はどのくらいですか?あなたがそれを使用しているものについては、それらが制限されているように聞こえますつまり、値を事前に計算することができます。たとえば、入力値を最も近い次数に切り上げる場合、可能な値は360のみです。事前に計算してテーブルに保存するだけです。

小数点以下1桁など、少し多くの値が必要な場合は、テーブルから補間することができます-perlin noiseには詳しくありませんが、「noise」という言葉は、高精度を必要としないことを示しているようです。:)(3600エントリは大きなスペースではなく、より大きなテーブルを作成することもできます)。


3
速度が一番の懸念事項であり、精度を少し犠牲にしても構わない場合は、これが最良の答えです。
AttackingHobo

1
「ベスト」については知りません-別の答えに示すように、5つのops + absで別の非常に良い近似を得ることができます(その速度は、あなたのarch /コンパイラによって異なりますが、多くの場合、ブランチレスです)。ルックアップテーブルがキャッシュにない場合、はるかに遅くなります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.