예제 #1
0
        /// <summary>
        /// Modified Bessel function of the first kind
        /// </summary>
        /// <param name="a">Order parameter.  Any real number except a negative integer.</param>
        /// <param name="x">Argument of the Bessel function.  Non-negative real number.</param>
        /// <remarks>
        /// Reference:
        /// "A short note on parameter approximation for von Mises-Fisher distributions, And a fast implementation of Is(x)"
        /// Suvrit Sra
        /// Computational Statistics, 2011
        /// http://people.kyb.tuebingen.mpg.de/suvrit/papers/vmfFinal.pdf
        /// </remarks>
        /// <returns>BesselI(a,x)</returns>
        public static double BesselI(double a, double x)
        {
            if (x < 0)
            {
                throw new ArgumentException("x (" + x + ") cannot be negative");
            }
            if (a < 0 && a == Math.Floor(a))
            {
                throw new ArgumentException("Order parameter a=" + a + " cannot be a negative integer");
            }
            // http://functions.wolfram.com/Bessel-TypeFunctions/BesselI/02/
            double xh   = 0.5 * x;
            double term = Math.Pow(xh, a) / MMath.Gamma(a + 1);
            double xh2  = xh * xh;
            double sum  = 0;

            for (int k = 0; k < 1000; k++)
            {
                double oldsum = sum;
                sum  += term;
                term *= xh2 / ((k + 1 + a) * (k + 1));
                if (AreEqual(oldsum, sum))
                {
                    break;
                }
            }
            return(sum);
        }
예제 #2
0
        /// <summary>
        /// Computes <c>1/Gamma(x+1) - 1</c> to high accuracy
        /// </summary>
        /// <param name="x">A real number &gt;= 0</param>
        /// <returns></returns>
        public static double ReciprocalFactorialMinus1(double x)
        {
            if (x > 0.3)
            {
                return(1 / MMath.Gamma(x + 1) - 1);
            }
            double sum  = 0;
            double term = x;

            for (int i = 0; i < reciprocalFactorialMinus1Coeffs.Length; i++)
            {
                sum  += reciprocalFactorialMinus1Coeffs[i] * term;
                term *= x;
            }
            return(sum);
        }
예제 #3
0
        /// <summary>
        /// Compute the regularized upper incomplete Gamma function by a series expansion
        /// </summary>
        /// <param name="a">The shape parameter, &gt; 0</param>
        /// <param name="x">The lower bound of the integral, &gt;= 0</param>
        /// <returns></returns>
        private static double GammaUpperSeries(double a, double x)
        {
            // this series should only be applied when x is small
            // the series is: 1 - x^a sum_{k=0}^inf (-x)^k /(k! Gamma(a+k+1))
            // = (1 - 1/Gamma(a+1)) + (1 - x^a)/Gamma(a+1) - x^a sum_{k=1}^inf (-x)^k/(k! Gamma(a+k+1))
            double xaMinus1 = MMath.ExpMinus1(a * Math.Log(x));
            double aReciprocalFactorial, aReciprocalFactorialMinus1;

            if (a > 0.3)
            {
                aReciprocalFactorial       = 1 / MMath.Gamma(a + 1);
                aReciprocalFactorialMinus1 = aReciprocalFactorial - 1;
            }
            else
            {
                aReciprocalFactorialMinus1 = ReciprocalFactorialMinus1(a);
                aReciprocalFactorial       = 1 + aReciprocalFactorialMinus1;
            }
            // offset = 1 - x^a/Gamma(a+1)
            double offset = -xaMinus1 * aReciprocalFactorial - aReciprocalFactorialMinus1;
            double scale  = 1 - offset;
            double term   = x / (a + 1) * a;
            double sum    = term;

            for (int i = 1; i < 1000; i++)
            {
                term *= -(a + i) * x / ((a + i + 1) * (i + 1));
                double sumOld = sum;
                sum += term;
                //Console.WriteLine("{0}: {1}", i, sum);
                if (AreEqual(sum, sumOld))
                {
                    return(scale * sum + offset);
                }
            }
            throw new Exception(string.Format("GammaUpperSeries not converging for a={0} x={1}", a, x));
        }