Exemple #1
0
 /// <summary>
 /// Computes the Gamma function.
 /// </summary>
 /// <param name="x">The argument.</param>
 /// <returns>The value of &#x393;(x).</returns>
 /// <remarks>
 /// <para>The Gamma function is a generalization of the factorial (see <see cref="AdvancedIntegerMath.Factorial"/>) to arbitrary real values.</para>
 /// <img src="../images/GammaIntegral.png" />
 /// <para>For positive integer arguments, this integral evaluates to &#x393;(n+1)=n!, but it can also be evaluated for non-integer z.</para>
 /// <para>Like the factorial, &#x393;(x) grows rapidly with increasing x; &#x393;(x) overflows <see cref="System.Double" />
 /// for all x larger than ~171. For arguments in this range, you may find it useful to work with the <see cref="LogGamma" /> method, which
 /// returns accurate values for ln(&#x393;(x)) even in the range for which &#x393;(x) overflows.</para>
 /// <para>To evaluate the Gamma function for a complex argument, use <see cref="AdvancedComplexMath.Gamma" />.</para>
 /// <h2>Domain, Range, and Accuracy</h2>
 /// <para>The function is defined for all x. It has poles at all negative integers and at zero; the method returns <see cref="Double.NaN"/> for these arguments. For positive
 /// arguments, the value of the function increases rapidly with increasing argument. For values of x greater than about 170, the value of the function exceeds
 /// <see cref="Double.MaxValue"/>; for these arguments the method returns <see cref="Double.PositiveInfinity"/>. The method is accurate to full precision over its entire
 /// domain.</para>
 /// </remarks>
 /// <seealso cref="AdvancedIntegerMath.Factorial" />
 /// <seealso cref="LogGamma" />
 /// <seealso cref="AdvancedComplexMath.Gamma" />
 /// <seealso href="http://en.wikipedia.org/wiki/Gamma_function" />
 /// <seealso href="http://mathworld.wolfram.com/GammaFunction.html" />
 /// <seealso href="http://dlmf.nist.gov/5">DLMF on the Gamma Function</seealso>
 public static double Gamma(double x)
 {
     if (x < 0.5)
     {
         // Use \Gamma(x) \Gamma(1-x) = \frac{\pi}{\sin(\pi x)} to move values close to and left of origin to x > 0
         return(Math.PI / MoreMath.SinPi(x) / Gamma(1.0 - x));
     }
     else if (x < 1.5)
     {
         return(GammaSeries.GammaOnePlus(x - 1.0));
     }
     else if (x < 2.5)
     {
         return(GammaSeries.GammaTwoPlus(x - 2.0));
     }
     else if (x < 16.0)
     {
         return(Lanczos.Gamma(x));
     }
     else if (x < 172.0)
     {
         return(Stirling.Gamma(x));
     }
     else if (x <= Double.PositiveInfinity)
     {
         // For x >~ 172, Gamma(x) overflows.
         return(Double.PositiveInfinity);
     }
     else
     {
         return(Double.NaN);
     }
 }
Exemple #2
0
 /// <summary>
 /// Computes the digamma function.
 /// </summary>
 /// <param name="x">The argument.</param>
 /// <returns>The value of &#x3C8;(x).</returns>
 /// <remarks>
 /// <para>The psi function, also called the digamma function, is the logrithmic derivative of the &#x393; function.</para>
 /// <img src="../images/DiGamma.png" />
 /// <para>Because it is defined as a <i>logarithmic</i> derivative, the digamma function does not overflow <see cref="System.Double"/>
 /// even for arguments for which <see cref="Gamma(double)"/> does.</para>
 /// <para>To evaluate the psi function for complex arguments, use <see cref="AdvancedComplexMath.Psi" />.</para>
 /// </remarks>
 /// <seealso cref="Gamma(double)"/>
 /// <seealso cref="AdvancedComplexMath.Psi"/>
 /// <seealso href="http://en.wikipedia.org/wiki/Digamma_function" />
 /// <seealso href="http://mathworld.wolfram.com/DigammaFunction.html" />
 public static double Psi(double x)
 {
     if (x < 0.5)
     {
         return(Psi(1.0 - x) - Math.PI / MoreMath.TanPi(x));
     }
     else if (x < 1.5)
     {
         return(GammaSeries.PsiOnePlus(x - 1.0));
     }
     else if (x < 2.5)
     {
         return(GammaSeries.PsiTwoPlus(x - 2.0));
     }
     else if (x < 16.0)
     {
         return(Lanczos.Psi(x));
     }
     else if (x <= Double.PositiveInfinity)
     {
         // For large arguments, the Stirling asymptotic expansion is faster than the Lanzcos approximation
         return(Stirling.Psi(x));
     }
     else
     {
         return(Double.NaN);
     }
 }
Exemple #3
0
        // one-argument functions

        /// <summary>
        /// Computes the natural logarithm of the Gamma function.
        /// </summary>
        /// <param name="x">The argument, which must be positive.</param>
        /// <returns>The log Gamma function ln(&#x393;(x)).</returns>
        /// <remarks>
        /// <para>Because &#x393;(x) grows rapidly for increasing positive x, it is often necessary to
        /// work with its logarithm in order to avoid overflow. This function returns accurate
        /// values of ln(&#x393;(x)) even for values of x which would cause &#x393;(x) to overflow.</para>
        /// </remarks>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="x"/> is negative.</exception>
        /// <seealso cref="Gamma(double)" />
        public static double LogGamma(double x)
        {
            if (x < 0.0)
            {
                throw new ArgumentOutOfRangeException(nameof(x));
            }
            else if (x < 0.5)
            {
                // For small arguments, use the Lanczos approximation.
                return(Lanczos.LogGamma(x));
            }
            else if (x < 1.5)
            {
                // Use the series expansion near 1.
                return(GammaSeries.LogGammaOnePlus(x - 1.0));
            }
            else if (x < 2.5)
            {
                // The series expansion can be adapted near 2, too.
                return(GammaSeries.LogGammaTwoPlus(x - 2.0));
            }
            else if (x < 16.0)
            {
                // In between, we still use Lanczos.
                return(Lanczos.LogGamma(x));
            }
            else if (x < Double.PositiveInfinity)
            {
                // For large arguments, the asymptotic series is even faster than the Lanczos approximation.
                return(Stirling.LogGamma(x));
            }
            else if (x == Double.PositiveInfinity)
            {
                // Precisely at infinity x * Math.Log(x) - x => NaN, so special-case it.
                return(Double.PositiveInfinity);
            }
            else
            {
                return(Double.NaN);
            }
        }