Beispiel #1
0
        // Li_n(x) = \sum_{k=0}^{\infty} \zeta(n-k) \frac{\log^k x}{k!} + \frac{\log^{n-1} x}{(n-1)!} \left( H_{n-1} -\log(-\log x) \right)

        private static double PolyLog_LogSeries(int n, double x)
        {
            double lnx = Math.Log(x);

            double f = AdvancedMath.RiemannZeta(n);

            if (lnx == 0.0)
            {
                return(f);
            }

            // c stores [log(x)]^k / k!
            double c = 1.0;

            for (int k = 1; k < Global.SeriesMax; k++)
            {
                double f_old = f;
                c *= lnx / k;
                // argument of zeta
                int m = n - k;
                if (m < 0)
                {
                    // For negative arguments, use \zeta(-m) = \frac{B_{m+1}}{m+1} and that odd Bernoulli numbers vanish.
                    if (-m % 2 == 0)
                    {
                        continue;
                    }
                    // This could theoretically overrun our stored Bernoulli values, but if we haven't converged after 32 negative terms, we are in trouble.
                    //f += c * AdvancedIntegerMath.Bernoulli[(-m + 1) / 2] / (-m + 1);
                    f += c * AdvancedMath.RiemannZeta(m);
                }
                else if (m == 1)
                {
                    // Special term in place of \zeta(1).
                    f += c * (AdvancedIntegerMath.HarmonicNumber(n - 1) - Math.Log(-lnx));
                }
                else
                {
                    // Otherwise just compute \zeta(m).
                    // We could reduce even m to Bernoulli references but then we would be in trouble for n > 32.
                    f += c * AdvancedMath.RiemannZeta(m);
                }
                if (f == f_old)
                {
                    return(f);
                }
            }
            throw new NonconvergenceException();
        }
        /// <summary>
        /// Computes the given Bernoulli number.
        /// </summary>
        /// <param name="n">The index of the Bernoulli number to compute, which must be non-negative.</param>
        /// <returns>The Bernoulli number B<sub>n</sub>.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is negative.</exception>
        /// <remarks>
        /// <para>B<sub>n</sub> vanishes for all odd n except n=1. For n about 260 or larger, B<sub>n</sub> overflows a double.</para>
        /// </remarks>
        /// <seealso href="http://en.wikipedia.org/wiki/Bernoulli_number"/>
        /// <seealso href="http://mathworld.wolfram.com/BernoulliNumber.html"/>
        public static double BernoulliNumber(int n)
        {
            if (n < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(n));
            }

            // B_1 is the only odd Bernoulli number.
            if (n == 1)
            {
                return(-1.0 / 2.0);
            }

            // For all other odd arguments, return zero.
            if (n % 2 != 0)
            {
                return(0.0);
            }

            // If the argument is small enough, look up the answer in our stored array.
            int m = n / 2;

            if (m < Bernoulli.Length)
            {
                return(Bernoulli[m]);
            }

            // Otherwise, use the relationship with the Riemann zeta function to get the Bernoulli number.
            // Since this is only done for large n, it would probably be faster to just sum the zeta series explicitly here.
            double B = 2.0 * AdvancedMath.RiemannZeta(n) / AdvancedMath.PowOverGammaPlusOne(Global.TwoPI, n);

            if (m % 2 == 0)
            {
                B = -B;
            }
            return(B);
        }