// The expansions in which they appear are asymptotic; the numbers grow rapidly after ~B_16

        /// <summary>
        /// Computes a Stirling number of the first kind.
        /// </summary>
        /// <param name="n">The upper argument, which must be non-negative.</param>
        /// <param name="k">The lower argument, which must lie between 0 and n.</param>
        /// <returns>The value of the unsigned Stirling number of the first kind.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is negative, or <paramref name="k"/>
        /// lies outside [0, n].</exception>
        /// <seealso href="https://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind"/>
        public static double StirlingNumber1(int n, int k)
        {
            if (n < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(n));
            }
            if ((k < 0) || (k > n))
            {
                throw new ArgumentOutOfRangeException(nameof(k));
            }

            if (k == n)
            {
                return(1.0);
            }
            else if (k == 0)
            {
                return(0.0);
            }
            else if (k == 1)
            {
                return(AdvancedIntegerMath.Factorial(n - 1));
            }
            else if (k == (n - 1))
            {
                return(AdvancedIntegerMath.BinomialCoefficient(n, 2));
            }
            else
            {
                double[] s = Stirling1_Recursive(n, k);
                return(s[k]);
            }
        }
Example #2
0
        private static double[] ReimannCoefficients(int n)
        {
            double[] e   = new double[n];
            double   sum = 0.0;

            for (int k = n; k > 0; k--)
            {
                sum     += (double)AdvancedIntegerMath.BinomialCoefficient(n, k);
                e[k - 1] = sum;
            }
            return(e);
        }
        /// <summary>
        /// Computes a Stirling number of the second kind.
        /// </summary>
        /// <param name="n">The upper argument, which must be non-negative.</param>
        /// <param name="k">The lower argument, which must lie between 0 and n.</param>
        /// <returns>The value of the Stirling number of the second kind.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is negative, or <paramref name="k"/>
        /// lies outside [0, n].</exception>
        /// <seealso href="https://en.wikipedia.org/wiki/Stirling_numbers_of_the_second_kind"/>
        public static double StirlingNumber2(int n, int k)
        {
            if (n < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(n));
            }
            if ((k < 0) || (k > n))
            {
                throw new ArgumentOutOfRangeException(nameof(k));
            }

            if ((k == 1) || (k == n))
            {
                return(1.0);
            }
            else if (k == 0)
            {
                return(0.0);
                // The exceptional value 1 for n = k = 0 will already have been returned by the previous case.
            }
            else if (k == 2)
            {
                return(Math.Round(MoreMath.Pow(2.0, n - 1) - 1.0));
            }
            else if (k == (n - 1))
            {
                return(AdvancedIntegerMath.BinomialCoefficient(n, 2));
            }
            else
            {
                double[] s = Stirling2_Recursive(n, k);
                return(s[k]);
            }

            // There is a formula for Stirling numbers
            //   { n \brace k } = \frac{1}{k!} \sum{j=0}^{k} (-1)^j { k \choose j} (k - j)^n
            // which would be faster than recursion, but it has large cancelations between
            // terms. We could try to use it when all values are less than 2^52, for which
            // double arithmetic is exact for integers. For k!, that means k < 18. For
            // largest term in sum for all k, that means n < 14.
        }