web-dev-qa-db-ja.com

三角関数はどのように機能しますか?

そのため、高校の数学、そしておそらく大学では、トリガー関数の使用方法、その機能、およびそれらが解決する問題の種類を教えられます。しかし、それらは常にブラックボックスとして私に提示されてきました。何かのサインまたはコサインが必要な場合は、電卓のsinまたはcosボタンを押すと設定が完了します。大丈夫です。

私が疑問に思っているのは、三角関数が通常どのように実装されるかです。

99
Jurassic_C

まず、何らかの範囲の縮小を行う必要があります。トリガー関数は周期的であるため、引数を標準間隔まで減らす必要があります。手始めに、角度を0〜360度に減らすことができます。しかし、いくつかのIDを使用することで、より少ないもので済むことを実感できます。 0〜45度の角度の正弦と余弦を計算する場合、bootstrapすべての角度のすべてのトリガー関数を計算する方法を使用できます。

引数を減らすと、ほとんどのチップは [〜#〜] cordic [〜#〜] アルゴリズムを使用してサインとコサインを計算します。コンピューターがテイラー級数を使用していると人々が言うのを聞くかもしれません。それは理にかなっていますが、そうではありません。 CORDICアルゴリズムは、効率的なhardware実装により適しています。 (Softwareライブラリは、たとえば、Trig関数をサポートしないハードウェア上でTaylorシリーズを使用する場合があります。)CORDICアルゴリズムを使用して、追加の処理が行われる場合があります。かなり良い答えを得ることができますが、その後、精度を向上させるために他の何かをします。

上記にはいくつかの改良点があります。たとえば、θ(ラジアン単位)が非常に小さい場合は、sin(theta)= thetaをすべての精度で使用するため、他のアルゴリズムを使用するよりも単純にthetaを返す方が効率的です。したがって、実際には、可能なすべてのパフォーマンスと精度を絞り出す特別なケースロジックがたくさんあります。小規模な市場のチップは、最適化の努力をそれほど行っていない可能性があります。

141
John D. Cook

編集:Jack Ganssleは組み込みシステムに関する彼の本でまともな議論をしています "The Firmware Handbook"

参考:精度とパフォーマンスの制約がある場合、数値目的で関数を近似するために、テイラー級数notを使用する必要があります。 (Calculusコース用に保存します。)1つのポイントで関数analyticity を使用します。その時点ですべての派生物が存在するという事実。それらは、関心のある区間で必ずしも収束するわけではありません。多くの場合、評価点の近くで「完全」になるように、関数近似の精度を分散させるというお粗末な仕事をします。通常、エラーは回避されると上方にズームします。また、非連続微分(たとえば、方形波、三角波、およびそれらの積分)を持つ関数がある場合、テイラー級数は間違った答えを与えます。

最大次数Nの多項式を使用して、与えられた関数f(x)区間x0 <x <x1にわたって近似する場合、最良の「簡単な」解は Chebyshev近似 ;良い議論については、数値レシピを参照してください。リンクしたWolframの記事のTj(x)とTk(x)はcosと逆余弦を使用しましたが、これらは多項式であり、実際には再帰式を使用して係数を取得します。再び、数値レシピを参照してください。

編集:ウィキペディアには、 近似理論 に関するかなりまともな記事があります。彼らが引用する情報源の1つ(Hart、「コンピューター近似」)は絶版です(&使用されたコピーは高価になる傾向があります)が、このようなものについて多くの詳細に入ります。 (Jack Ganssleは、彼のニュースレターの39号でこれについて言及しています The Embedded Muse 。)

編集2:ここでは、sin(x)のTaylor vs. Chebyshevの具体的なエラー測定基準(下記参照)を示します。注意すべき重要な点:

  1. 与えられた範囲でのテイラー級数近似の最大誤差は、同程度のチェビシェフ近似の最大誤差よりもはるかに大きいこと。 (ほぼ同じエラーについては、チェビシェフを使用すると用語が1つ少なくなります。つまり、パフォーマンスが向上します)
  2. 範囲の縮小は大きな勝利です。これは、近似の間隔が小さくなると、高次多項式の寄与が小さくなるためです。
  3. 範囲の縮小に対応できない場合、係数をより正確に保存する必要があります。

誤解しないでください:テイラー級数はサイン/コサインに対して適切に機能します(範囲-pi/2から+ pi/2に合理的な精度を持ちます;技術的には、十分な用語で、すべての実際の入力に対して任意の精度に到達できますが、しかし、テイラー級数を使用してcos(100)を計算しようとすると、任意精度の算術演算を使用しない限り計算できません。非科学的な計算機を備えた無人島で立ち往生し、サインとコサインを計算する必要がある場合、係数は覚えやすいので、おそらくテイラー級数を使用します。しかし、独自のsin()またはcos()関数を作成する必要がある現実世界のアプリケーションは、効率的な実装を使用して望ましい精度に到達するのが最善であるほどまれです-テイラー級数はnot

範囲= -pi/2〜+ pi/2、次数5(3項)

  • テイラー:4.5e-3あたりの最大誤差、f(x) = x-x3/ 6 + x5/ 120
  • チェビシェフ:7e-5あたりの最大誤差、f(x) = 0.9996949x-0.1656700x3+ 0.0075134x5

範囲= -pi/2〜+ pi/2、次数7(4項)

  • テイラー:1.5e-4あたりの最大誤差、f(x) = x-x3/ 6 + x5/ 120-x7/ 5040
  • チェビシェフ:6e-7あたりの最大エラー、f(x) = 0.99999660x-0.16664824x3+ 0.00830629x5-0.00018363x7

範囲= -pi/4〜+ pi/4、次数3(2項)

  • テイラー:2.5e-3あたりの最大誤差、f(x) = x-x3/ 6
  • チェビシェフ:1.5e-4あたりの最大誤差、f(x) = 0.999x-0.1603x3

範囲= -pi/4〜+ pi/4、次数5(3項)

  • テイラー:3.5e-5あたりの最大誤差、f(x) = x-x3/ 6 + x5
  • チェビシェフ:6e-7あたりの最大エラー、f(x) = 0.999995x-0.1666016x3+ 0.0081215x5

範囲= -pi/4〜+ pi/4、次数7(4項)

  • テイラー:3e-7あたりの最大誤差、f(x) = x-x3/ 6 + x5/ 120-x7/ 5040
  • チェビシェフ:最大誤差1.2e-9、f(x) = 0.999999986x-0.166666367x3+ 0.008331584x5-0.000194621x7
47
Jason S

Taylor Series または [〜#〜] cordic [〜#〜] を使用して計算されていると思います。トリガー関数(ゲーム、グラフィックス)を頻繁に使用する一部のアプリケーションは、起動時にトリガーテーブルを作成するため、値を何度も再計算するのではなく、ルックアップするだけです。

14
Jon Galloway

Wikipediaの記事 トリガー関数について調べてください。実際にコードで実装することを学ぶのに適した場所は、 数値レシピ です。

私は数学者ではありませんが、罪、余韻、日焼けがどこから来るのかについての私の理解は、直角三角形で作業​​しているときに、ある意味でそれらが観察されるということです。さまざまな直角三角形の束の辺の長さを測定し、グラフにポイントをプロットすると、そこからsin、cos、およびtanを取得できます。 Harper Shelbyが指摘しているように、関数は単純に直角三角形のプロパティとして定義されています。

これらの比率が円の幾何学にどのように関係しているかを理解することにより、より洗練された理解が達成され、ラジアンとそのすべての良さにつながります。それはすべてウィキペディアのエントリにあります。

6
Parappa

最も一般的なコンピューターでは、べき級数表現は正弦と余弦の計算に使用され、これらは他のトリガー関数に使用されます。これらのシリーズを約8項に拡張すると、マシンのイプシロン(保持できるゼロ以外の最小の浮動小数点数)に近い精度で必要な値が計算されます。

CORDICメソッドはハードウェアに実装されているため高速ですが、標準のコンピューターではなく、主に組み込みシステムに使用されます。

1
Joshua Howard

@Jason Sによって提供される答えを拡張したいと思います。@ Jason Sによって説明されたものと同様のドメイン細分化方法を使用し、Maclaurin級数近似を使用して、tan()、sin()の平均(2-3)X 、cos()、atan()、asin()、およびacos()関数が-O3最適化でgccコンパイラーに組み込まれました。以下に説明する関数を近似する最高のMaclaurinシリーズは、倍精度の精度を達成しました。

Tan()、sin()、およびcos()関数の場合、および簡単にするために、重複する0〜2pi + pi/80ドメインは、pi/80、3pi/80の「アンカーポイント」で81等間隔に分割されました。 ...、161pi/80。次に、これらの81個のアンカーポイントのtan()、sin()、およびcos()が評価および保存されました。トリガーIDを使用して、各トリガー関数に対して単一のMaclaurinシリーズ関数が開発されました。関数は最初に入力角度を0から2pi領域に変換するため、±∞の間の任意の角度をトリガー近似関数に送信できます。この変換オーバーヘッドは、近似オーバーヘッドに含まれています。

同様のメソッドがatan()、asin()、およびacos()関数に対して開発されました。重複する-1.0から1.1ドメインは、アンカーポイントが-19/20、-17/20、...の21等間隔に分割されました。 。、19/20、21/20。次に、これら21のアンカーポイントのatan()のみが保存されました。この場合も、逆トリガーIDを使用して、atan()関数用に単一のMaclaurinシリーズ関数が開発されました。次に、atan()関数の結果を使用してasin()およびacos()を近似しました。

すべての逆トリガー近似関数はatan()近似関数に基づいているため、任意の倍精度引数入力値が許可されます。ただし、関数を近似するasin()およびacos()への引数入力は、それ以外の値は無意味であるため、±1ドメインに切り捨てられます。

近似関数をテストするために、10億のランダム関数評価が強制的に評価されました(つまり、-O3最適化コンパイラは、計算結果が使用されないため、評価をバイパスできませんでした)。乱数と結果の処理、トリガーまたは逆トリガー関数を評価せずに実行するコストが最初に実行されました。次に、各テストからこのバイアスを差し引いて、実際の関数評価時間のより代表的な近似値を取得しました。

表2.指定された1つまたは複数の機能を10億回実行するのにかかった時間(秒)推定値は、表1の残りの行から、表1の最初の行に示されている10億個の乱数を評価するための時間コストを引いて得られます。

Tan()で費やした時間:18.0515 18.2545

TAN3()で費やした時間:5.93853 6.02349

TAN4()で費やした時間:6.72216 6.99134

Sin()およびcos()で費やした時間:19.4052 19.4311

SINCOS3()で費やした時間:7.85564 7.92844

SINCOS4()で費やした時間:9.36672 9.57946

Atan()で費やした時間:15.7160 15.6599

ATAN1()で費やされた時間:6.47800 6.55230

ATAN2()で費やした時間:7.26730 7.24885

ATAN3()で費やした時間:8.15299 8.21284

Asin()およびacos()で費やされた時間:36.8833 36.9496

ASINCOS1()で費やした時間:10.1655 9.78479

ASINCOS2()で費やした時間:10.6236 10.6000

ASINCOS3()で費やした時間:12.8430 12.0707

(スペースを節約するために、表1は示していません。)表2は、各近似関数の10億回の評価を2回実行した結果を示しています。最初の列は最初の実行で、2番目の列は2回目の実行です。関数名の数字「1」、「2」、「3」または「4」は、特定のトリガー近似または逆トリガー近似を評価するためにマクラウリン級数関数で使用される項の数を示します。 SINCOS#()は、sinとcosの両方が同時に評価されたことを意味します。同様に、ASINCOS#()は、asinとacosの両方が同時に評価されたことを意味します。両方の数量を同時に評価する場合、余分なオーバーヘッドはほとんどありません。

結果は、用語の数を増やすと、予想されるように実行時間がわずかに増加することを示しています。最小数の項でさえ、その値が±無限大に近づく付近でのtan()近似を除いて、どこでも約12-14桁の精度を与えました。 tan()関数でさえ問題があると思われます。

UnixのハイエンドMacBook ProラップトップおよびLinuxのハイエンドデスクトップコンピューターでも同様の結果が得られました。

0
Roger Wehage