Example #1
0
 /// <summary>
 /// Computes the complex Gamma function.
 /// </summary>
 /// <param name="z">The complex argument.</param>
 /// <returns>The complex value of &#x393;(z).</returns>
 /// <remarks>
 /// <para>The image below shows the complex &#x393; 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)));
     }
 }
Example #2
0
 /// <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) = &#x393;(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);
     }
 }