/// <summary> /// Computes the complex Gamma function. /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The complex value of Γ(z).</returns> /// <remarks> /// <para>The image below shows the complex Γ function near the origin using domain coloring.</para> /// <img src="../images/ComplexGammaPlot.png" /> /// </remarks> /// <seealso cref="AdvancedMath.Gamma(double)"/> /// <seealso href="http://en.wikipedia.org/wiki/Gamma_function" /> /// <seealso href="http://mathworld.wolfram.com/GammaFunction.html" /> public static Complex Gamma(Complex z) { if (z.Re < 0.5) { // 1-z form return(Math.PI / Gamma(1.0 - z) / ComplexMath.SinPi(z)); } else if (ComplexMath.Abs(z) < 16.0) { return(Lanczos.Gamma(z)); } else { // Add flag to do z-reduction return(ComplexMath.Exp(LogGamma_Stirling(z))); } }
/// <summary> /// Compute the complex log Gamma function. /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The principal complex value y for which exp(y) = Γ(z).</returns> /// <seealso cref="AdvancedMath.LogGamma" /> /// <seealso href="http://mathworld.wolfram.com/LogGammaFunction.html"/> public static Complex LogGamma(Complex z) { if (z.Im == 0.0 && z.Re < 0.0) { // Handle the pure negative case explicitly. double re = Math.Log(Math.PI / Math.Abs(MoreMath.SinPi(z.Re))) - AdvancedMath.LogGamma(1.0 - z.Re); double im = Math.PI * Math.Floor(z.Re); return(new Complex(re, im)); } else if (z.Re > 16.0 || Math.Abs(z.Im) > 16.0) { // According to https://dlmf.nist.gov/5.11, the Stirling asymptoic series is valid everywhere // except on the negative real axis. So at first I tried to use it for |z.Im| > 0, |z| > 16. But in practice, // it exhibits false convergence close to the negative real axis, e.g. z = -16 + i. So I have // moved to requiring |z| large and reasonably far from the negative real axis. return(Stirling.LogGamma(z)); } else if (z.Re >= 0.125) { return(Lanczos.LogGamma(z)); } else { // For the remaining z < 0, we need to use the reflection formula. // For large z.Im, SinPi(z) \propto e^{\pi |z.Im|} overflows even though its log does not. // It's possible to do some algebra to get around that problem, but it's not necessary // because for z.Im that big we would have used the Stirling series. Complex f = ComplexMath.Log(Math.PI / ComplexMath.SinPi(z)); Complex g = Lanczos.LogGamma(1.0 - z); // The reflection formula doesn't stay on the principal branch, so we need to add a multiple of 2 \pi i // to fix it up. See Hare, "Computing the Principal Branch of Log Gamma" for how to do this. // https://pdfs.semanticscholar.org/1c9d/8865836a312836500126cb47c3cbbed3043e.pdf Complex h = new Complex(0.0, 2.0 * Math.PI * Math.Floor(0.5 * (z.Re + 0.5))); if (z.Im < 0.0) { h = -h; } return(f - g + h); } }