正弦の計算
出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2022/03/01 16:16 UTC 版)
「ルックアップテーブル」の記事における「正弦の計算」の解説
四則演算しか行えないようなコンピュータの多くでは、与えられた値の正弦を直接求めることはできないため、高い精度の正弦を求める際には、代わりにCORDICアルゴリズムを使用するか、または以下のようなテイラー展開を行う。 sin ( x ) ≈ x − x 3 6 + x 5 120 − x 7 5040 {\displaystyle \operatorname {sin} (x)\approx x-{\frac {x^{3}}{6}}+{\frac {x^{5}}{120}}-{\frac {x^{7}}{5040}}} (xが0に近い場合) しかし、この処理は(特に低速なコンピュータでは)計算に時間がかかる。また、コンピュータグラフィックス作成用のソフトウェアなどでは正弦値を求める処理が毎秒何千回も行われる。一般的な解決方法としては、予めある範囲の値の正弦を一定間隔で計算しておき、xの正弦を求める際はxに最も近い値の正弦を使用するという方法がある。正弦は連続関数であり、また値も一定範囲に収まるため、このような方法でもある程度正確な結果に近い値が得られる。処理は例えば以下のようになる。 real array sine_table[-1000..1000] for x from -1000 to 1000 sine_table[x] := sine(pi * x / 1000) function lookup_sine(x) return sine_table[round(1000 * x / pi)] ただし、このテーブルは相当の大きさになる。IEEE倍精度浮動小数点数を使用する場合なら、テーブルのサイズは16,000バイト以上にもなる。サンプル数を減らす方法もあるが、これは代わりに精度が著しく悪化する。この問題の一つの解決方法としては線形補間がある。これは、テーブル中でxと隣り合っている2つの値の間に直線を引き、この直線上の値を求めるという方法である。これは計算も速く、滑らかな関数においてもかなり正確な値を求められる。線形補間を利用した例は以下のようになる。 function lookup_sine(x) x1 := floor(x*1000/pi) y1 := sine_table[x1] y2 := sine_table[x1+1] return y1 + (y2-y1)*(x*1000/pi-x1) その他には、正弦と余弦の関係、および対称性を利用して、少しの計算時間を引き換えにテーブルのサイズを1/4にする方法がある。この場合、ルックアップテーブルを作成する際に、第一象限だけを対象とする(つまり、 0 ≦ x ≦ π 2 {\displaystyle 0\leqq x\leqq {\frac {\pi }{2}}} の範囲のみ正弦の計算を行う)。値を求める際は、変数を第一象限に当てはめなおす。角度を 0 ≦ x ≦ 2 π {\displaystyle 0\leqq x\leqq 2\pi } の範囲に直した後(元々 0 ≦ x ≦ 2 π {\displaystyle 0\leqq x\leqq 2\pi } の範囲しか考慮しないのであればこれは不要)、正しい値に変換して返す。つまり、第一象限ならテーブルの値をそのまま返し、第二象限なら π 2 − x {\displaystyle {\frac {\pi }{2}}-x} の値を返し、第三象限と第四象限の場合はそれぞれ第一象限と第二象限の値をマイナスにして返す。余弦を求める場合は、 π 2 {\displaystyle {\frac {\pi }{2}}} だけずらした値(つまり x + π 2 {\displaystyle x+{\frac {\pi }{2}}} で求めた値)を返せばよい。正接を求める場合は、余弦で正弦を割ればよい(実装によってはゼロ除算の処置が必要になる)。 function init_sine() for x from 0 to (360/4)+1 sine_table[x] := sine(2*pi * x / 360) function lookup_sine(x) x = wrap x from 0 to 360 y := mod (x, 90) if (x < 90) return sine_table[ y] if (x < 180) return sine_table[90-y] if (x < 270) return -sine_table[ y] return -sine_table[90-y] function lookup_cosine(x) return lookup_sine(x + 90) function lookup_tan(x) return (lookup_sine(x) / lookup_cosine(x)) 内挿を行う場合、不均一サンプリングを利用することでルックアップテーブルのサイズを削減できる。これは、関数の値が直線状にしか変化しない部分ではサンプリング点を減らし、そうでない部分ではサンプリング点を増やして近似値を実際の関数のカーブに近づけるという方法である。詳細については内挿を参照すること。
※この「正弦の計算」の解説は、「ルックアップテーブル」の解説の一部です。
「正弦の計算」を含む「ルックアップテーブル」の記事については、「ルックアップテーブル」の概要を参照ください。
- 正弦の計算のページへのリンク