示例#1
0
        /// <summary>
        /// Implements the Exponential Series for integer n
        /// <para>Sum = ((-z)^(n-1)/(n-1)!) * (ψ(n)-Log(z)) - Σ( (k==n-1) ? 0 : ((-1)^k * z^k)/((k-n+1) * k!)) k={0,∞}</para>
        /// </summary>
        /// <param name="n"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        /// <see href="http://functions.wolfram.com/GammaBetaErf/ExpIntegralE/06/01/04/01/02/0005/"/>
        public static double En_Series(int n, double z)
        {
            Debug.Assert(n > 0);

            const double DefaultTolerance = 2 * DoubleLimits.MachineEpsilon;

            // the sign of the summation is negative
            // so negate these
            double sum  = (n > 1) ? -1.0 / (1.0 - n) : 0;
            double term = -1.0;

            int k = 1;

            for (; k < n - 1; k++)
            {
                term *= -z / k;
                if (term == 0)
                {
                    break;
                }
                sum += term / (k - n + 1);
            }

            sum += Math.Pow(-z, n - 1) * (Math2.Digamma(n) - Math.Log(z)) / Math2.Factorial(n - 1);

            if (term == 0)
            {
                return(sum);
            }

            // skip n-1 term
            term *= -z / k;

            for (int i = 0; i < Policies.MaxSeriesIterations; i++)
            {
                double prevSum = sum;

                k++;
                term *= -z / k;
                double delta = term / (k - n + 1);
                sum += delta;

                if (Math.Abs(delta) <= Math.Abs(prevSum) * DefaultTolerance)
                {
                    return(sum);
                }
            }


            Policies.ReportConvergenceError("Series did not converge in {0} iterations", Policies.MaxSeriesIterations);
            return(double.NaN);
        }
示例#2
0
        public static (double Result, int Iterations) RefineQ_SmallA_LargeZ(double z, double p, double q, double aGuess)
        {
            Debug.Assert(z >= 0, "Requires z >= 0");
            Debug.Assert(aGuess >= 0 && aGuess <= double.MaxValue, "Requires finite aGuess >= 0");
            Debug.Assert(q <= 0.5, "Requires q <= 0.5");
            Debug.Assert(aGuess < z + 1);

            // f = Log(z^a/Gamma(a))-Log(q);
            // f/f' = (Log(z^a/Gamma(a))-Log(q))/ (Log(z) - Polygamma(0, a))
            //
            // http://functions.wolfram.com/GammaBetaErf/GammaRegularized/06/02/02/0001/
            // For z->Infinity, Q(a,z) ~= z^(a-1)*e^-z/Gamma(a) * (1 - (1-a)/z ...)

            // Find a quick estimate of a
            // where Log[q] = Log[z^(a-1)*e^-z/Gamma(a)] to get into the ballpark

            double lz = Math.Log(z);
            double lq = Math.Log(q);

            int i = 0;

            for (; i < 1; i++)
            {
                const double eps = 1.0 / 2;

                double f = (aGuess - 1) * lz - z - Math2.Lgamma(aGuess) - lq;
                if (f == 0)
                {
                    break;
                }

                var    delta = f / (lz - Math2.Digamma(aGuess));
                double aLast = aGuess;
                aGuess -= delta;

                if (Math.Abs(delta) <= eps * Math.Abs(aLast))
                {
                    break;
                }
            }

            return(aGuess, i);
        }