不完全でガンマ関数の高速かつ正確な倍精度実装


10

倍精度特殊関数を実装する最新の方法は何ですか?:私は、次の積分必要 ため、M=012そして、t>0で、これは下側の不完全ガンマ関数で書くことができます。これが私のFortranとCの実装です。

Fメートルt=01あなた2メートルetあなた2dあなた=γメートル+12t2tメートル+12
メートル=012t>0

https://gist.github.com/3764427

これは級数展開を使用し、指定された精度になるまで項を合計し、再帰関係を使用してより低い値を効率的に取得します。私はそれをうまくテストし、必要なすべてのパラメーター値に対して1e-15の精度を取得しました。詳細については、Fortranバージョンのコメントを参照してください。メートル

それを実装するより良い方法はありますか?以下は、gfortranでのガンマ関数の実装です。

https://github.com/mirrors/gcc/blob/master/libgfortran/intrinsics/c99_functions.c#L1781

私がしている無限級数を合計する代わりに、有理関数近似を使用しています。均一な精度を得る必要があるので、これはより良いアプローチだと思います。これらのものにアプローチするためのいくつかの標準的な方法はありますか、または各特別な関数の特別なアルゴリズムを理解する必要がありますか?

アップデート1

コメントに基づいて、SLATECを使用した実装を次に示します。

https://gist.github.com/3767621

おおよそ1e-15の精度で、私自身の関数の値を再現します。ただし、t = 1e-6およびm = 50の場合、項は1e-303に等しくなり、より高い "m"の場合は、誤った答えを出し始めます。Fmに直接級数展開/再帰関係を使用するため、関数にこの問題はありません。正しい値の例を次に示します。tメートル+12Fメートル

F100(1e-6)=4.97511945200351715E-003

しかし、分母が爆発するため、SLATECを使用してこれを取得することはできません。ご覧のとおり、実際の値は小さく、小さくなっています。Fメートル

アップデート2

上記の問題を回避するために、1機能を使用することができますdgamit(Tricomiの不完全ガンマ関数)を、そしてF(m, t) = dgamit(m+0.5_dp, t) * gamma(m+0.5_dp) / 2、その問題がないもはや、残念ながら吹くアップのためのM 172。しかし、これは十分に高いかもしれませんメートルtgamma(m+0.5_dp)メートル172メートル私の目的のために。


2
なぜ独自の関数をコーディングするのですか?GSL、cephes、SLATECはすべてGSLを実装しています。
Geoff Oxberry

SLATECを使用しない理由を更新しました。
オンドレジ・セティク

@OndřejČertíkバグを発見しました!あなたの質問に賛成しました!
アリ

Ali --- SLATECのバグではありませんが、実際には、t m + 1で除算する必要がありますγzバツ Fmt)の値を取得するため。したがって、γzxに対して機能する数値法は、Fmtに対してはあまり機能しない可能性があります。tメートル+12FメートルtγzバツFメートルt
オンドレジ・セティク

@OndřejČertíkわかりました。申し訳ありませんが、間違いです。コメントする前にコードをチェックしませんでした。
アリ

回答:


9

問題の積分は、1950年代初頭にその使用を導入した英国の化学者サミュエルフランシスボーイズの後、ボーイズ関数としても知られています。数年前、私はこの関数を可能な限り速く正確に倍精度で計算する必要がありました。私は、程度の相対誤差を達成するために管理全入力ドメイン全体を。1015

一般に、「大」と「小」の間の最適な切り替えが実験的に最もよく決定され、一般的に関数である場合、小引数と大引数に異なる近似を使用することが有利です。私のコードのために、私は条件を満たすものとして、「小」の引数が定義され、A M + 1 1メートルaメートル+112

大きな引数の場合、私は計算します

Fメートルa=12γメートル+12a×p×p  p=a12メートル+12

この操作順序により、早期のアンダーフローが回避されます。ここでは、完全に一般的な低い不完全ガンマ関数ではなく、半整数次の低い不完全ガンマ関数のみが必要であるため、パフォーマンスの観点から計算すると有利です。

γ(m+12,a)=Γ(m+12)Γ(m+12,a)

集計値用い及び計算ΓM+1Γ(m+12)この回答によれば 、融合型積和演算の使用による減算キャンセルの問題は慎重に回避されます。さらなる最適化の可能性は、十分に大きいaγm+1Γ(m+12,a)a与えられた浮動小数点精度内。γ(m+12,a)=Γ(m+12)

小さな引数については、以下の不完全なガンマ関数の級数展開から始めました

A. Erdelyi、W。Magnus、F。Oberhettinger、およびFG Tricomi、「Higher Transcendental Functions、Vol。2」。ニューヨーク、ニューヨーク:McGraw-Hill 1953

そして、次のようにBoys関数を計算するように修正しました(項が与えられた精度に対して十分に小さい場合、系列を切り捨てます)。Fm(a)

Fm(a)=121m+12exp(a)(1+n=1an(1+m+12)× ... ×(n+m+12))

m=0,1,2,3F0a=π4aerfaerfERFerferff

メートル=12a<212Fメートルa=12a2メートル1Fメートル1aexpa、大きなものの場合、後者での減算によるキャンセルの問題は、融合型積和演算の使用によって軽減されます。

aメートルメートルFメートル1=12メートル12a Fメートルa+expa


素晴らしい答えをありがとう@njuffa。このオープンソース用のコードを作成すると、多くの人にとって非常に役立つと思います。
オンドレジ・セティク

1
現在、説明されているアルゴリズムのCUDA実装は、NVIDIAの開発者向けWebサイトから無料でダウンロードできます(CUDA開発者としての無料登録、通常は1営業日以内の承認が必要です)。コードはBSDライセンスの下にあり、ほぼすべての種類のプロジェクトと互換性があります。
njuffa 2016年


4

私はAbramowicz&Stegunの本、またはNISTが数年前に発行した新しい改訂版を見て、それはオンラインで入手できると思います。また、安定した方法で物事を実装する方法についても説明します。


私はこれを使用していた:dlmf.nist.gov/8、それを実装するとき、それはおそらく別のリソースです。数値レシピの第5章にも興味深い情報がありますが、1つの変数の関数にのみ適用できます。
オンドレジ・セティク

2001年の参考文献よりも最近のものは見当たらないと思います。SLATECはそれよりも古いものになります。
Geoff Oxberry

1

最先端ではないようですが、NetlibのSLATECは「1400汎用の数学および統計ルーチン」を提供しています。不完全なガンマは、ここ特別な機能の下で利用できます

このような関数の実装には時間がかかり、エラーが発生しやすいので、どうしても必要な場合を除いて、自分で実装することはありません。SLATECはかなり以前から存在しており、少なくともダウンロード数に基づいて広く使用されているので、実装は成熟していると思います。

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