Exemple #1
0
        // series near the origin; this is entirely analogous to the Bessel series near the origin
        // it has a corresponding radius of rapid convergence, x < 4 + 2 Sqrt(nu)

        // This is exactly the same as BesselJ_Series with xx -> -xx.
        // We could even factor this out into a common method with an additional parameter.

        private static void ModifiedBesselI_Series(double nu, double x, out double I, out double IP)
        {
            if (x == 0.0)
            {
                if (nu == 0.0)
                {
                    I  = 1.0;
                    IP = 0.0;
                }
                else if (nu < 1.0)
                {
                    I  = 0.0;
                    IP = Double.PositiveInfinity;
                }
                else if (nu == 1.0)
                {
                    I  = 0.0;
                    IP = 0.5;
                }
                else
                {
                    I  = 0.0;
                    IP = 0.0;
                }
            }
            else
            {
                double x2 = x / 2.0;
                double xx = x2 * x2;
                double dI;
                if (nu < 128.0)
                {
                    dI = Math.Pow(x2, nu) / AdvancedMath.Gamma(nu + 1.0);
                }
                else
                {
                    dI = Math.Exp(nu * Math.Log(x2) - AdvancedMath.LogGamma(nu + 1.0));
                }
                I = dI; IP = nu * dI;
                for (int k = 1; k < Global.SeriesMax; k++)
                {
                    double I_old = I; double IP_old = IP;
                    dI *= xx / k / (nu + k);
                    I  += dI; IP += (nu + 2 * k) * dI;
                    if ((I == I_old) && (IP == IP_old))
                    {
                        IP = IP / x;
                        return;
                    }
                }
            }
        }
 private static double LogDoubleFactorial_Gamma(int n)
 {
     if (n % 2 == 0)
     {
         // m = n/2, n!! = 2^m Gamma(m+1)
         int m = n / 2;
         return(m * Global.LogTwo + AdvancedMath.LogGamma(m + 1.0));
     }
     else
     {
         // m = (n+1)/2, n!! = 2^m Gamma(m+1/2) / Sqrt(PI)
         int m = (n + 1) / 2;
         return(m * Global.LogTwo + AdvancedMath.LogGamma(m + 0.5) - Math.Log(Math.PI) / 2.0);
     }
 }
 /// <summary>
 /// Computes the logrithm of the factorial of an integer.
 /// </summary>
 /// <param name="n">The argument, which must be non-negative.</param>
 /// <returns>The value of ln(n!).</returns>
 /// <remarks>
 /// <para>This function provides accurate values of ln(n!) even for values of n which would cause n! to overflow.</para>
 /// </remarks>
 /// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is negative.</exception>
 /// <seealso cref="Factorial"/>
 public static double LogFactorial(int n)
 {
     if (n < 0)
     {
         throw new ArgumentOutOfRangeException(nameof(n));
     }
     else if (n < factorialTable.Length)
     {
         return(Math.Log((double)factorialTable[n]));
     }
     else
     {
         return(AdvancedMath.LogGamma(n + 1));
     }
 }
Exemple #4
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);
     }
 }