1. ホーム
  2. c

[解決済み】C言語ではsin()などの数学関数はどのように計算されるのですか?

2022-04-17 14:59:14

質問

.NETのディスアセンブリとGCCのソースコードに目を通しましたが、実際には sin() や他の数学関数は、常に他の何かを参照しているようです。

どなたか探すのを手伝っていただけませんか? C言語が動作するすべてのハードウェアがハードウェアで三角関数をサポートしているとは考えにくいので、ソフトウェアアルゴリズムがあるはずです。 どこかで ということですよね?


私が知っているのは できる また、遊びでテイラー級数を使って関数を計算するルーチンを自分で書いたこともあります。 私の実装はすべて、私のアルゴリズムがかなり賢いと思っていても、常に数桁は遅いので(明らかにそうではない)、実際の生産言語がどのようにそれを行っているのか興味があります。

どのように解決するのか?

GNU libmの実装では sin はシステム依存です。したがって、各プラットフォームの実装は、以下の適切なサブディレクトリのどこかで見つけることができます。 sysdeps .

あるディレクトリには、IBMが寄贈したC言語による実装が含まれています。2011年10月以降、このコードで sin() 典型的な x86-64 Linux システムの場合。の方が速いらしい。 fsin アセンブリ命令 ソースコード sysdeps/ieee754/dbl-64/s_sin.c を探します。 __sin (double x) .

このコードは非常に複雑です。の全範囲で可能な限り高速で、かつ正確なソフトウェアアルゴリズムはありません。 x そのため、このライブラリはいくつかの異なるアルゴリズムを実装しており、その最初の仕事は x で、どのアルゴリズムを使うかを決める。

  • いつ x は非常に 非常に は0に近い。 sin(x) == x が正しい答えです。

  • もうちょっと先 sin(x) は、おなじみのテイラー級数を使っています。しかし、これは0付近でしか正確ではないので...

  • 角度が約7°以上の場合は、別のアルゴリズムが使用され、sin(x) と cos(x) の両方についてテイラー列近似を計算し、事前に計算されたテーブルの値を使って近似を精緻化します。

  • の場合 x | そのため、0に近い値を計算することから始め、それを sin または cos の代わりに

  • さらにもう1つのブランチに対処する必要があります x はNaNまたは無限大である。

このコードでは、浮動小数点数の専門家の間では有名かもしれないが、私はこれまで見たことがない数値計算のハックをいくつか使っている。時には、数行のコードを説明するのに数段落かかることもあります。例えば、次の2行です。

double t = (x * hpinv + toint);
double xn = t - toint;

を減らすために使われる(こともある)。 x とは異なる0に近い値にします。 x をπ/2の倍数で、具体的には xn × π/2. 除算も分岐もしないこのやり方は、なかなか巧妙です。しかし、コメントが全くない!?


古い32ビット版のGCC/glibcでは fsin という命令がありますが、これはいくつかの入力に対して驚くほど不正確です。そこには このことをたった2行のコードで説明した興味深いブログ記事です。 .

fdlibm の実装は sin は、glibc のものよりずっとシンプルで、うまくコメントされています。ソースコードです。 fdlibm/s_sin.c fdlibm/k_sin.c