したがって、高校の数学、そしておそらく大学では、トリガー関数の使用方法、その機能、およびそれらが解決する問題の種類を教えられています。しかし、それらは常にブラックボックスとして提示されてきました。何かのサインまたはコサインが必要な場合は、電卓のsinまたはcosボタンを押すと、設定が完了します。それは結構です。
私が疑問に思っているのは、三角関数が通常どのように実装されているかです。
したがって、高校の数学、そしておそらく大学では、トリガー関数の使用方法、その機能、およびそれらが解決する問題の種類を教えられています。しかし、それらは常にブラックボックスとして提示されてきました。何かのサインまたはコサインが必要な場合は、電卓のsinまたはcosボタンを押すと、設定が完了します。それは結構です。
私が疑問に思っているのは、三角関数が通常どのように実装されているかです。
回答:
まず、ある範囲の縮小を行う必要があります。Trig関数は定期的であるため、引数を標準の間隔に減らす必要があります。まず、角度を0〜360度に減らすことができます。しかし、いくつかのIDを使用することで、少ないリソースでうまくいくことがわかります。0〜45度の角度の正弦と余弦を計算する場合、すべての角度のすべてのトリガー関数を計算する方法をブートストラップできます。
引数を減らすと、ほとんどのチップはCORDICアルゴリズムを使用してサインとコサインを計算します。コンピュータがテイラー級数を使用していると人々が言うのを聞くかもしれません。それは合理的に聞こえますが、それは本当ではありません。CORDICアルゴリズムは、効率的なハードウェア実装により適しています。(ソフトウェアライブラリは、トリガー関数をサポートしていないハードウェアで言うと、Taylorシリーズを使用する場合があります。)CORDICアルゴリズムを使用してかなり良い答えを得るが、精度を向上させるために何か他のことを行う追加処理がある場合があります。
上記にはいくつかの改良点があります。たとえば、非常に小さい角度theta(ラジアン単位)の場合、sin(theta)= thetaはすべての精度に対応しているため、他のアルゴリズムを使用するよりも単にthetaを返す方が効率的です。したがって、実際には、可能なすべてのパフォーマンスと精度を絞り出すための特別なケースロジックがたくさんあります。市場が小さいチップは、最適化にそれほど努力を払わないかもしれません。
編集:ジャックガンスルは、組み込みシステムに関する本「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)のチェビシェフの具体的なエラーメトリック(以下を参照)を以下に示します。注意すべきいくつかの重要な点:
誤解しないでください:Taylorシリーズは正弦/余弦に対して適切に機能します(-pi / 2から+ pi / 2の範囲の妥当な精度で;技術的には、十分な項があれば、すべての実際の入力で任意の精度に到達できます。しかし、テイラー級数を使用してcos(100)を計算しようとすると、任意精度の算術を使用しない限り、実行できません)。非科学的な計算機で無人島に行き詰まり、サインとコサインを計算する必要がある場合、係数が覚えやすいので、おそらくテイラー級数を使用します。ただし、独自のsin()関数またはcos()関数を作成する必要のある実際のアプリケーションは非常にまれであるため、効率的な実装を使用して目的の精度に到達するのが最善の方法です(テイラーシリーズではありません)。
範囲= -pi / 2〜+ pi / 2、次数5(3項)
範囲= -pi / 2〜+ pi / 2、次数7(4項)
範囲= -pi / 4〜+ pi / 4、次数3(2項)
範囲= -pi / 4〜+ pi / 4、次数5(3項)
範囲= -pi / 4〜+ pi / 4、7度(4項)
トリガー関数に関するウィキペディアの記事をチェックしてください。実際にコードでそれらを実装する方法について学ぶのに適した場所は、数値レシピです。
私は数学者ではありませんが、罪、余弦、日焼けがどこから「どこから来たのか」についての私の理解は、ある意味では、直角三角形を操作しているときに観察されるということです。さまざまな直角三角形の束の辺の長さを測定し、その点をグラフにプロットすると、sin、cos、tanを得ることができます。Harper Shelbyが指摘するように、関数は単純に直角三角形のプロパティとして定義されます。
これらの比率が円のジオメトリにどのように関連するかを理解することで、より洗練された理解が得られ、ラジアンとそのすべての良さにつながります。それはすべてウィキペディアのエントリにあります。
@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のハイエンドデスクトップコンピューターでも同様の結果が得られました。