Schnelle und genaue Implementierung einer unvollständigen Gammafunktion mit doppelter Genauigkeit


10

Wie werden Spezialfunktionen mit doppelter Genauigkeit auf dem neuesten Stand der Technik implementiert? Ich brauche die folgende Integral: fürm=0,1,2,. . . undt>0, was als niedrigere unvollständige Gammafunktion geschrieben werden kann. Hier ist meine Fortran- und C-Implementierung:

Fm(t)=01u2metu2du=γ(m+12,t)2tm+12
m=0,1,2,...t>0

https://gist.github.com/3764427

Bei Verwendung der Reihenerweiterung werden die Terme bis zur angegebenen Genauigkeit zusammengefasst und anschließend Rekursionsrelationen verwendet, um effizient Werte für niedrigeres . Ich habe es gut getestet und erhalte eine 1e-15-Genauigkeit für alle Parameterwerte, die ich benötige. Weitere Informationen finden Sie in den Kommentaren der Fortran-Version.m

Gibt es einen besseren Weg, um es umzusetzen? Hier ist eine Implementierung der Gammafunktion in Gfortran:

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

Es verwendet die rationale Funktionsnäherung, anstatt einige unendliche Reihen zusammenzufassen, die ich mache. Ich denke, das ist ein besserer Ansatz, weil man eine einheitliche Genauigkeit erhalten sollte. Gibt es eine kanonische Möglichkeit, sich diesen Dingen zu nähern, oder muss man für jede spezielle Funktion einen speziellen Algorithmus finden?

Update 1 :

Basierend auf den Kommentaren ist hier die Implementierung mit SLATEC:

https://gist.github.com/3767621

Es gibt Werte aus meiner eigenen Funktion wieder, ungefähr auf der Ebene der Genauigkeit 1e-15. Ich bemerkte jedoch ein Problem, dass für t = 1e-6 und m = 50 Term wird gleich 1e-303 und für höheres "m" gibt es einfach falsche Antworten. Meine Funktion hat dieses Problem nicht, da ich eine Reihenexpansions- / Wiederholungsrelation direkt fürFm verwende. Hier ist ein Beispiel für einen korrekten Wert:tm+12Fm

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

aber ich kann das nicht mit SLATEC bekommen, weil der Nenner explodiert. Wie Sie sehen können, ist der tatsächliche Wert von schön klein.Fm

Update 2 :

Um das obige Problem zu vermeiden, kann man die Funktion dgamit(Tricomis unvollständige Gammafunktion) verwenden, F(m, t) = dgamit(m+0.5_dp, t) * gamma(m+0.5_dp) / 2so dass es kein Problem mehr mit , aber leider explodiert das für m 172 . Dies könnte jedoch hoch genug sein , m für meine Zwecke.tgamma(m+0.5_dp)m172m


2
Warum Ihre eigene Funktion codieren? GSL, Cephes und SLATEC implementieren es alle.
Geoff Oxberry

Ich habe die Frage aktualisiert, warum ich SLATEC nicht verwende.
Ondřej Čertík

@ OndřejČertík Sie haben offenbar einen Fehler entdeckt! Ihre Frage positiv bewertet!
Ali

Ali --- es ist kein Fehler in SLATEC, aber in der Tatsache, dass ich tatsächlich teilen mussγ(z,x)tm+12Fm(t)γ(z,x)Fm(t)

@ OndřejČertík OK, sorry, mein Fehler, ich habe Ihren Code nicht überprüft, bevor ich meinen Kommentar abgegeben habe.
Ali

Antworten:


9

1015

mam+112

Für große Argumente berechne ich

Fm(a)=12γ(m+12,a)×p×p,  p=a12(m+12)

Diese Betriebsreihenfolge vermeidet vorzeitiges Unterlaufen. Da wir hier nur die niedrigere unvollständige Gammafunktion von halbzahligen Ordnungen anstelle einer vollständig allgemeinen unteren unvollständigen Gammafunktion benötigen, ist die Berechnung aus Sicht der Leistung vorteilhaft

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

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

Für kleine Argumente habe ich mit einer Reihenerweiterung für die untere unvollständige Gammafunktion von begonnen

A. Erdelyi, W. Magnus, F. Oberhettinger und FG Tricomi, "Higher Transcendental Functions, Vol. 2". New York, NY: McGraw-Hill 1953

Fm(a)

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

m=0,1,2,3F0(a)=π4aerf(a)erfERFerferff

m=1,2,3a<212Fm(a)=12a((2m1)Fm1(a)exp(a))

ammFm1=12m1(2a Fm(a)+exp(a))


Danke @njuffa für die tolle Antwort. Wenn Sie Ihren Code für dieses Open Source erstellen, ist er meiner Meinung nach für viele Menschen sehr nützlich.
Ondřej Čertík

1
Derzeit kann eine CUDA-Implementierung des beschriebenen Algorithmus kostenlos von der NVIDIA-Entwicklerwebsite heruntergeladen werden (erfordert eine kostenlose Registrierung als CUDA-Entwickler, Genehmigung normalerweise innerhalb eines Werktages). Der Code steht unter einer BSD-Lizenz, die mit nahezu jeder Art von Projekt kompatibel sein sollte.
Njuffa


4

Ich würde mir Abramowicz & Steguns Buch oder die neuere Version ansehen, die NIST vor ein paar Jahren veröffentlicht hat und die meiner Meinung nach online verfügbar ist. Sie diskutieren auch Möglichkeiten, Dinge stabil zu implementieren.


Ich habe dies verwendet: dlmf.nist.gov/8 , als ich es implementiert habe, aber das ist wahrscheinlich eine andere Ressource. Das Kapitel 5 in Numerische Rezepte enthält ebenfalls interessante Informationen, die jedoch nur für Funktionen einer Variablen gelten.
Ondřej Čertík

Ich glaube nicht, dass Sie etwas viel Neueres finden werden als die Referenz von 2001; SLATEC wird älter sein.
Geoff Oxberry

1

Es scheint nicht auf dem neuesten Stand der Technik zu sein, aber SLATEC bei Netlib bietet "1400 allgemeine mathematische und statistische Routinen". Das unvollständige Gamma steht hier unter den Sonderfunktionen zur Verfügung .

Die Implementierung solcher Funktionen ist zeitaufwändig und fehleranfällig, sodass ich sie nur dann selbst ausführen würde, wenn dies unbedingt erforderlich ist. SLATEC gibt es schon seit einiger Zeit und ist weit verbreitet, zumindest basierend auf der Anzahl der Downloads. Daher würde ich erwarten, dass die Implementierung ausgereift ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.