36

、、、、、(これらはmath.h/cmathから)のようなsqrt()関数の定義はありますか?sin()cos()tan()log()exp()

それらがどのように機能するのか知りたかっただけです。

4

8 に答える 8

66

これは興味深い質問ですが、使用されている方法を知らない限り、効率的なライブラリのソースを読んでもそれほど遠くはありません。

ここに、古典的な方法を理解するのに役立ついくつかの指針があります。私の情報は決して正確ではありません。以下のメソッドは古典的なメソッドにすぎません。特定の実装では他のメソッドを使用できます。

  • ルックアップテーブルが頻繁に使用されます
  • 三角関数は、多くの場合、CORDICアルゴリズム(CPUまたはライブラリのいずれか)を介して実装されます。sincos通常、正弦と余弦は一緒に計算されることに注意してください。標準Cライブラリが関数を提供しないのはなぜかといつも思っていました。
  • 平方根は、いくつかの巧妙な実装トリックでニュートン法を使用します。Webのどこかに、気が遠くなるような1 / sqrt(x)実装を備えたQuakeソースコードからの抜粋が見つかる場合があります。
  • 指数および対数は、exp(2 ^ nx)= exp(x)^(2 ^ n)およびlog2(2 ^ nx)= n + log2(x)を使用して、ゼロに近い引数(logの場合は1)を使用します。有理関数近似(通常はパデ近似)。これとまったく同じトリックで、行列指数と対数を取得できることに注意してください。@Stephen Canonによると、最近の実装では、除算が乗算よりもはるかに遅い有理関数近似よりもテイラー展開が優先されます。
  • 他の関数はこれらの関数から推測できます。実装は、特殊なルーチンを提供する場合があります。
  • pow(x、y)= exp(y * log(x))であるため、yが整数の場合はpowは使用されません
  • hypot(x、y)= abs(x)sqrt(1 +(y / x)^ 2)if x> y(hypot(y、x)それ以外の場合)オーバーフローを回避します。の呼び出しと小さなロジックatan2を使用して計算されます。sincosこれらの関数は、複雑な算術の構成要素です。
  • その他の超越関数(ガンマ、erf、ベッセルなど)については、優れた本Numerical Recipes、第3版でいくつかのアイデアを参照してください。古き良きAbramowitz&Stegunも便利です。http://dlmf.nist.gov/に新しいバージョンがあります。
  • Chebyshev近似、連分数展開(実際にはパデ近似に関連)、べき級数の経済化などの手法は、より複雑な関数で使用されます(たとえば、erf、bessel、またはgammaのソースコードを読み取る場合)。ベアメタルの単純な数学関数で実際に使用されているとは思えませんが、誰が知っていますか。概要については、数値レシピを参照してください。
于 2010-12-27T19:39:43.060 に答える
21

実装はそれぞれ異なる場合がありますが、glibc(GNU Cライブラリ)のソースコードから1つの実装を確認できます。

編集:グーグルコード検索はオフラインにされたので、私が持っていた古いリンクはどこにも行きません。

glibcの数学ライブラリのソースは次の場所にあります。

http://sourceware.org/git/?p=glibc.git;a=tree;f=math;h=3d5233a292f12cd9e9b9c67c3a114c64564d72ab;hb=HEAD

于 2010-12-27T19:14:40.000 に答える
7

glibc魔法、近似、アセンブリに満ちたさまざまな数学関数を実装する方法をご覧ください。

于 2010-12-27T19:16:41.107 に答える
5

間違いなくfdlibmソースを見てください。fdlibmライブラリは自己完結型であり、各関数は関連する数学の詳細な説明とともに十分に文書化されており、コードは非常に読みやすいので、これらは素晴らしいものです。

于 2010-12-28T01:45:36.067 に答える
4

数学コードをよく見てきたので、glibcを見るのはお勧めしません。コードを理解するのは非常に難しく、glibcの魔法に大きく依存しています。FreeBSDのmathlibは、どういうわけか時々遅くなる場合でも、はるかに読みやすくなります(ただしそれほどではありません)。

複雑な関数の場合、主な問題は境界の場合です。実際の関数ではnan / inf / 0の正しい処理はすでに困難ですが、複雑な関数の場合は悪夢です。C99標準では、多くのコーナーケースが定義されており、一部の関数には10〜20のコーナーケースがあります。最新のC99標準ドキュメントの付録Gを見て、アイデアを得ることができます。ロングダブルではフォーマットが標準化されていないため、難しいこともあります。私の経験では、ロングダブルではかなりの数のバグが予想されます。うまくいけば、拡張精度を備えたIEEE754の次の改訂版が状況を改善するでしょう。

于 2010-12-28T03:06:24.357 に答える
0

最新のハードウェアのほとんどには、これらの機能を非常に効率的に実装する浮動小数点ユニットが含まれています。

于 2010-12-28T10:58:23.663 に答える
-1

使用法:root(number、root、depth)

:root(16,2)== sqrt(16)== 4
:root(16,2,2)== sqrt(sqrt(16))== 2
:root(64,3)== 4

C#での実装

double root(double number, double root, double depth = 1f)
{
    return Math.Pow(number, Math.Pow(root, -depth));
}

使用法:Sqrt(数値、深さ)

:Sqrt(16)== 4
:Sqrt(8,2)== sqrt(sqrt(8))

double Sqrt(double number, double depth = 1) return root(number,2,depth);

作成者:Imk0tter

于 2020-05-09T17:05:20.520 に答える
-16

これらはほとんどの場合、システムコールとして実装されます。ソースを確認したい場合は、OSソースにアクセスする必要があります。つまり、LinuxやBSDなどのオープンソースOSを確認する必要があります。

于 2010-12-27T19:13:00.560 に答える