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:
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.
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:
,(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.
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) / 2
so 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.gamma(m+0.5_dp)