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


101

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

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


トリガー関数とは何か、またはそれらがどのように実装されているかについて混乱していますか?
カイルクローニン

15
私は彼らが何であるかを知っています。私は彼らが何をしているのか知っています。私は、どの目的で何が必要かを判断する方法を知っています。角度と距離の関係についてお話しします。私が探していたのは、ジョン・D・クックの答えに沿ったものでした。そして、実際のアルゴリズムに言及した他のすべての人
Jurassic_C

これは良い質問です。たとえば、サイン、コサイン、タンジェントは超越関数であり、それらを解決することは困難です...一方、これらは、有限の精度まで正しい答えを与える単純なテイラー級数展開を使用して定義できます。必須。
Alex

回答:


144

まず、ある範囲の縮小を行う必要があります。Trig関数は定期的であるため、引数を標準の間隔に減らす必要があります。まず、角度を0〜360度に減らすことができます。しかし、いくつかのIDを使用することで、少ないリソースでうまくいくことがわかります。0〜45度の角度の正弦と余弦を計算する場合、すべての角度のすべてのトリガー関数を計算する方法をブートストラップできます。

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

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


4
すばらしい答え-CORDICはそれ自体は範囲縮小自体を必要としませんが(実際には、本質的にそれ自体が範囲縮小アルゴリズムです)、-pi / 2と+ pi / 2の間の角度では問題なく機能するので、その範囲外の角度に対してベクトルを180度回転させる必要があります。
Jason S、

3
多項式近似を使用する実装では、テイラー級数を使用することがよくありますが、通常 Remezアルゴリズムで決定された係数を使用する必要があります。lolengine.net/blog/2011/12/21/better-function-approximations
Pascal Cuoq

1
CORDICが使用する値のテーブルは事前に計算する必要があることに注意してください。したがって、テイラーは「コンパイル時」でも使用される可能性があります。
Rhubbarb 2013年

2
この回答は、この同様の質問に対する高評価の受け入れられた回答とは矛盾するようです:stackoverflow.com/questions/2284860/…。この答えは、他のC.に述べていながら罪()関数は、主に、ハードウェアレベルで実装されていることを述べている
ペリー

48

編集:ジャックガンスルは、組み込みシステムに関する本「The Firmware Handbook」で、まともな議論をしています。

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

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

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

編集2:テイラーとsin(x)のチェビシェフの具体的なエラーメトリック(以下を参照)を以下に示します。注意すべきいくつかの重要な点:

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

誤解しないでください:Taylorシリーズは正弦/余弦に対して適切に機能します(-pi / 2から+ pi / 2の範囲の妥当な精度で;技術的には、十分な項があれば、すべての実際の入力で任意の精度に到達できます。しかし、テイラー級数を使用してcos(100)を計算しようとすると、任意精度の算術を使用しない限り、実行できません)。非科学的な計算機で無人島に行き詰まり、サインとコサインを計算する必要がある場合、係数が覚えやすいので、おそらくテイラー級数を使用します。ただし、独自のsin()関数またはcos()関数を作成する必要のある実際のアプリケーションは非常にまれであるため、効率的な実装を使用して目的の精度に到達するのが最善の方法です(テイラーシリーズではありません)

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

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

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

  • テイラー:1.5E-4、F(X)= X-Xの周り最大誤差3 /6 + X 5 /120 X 7 /5040
  • チェビシェフ:6e-7あたりの最大誤差、f(x)= 0.99999660x-0.16664824x 3 + 0.00830629x 5 -0.00018363x 7

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

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

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

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

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

  • テイラー:3E-7、F(X)= X-Xの周り最大誤差3 /6 + X 5 /120 X 7 /5040
  • チェビシェフ:1.2e-9あたりの最大エラー、f(x)= 0.999999986x-0.166666367x 3 + 0.008331584x 5 -0.000194621x 7

2
このコメントは間違っています。すべての近似には時間と場所があります。系列近似の収束領域を決定するのに十分な分析がわからない場合は、使用しないでください。それはテイラー、チェビシェフ、パデなどのシリーズに当てはまります。多くの場合、テイラーシリーズは十分に優れています。
kquinn 2009

4
:shrug:私はあなたについては知りませんが、たった1点の小さな近傍で関数を評価することに興味がありませんでした。ある間隔で最小二乗法を適用するのは簡単です。テイラーシリーズを使用している人は誰もが要点を逃しています。
Jason S、

1
@kquinn:チェビシェフ近似の収束領域は、それらが計算される間隔がプロセスへの明示的な入力であるため、有用な概念ではありません。
Jason S、

2
応答者がハートの存在を知っていたため賛成票を投じました。:smile:25年前に(印刷された)コピーを購入したときに見つけるのが困難だったとしても、ハートはここでの古典的なリファレンスです。それはすべてのペニーの価値があります。可能な限り範囲を縮小し、適切な近似と組み合わせて、パデ、チェビシェフ、さらには適切なテイラー級数であっても、良いアプローチです。ただし、通常はパデまたはチェビシェフ近似がテイラー級数よりも優れています。

3
??? どう違うの?-2piから+ 2piまでのsin(x)を計算するための17度までのテイラー級数は、おそらく7度または9度の多項式でチェビシェフによって打ち負かされます。「樹木を伐採するときに時間の制約がある場合は、ハンドソーを使用しないでください。チェーンソーを使用してください。」と言っても問題はありません。おそらく、「すべきではない」から「テイラーシリーズの使用はお勧めしません」のように書き直すべきでしょう。もちろん、場合によってはTaylorシリーズを使用することもできますが、精度とパフォーマンスに問題があります。パフォーマンスとは、CPU実行時間を意味します。
Jason S

14

テイラーシリーズまたはCORDICを使用して計算されたと思います。トリガー関数(ゲーム、グラフィック)を頻繁に使用する一部のアプリケーションは、起動時にトリガーテーブルを構築するため、値を何度も再計算するのではなく、単に値を調べることができます。


6

トリガー関数に関するウィキペディアの記事をチェックしください。実際にコードでそれらを実装する方法について学ぶのに適した場所は、数値レシピです。

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

これらの比率が円のジオメトリにどのように関連するかを理解することで、より洗練された理解が得られ、ラジアンとそのすべての良さにつながります。それはすべてウィキペディアのエントリにあります。


1

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

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


0

@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を使用して、トリガー関数ごとに1つのMaclaurin系列関数が開発されました。関数は最初に入力角度を0から2piのドメインに変換するため、±無限大の間の任意の角度をトリガー近似関数に送信できます。この変換オーバーヘッドは、概算オーバーヘッドに含まれています。

同様のメソッドがatan()、asin()、およびacos()関数用に開発されました。重複する-1.0から1.1のドメインは、アンカーポイントが-19 / 20、-17 / 20で21の等間隔に分割されました。 。、19 / 20、21 / 20。次に、これらの21のアンカーポイントのatan()のみが格納されました。繰り返しになりますが、逆トリガーIDの助けを借りて、単一のMaclaurin系列関数がatan()関数用に開発されました。次に、atan()関数の結果を使用して、asin()およびacos()を概算しました。

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

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

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

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」は、特定のトリガーまたは逆トリガー近似を評価するためにMaclaurin級数関数で使用される項の数を示します。SINCOS#()は、sinとcosの両方が同時に評価されたことを意味します。同様に、ASINCOS#()は、asinとacosの両方が同時に評価されたことを意味します。両方の量を同時に評価する場合、追加のオーバーヘッドはほとんどありません。

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

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


-5

罪、余弦、日焼けのより物理的な説明を求める場合は、直角三角形との関係を検討してください。cos(lambda)の実際の数値は、角度の1つがラムダである直角三角形を形成し、ラムダに隣接する三角形の辺の長さを斜辺の長さで割ることによって求めることができます。同様に罪のために斜辺で割った反対側を使用します。接線の場合は、反対側を隣接する側で割って使用します。これを思い出すための定番のメモは、ソカトア(SOHCAHTOA)です。

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