Qual è il modo più avanzato di implementare funzioni speciali a doppia precisione? Ho bisogno del seguente integrale: perm=0,1,2,. . . et>0, che può essere scritto in termini della funzione gamma incompleta inferiore. Ecco la mia implementazione Fortran e C:
https://gist.github.com/3764427
che utilizza l'espansione in serie, riassume i termini fino alla precisione data e quindi utilizza le relazioni di ricorsione per ottenere in modo efficiente valori per inferiori . L'ho testato bene e ottengo una precisione 1e-15 per tutti i valori dei parametri di cui ho bisogno, vedere i commenti della versione Fortran per i dettagli.
C'è un modo migliore per implementarlo? Ecco un'implementazione della funzione gamma in gfortran:
https://github.com/mirrors/gcc/blob/master/libgfortran/intrinsics/c99_functions.c#L1781
sta usando l'approssimazione di funzioni razionali invece di riassumere alcune serie infinite che sto facendo. Penso che sia un approccio migliore, perché si dovrebbe ottenere una precisione uniforme. Esiste un modo canonico per avvicinarsi a queste cose o si deve capire un algoritmo speciale per ogni funzione speciale?
Aggiornamento 1 :
Sulla base dei commenti, ecco l'implementazione con SLATEC:
https://gist.github.com/3767621
riproduce i valori della mia stessa funzione, approssimativamente al livello di precisione 1e-15. Tuttavia, ho notato un problema che per t = 1e-6 e m = 50, la termine 2 diventa uguale a 1e-303 e per una "m" più alta inizia semplicemente a dare risposte errate. La mia funzione non ha questo problema, perché uso una serie di relazioni di espansione / ricorrenza direttamente perFm. Ecco un esempio di un valore corretto:
,(1e-6)=4.97511945200351715E-003
ma non riesco a farlo usando SLATEC perché il denominatore esplode. Come puoi vedere, il valore reale di è bello e piccolo.
Aggiornamento 2 :
Per evitare il problema di cui sopra, si può usare la funzione dgamit
(la funzione Gamma incompleta di Tricomi), quindi F(m, t) = dgamit(m+0.5_dp, t) * gamma(m+0.5_dp) / 2
, quindi non ci sono più problemi con , ma sfortunatamente l' esplosione per m ≈ 172 . Questo però potrebbe essere abbastanza alto m per i miei scopi.gamma(m+0.5_dp)