Ejemplo n.º 1
0
        public static double LogValue(int n)
        {
            Assertion.NonNegative(nameof(n), n);

            if (n <= 20)
            {
                return(Math.Log(Value(n)));
            }

            return(GammaFunction.LogValue(n + 1));
        }
Ejemplo n.º 2
0
        public static double Value(int n)
        {
            Assertion.NonNegative(nameof(n), n);

            if (n <= 20)
            {
                long value = 1;
                for (long i = 1; i <= n; i++)
                {
                    value *= i;
                }
                return(value);
            }

            return(GammaFunction.Value(n + 1));
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Natural logarithm of Complete beta function B(a,b)
 /// </summary>
 public static double CompleteLogValue(double a, double b)
 {
     return(GammaFunction.LogValue(a) + GammaFunction.LogValue(b) - GammaFunction.LogValue(a + b));
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Complete beta function B(a,b)
 /// </summary>
 public static double CompleteValue(double a, double b)
 {
     return(GammaFunction.Value(a) * GammaFunction.Value(b) / GammaFunction.Value(a + b));
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Regularized incomplete beta function Ix(a, b)
        /// </summary>
        public static double RegularizedIncompleteValue(double a, double b, double x)
        {
            const double eps = 1e-5;

            if (a < -eps)
            {
                throw new ArgumentOutOfRangeException(nameof(a), "a should be positive");
            }
            if (b < -eps)
            {
                throw new ArgumentOutOfRangeException(nameof(b), "b should be positive");
            }

            if (x < eps)
            {
                return(0);
            }
            if (x > 1 - eps)
            {
                return(1);
            }

            if (a < eps && b < eps)
            {
                return(0.5);
            }
            if (a < eps)
            {
                return(1);
            }
            if (b < eps)
            {
                return(0);
            }

            if (a + b > 30) // For huge a+b, we use normal approximation
            {
                // We are trying to make the situation symmetric (|a-b|<1) to improve accuracy of the approximation
                double partialResult = 0;
                while (a < b - 1)
                {
                    partialResult += Math.Exp(GammaFunction.LogValue(a + b)
                                              - GammaFunction.LogValue(a + 1) - GammaFunction.LogValue(b)
                                              + a * Math.Log(x) + (b - 1) * Math.Log(1 - x));
                    a++;
                    b--;
                }
                while (b < a - 1)
                {
                    partialResult -= Math.Exp(GammaFunction.LogValue(a + b)
                                              - GammaFunction.LogValue(b + 1) - GammaFunction.LogValue(a)
                                              + (a - 1) * Math.Log(x) + b * Math.Log(1 - x));
                    a--;
                    b++;
                }

                var    betaDistribution    = new BetaDistribution(a, b);
                double normalApproximation = new NormalDistribution(betaDistribution.Mean, betaDistribution.StdDev).Cdf(x);
                return(partialResult + normalApproximation);
            }

            if (x > 0.5) // Accuracy is better for small x
            {
                return(1 - RegularizedIncompleteValue(b, a, 1 - x));
            }

            double result = Math.Exp(IncompleteLogValue(a, b, x) - CompleteLogValue(a, b));

            return(double.IsNaN(result) ? 0 : result.Clamp(0, 1));
        }