Quelle est la manière la plus moderne de mettre en œuvre des fonctions spéciales double précision? J'ai besoin de l'intégrale suivante: pour et , qui peut être écrit en termes de fonction gamma incomplète inférieure. Voici mon implémentation Fortran et C: m=0,1,2,. . . t>0
https://gist.github.com/3764427
qui utilise l'expansion en série, résume les termes jusqu'à la précision donnée, puis utilise les relations de récursivité pour obtenir efficacement des valeurs pour inférieur . Je l'ai bien testé et j'obtiens une précision de 1e-15 pour toutes les valeurs de paramètres dont j'ai besoin, voir les commentaires de la version Fortran pour plus de détails.
Existe-t-il un meilleur moyen de le mettre en œuvre? Voici une implémentation de la fonction gamma dans gfortran:
https://github.com/mirrors/gcc/blob/master/libgfortran/intrinsics/c99_functions.c#L1781
il utilise l'approximation de fonction rationnelle au lieu de résumer une série infinie que je fais. Je pense que c'est une meilleure approche, car il faut obtenir une précision uniforme. Existe-t-il une manière canonique d'aborder ces choses, ou faut-il trouver un algorithme spécial pour chaque fonction spéciale?
Mise à jour 1 :
Sur la base des commentaires, voici l'implémentation utilisant SLATEC:
https://gist.github.com/3767621
il reproduit les valeurs de ma propre fonction, à peu près au niveau de précision 1e-15. Cependant, j'ai remarqué un problème: pour t = 1e-6 et m = 50, le terme est égal à 1e-303 et pour un "m" supérieur, il commence simplement à donner des réponses incorrectes. Ma fonction n'a pas ce problème, car j'utilise une série de relations expansion / récurrence directement pour . Voici un exemple de valeur correcte: Fm
(1e-6)=4.97511945200351715E-003
,
mais je ne peux pas obtenir cela en utilisant SLATEC parce que le dénominateur explose. Comme vous pouvez le voir, la valeur réelle de est belle et petite.
Mise à jour 2 :
Pour éviter le problème ci-dessus, on peut utiliser la fonction dgamit
(la fonction Gamma incomplète de Tricomi), donc F(m, t) = dgamit(m+0.5_dp, t) * gamma(m+0.5_dp) / 2
, il n'y a plus de problème avec , mais malheureusement le souffle pour . Cela pourrait cependant être assez élevé pour mes besoins.m ≈ 172 mgamma(m+0.5_dp)