// 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); }